A Web Component for embedding YouTube videos on your site in a GDPR-compliant way. By setting certain parameters, nothing is fetched from Google’s servers until the user clicks Play on the video.
- Demo
- Features
- Installation
- Global Parameters
- Using the Web Component
- Properties List
- Default Configuration
- GDPR Compliance
- Events
- CSS Custom Properties
- Dev Team
- License
- Pure Web Component with no external dependencies.
- Ability to customize video delivery using the available parameter list. Some parameters can be set globally so you don’t have to repeat them on every component.
- SEO / Rich Results optimized via a Schema.org (JSON-LD) snippet.
- Encapsulated code that doesn’t interfere with the host site.
- Option to load the video from the “https://www.youtube-nocookie.com” domain for increased privacy.
- Responsive 16:9 video layout.
- Ability to display a custom poster image for each video instead of the original YouTube thumbnail; falls back to an SVG image on error.
You can install the script in three ways. For details on global parameters, see Global Parameters.
- Compiled script in page
Simply include the minified file. You can add data-* attributes on the <script> tag for global parameters:
<script src="embed-youtube.min.js"></script>
- Source module in page
Use the uncompiled file with type="module". In this mode you can’t add data-* on the <script> tag, but you can place them on the <body> instead. You must also include the include/ folder alongside the module file (see /docs/assets/js/module):
<script type="module" src="module/embed-youtube.js"></script>
- Side-effect import
Import the component in any other JavaScript entry point. Global parameters apply to the entry-point script (<script> tag) or the <body> if using type="module:
// master.js
import './embed-youtube.js';
You can set the following global parameters via data-* on the <script> or <body> tag:
data-autoload: automatically instantiate the YouTube iframe for every video on the page. GDPR compliant: No.data-autoplay: only works ifdata-autoloadis set. Starts the video muted on page load. GDPR compliant: No.data-autopause: pauses the video when the player leaves the viewport (e.g. on scroll).data-mute: mutes the audio when the user manually plays the video.data-no-preconnect: by default,<link rel="preconnect">tags are inserted for YouTube resources. This disables them (useful if your site already includes them).data-no-schema: disables the JSON-LD Schema.org snippet (used for SEO and accessibility).data-no-cookie: enables the "no-cookie" domain provided by YouTube to prevent the sending of tracking cookies.data-play-hiddentab: by default, a started video is automatically paused if the user moves the website tab to the background. Set this parameter to prevent videos from being paused when the browser tab changes.
Example with global parameters on the script tag:
<!DOCTYPE html>
<html lang="it">
<head>
<script defer src="embed-youtube.min.js" data-autoload data-autoplay data-autopause data-play-hiddentab></script>
</head>
<body>
<embed-youtube video-id="kTwPG53ZAIg"></embed-youtube>
<!-- you can use also full url. e.g.: https://youtu.be/kTwPG53ZAIg?si=P1KzvrzLOKE2SDHB -->
</body>
</html>
Example with type="module" and globals on the <body>:
<!DOCTYPE html>
<html lang="it">
<head>
<script type="module" src="module/embed-youtube.js"></script>
</head>
<body data-autoload data-autoplay data-autopause data-no-preconnect data-no-schema>
<embed-youtube video-id="kTwPG53ZAIg"></embed-youtube>
</body>
</html>
Once the main script is loaded, you can use one or more instances on the page. The only required attribute is the video ID:
<embed-youtube video-id="kTwPG53ZAIg"></embed-youtube>
This will display the official video thumbnail but won’t create the YouTube iframe until the user interacts. Note that the thumbnail itself is still fetched from Google servers, so this mode is not fully GDPR-compliant.
To be fully GDPR-compliant (no Google servers contacted before user consent), use a custom poster:
<embed-youtube video-id="kTwPG53ZAIg" poster-url="path/to/custom-poster.jpg"></embed-youtube>
Or fall back to the built-in SVG placeholder:
<embed-youtube video-id="kTwPG53ZAIg" poster-fallback></embed-youtube>
Either way, once the user clicks “Play,” the video iframe is created normally.
For enhanced privacy, you can also use YouTube’s no-cookie domain:
<embed-youtube video-id="kTwPG53ZAIg" poster-url="path/to/custom-poster.jpg" no-cookie></embed-youtube>
This will load the iframe from https://www.youtube-nocookie.com.
If you need fully custom iframe parameters, use the param-list attribute:
<embed-youtube video-id="kTwPG53ZAIg" param-list="enablejsapi=1&autoplay=1&mute=0"></embed-youtube>
Note: Using
param-listoverrides built-in handling of attributes likeautoloadandautoplay.
| Properties | Description | Default |
|---|---|---|
| video-id | YouTube video ID to embed (or full url). Required. Shows an error if empty or missing. | "" |
| playlist-id | Playlist ID for the initial video. | not set |
| video-title | Video title (used for the button text and Schema.org snippet). | "Video YouTube" |
| description | Video description (used in the Schema.org snippet). | "Guarda questo video incorporato nel sito da YouTube" ("Watch this embedded video from YouTube") |
| play-text | Alternative text / `aria-label` for the Play button. | "Riproduci" ("Play") |
| video-start-at | Start time in seconds. | 0 |
| autoload | Automatically initializes the iframe when the component enters the viewport (IntersectionObserver). | not set |
| autoload-margin | Margin (px or %) to trigger the IntersectionObserver. Larger values load the iframe earlier as you approach the component. | 0 |
| autoplay | Starts the video on page load (muted). Only works if `autoload` is also set. | not set |
| autopause | Pauses the video if the user scrolls it out of view. | not set |
| mute | Mutes the audio when the user manually plays the video. | not set |
| no-cookie | Enables the "no-cookie" domain provided by YouTube to prevent the sending of tracking cookies. | not set |
| no-lazyload | Disables lazy-loading of poster images (original or custom). | not set |
| no-schema | Disables the JSON-LD Schema.org snippet. | not set |
| no-preconnect | Disables insertion of `preconnect` tags for YouTube domains on hover. | not set |
| poster-fallback | If set, shows the built-in SVG placeholder (even if `poster-url` is also set). | not set |
| poster-url | URL or path to a custom poster image. | not set |
| poster-quality | Default quality for YouTube thumbnails. Ignored if `poster-url` or `poster-fallback` is set. Falls back to SVG on error. | "hqdefault" |
| param-list | Overrides all built-in parameters passed to YouTube in favor of the provided list. | not set |
| short | Displays the video in vertical format if viewport width <= 640 px. | not set |
| spinnerColor | Color of the loading spinner. | "#ff0000" |
You can override defaults by defining a global embedYoutubeConfig object before loading the script:
<script>
window.embedYoutubeConfig = {
"activeIframeClass": "isactive",
"textVideoTitle": "Video YouTube",
"textVideoDescription": "Guarda questo video incorporato nel sito da YouTube",
"textMissingVideoId": "ID video errato o mancante",
"textBtn": "Riproduci",
"textVideo": "video",
"videoStartAt": 0,
"spinnerColor": "#ff0000",
"posterQuality": "hqdefault",
"playOnHiddenTab": false,
"noCookie": false,
"noSchema": false
};
</script>
To fully comply with GDPR (when the user has not yet consented), never use autoload and never load any YouTube resources before user interaction. For example, these two components are valid without consent:
<embed-youtube video-id="kTwPG53ZAIg" poster-url="path/to/custom-poster.jpg"></embed-youtube>
<embed-youtube video-id="kTwPG53ZAIg" poster-fallback></embed-youtube>
When an iframe is created (manually or via autoload), an embedYoutubeLoaded event is dispatched with these details:
videoIdplaylistIdvideoTitleposterUrl
You can listen globally:
<script>
document.addEventListener("embedYoutubeLoaded", (e) => {
console.log(e.target);
console.log("VideoId:", e.detail.videoId, "PlayListId:", e.detail.playlistId, "videoTitle:", e.detail.videoTitle, "posterUrl:", e.detail.posterUrl);
});
</script>
Components can be updated dynamically by changing one or more attributes from this list: video-id, playlist-id, video-title, play-text, poster-url, poster-fallback, short, mute. Example:
<script>
setTimeout(() => {
const videoEl = document.getElementById("myVideo1");
// cambia id del video
videoEl.setAttribute("video-id", "dQw4w9WgXcQ");
// imposta la modalità muta
videoEl.setAttribute("mute", "");
// rimuove eventuali copertine di youtube e imposta il poster SVG
videoEl.setAttribute("poster-fallback", "");
console.log("video aggiornato");
}, 1000);
</script>
You can style parts of the component via CSS shadow parts:
<style>
/* immagine poster del video */
embed-youtube::part(poster)
{
object-fit: contain;
}
/* bottone play */
embed-youtube::part(play-button)
{
margin-block: 1rem;
}
/* spinner color */
embed-youtube::part(spinner)
{
display: none;
}
</style>Lorenzo "Saibal" Forti
