Privacy-friendly video embeds
If a picture's worth a thousand words and a video comprises many pictures, then a video's worth, erm… quite many words, really. From interviews to product reviews, tutorials to testimonials, behind-the-scenes glimpses to documentaries; video is a rich and highly engaging medium that can diversify and spice up the content of your website.
This is the simple case. Vimeo has a different business model than YouTube, based on paid memberships rather than advertising revenue. They don't need to track visitors no matter what and make it possible to opt out of any data collecting.
We do this by appending the
dnt parameter to the embed URL. Short for Do Not Track, the
dnt parameter will have the same effect as the browser setting of the same name. Setting the parameter to
1 prevents the Vimeo player from tracking any session data or gathering analytics. If the embed URL was
https://player.vimeo.com/video/45010429, it now becomes
All that's left is to make the video responsive using the classic intrinsic ratio trick. We wrap the
iframe in another element:
And apply the following styles:
With very little effort and without further measures, we comply with privacy regulations. So let's enjoy a dance, shall we?
Embedding YouTube videos requires a bit more work, as YouTube doesn't provide a mechanism to opt out of data collecting completely. There's a "privacy-enhanced" mode that serves the video from a different domain,
https://www.youtube-nocookie.com, but contrary to what you might think, this still makes use of browser storage to identify the viewer.
localStorage allows YouTube to track users whether or not they watch the video. As far as privacy regulations go, these different browser storage mechanisms are equivalent. Consent is still needed.
Asking for consent
Privacy laws stipulate that consent must be freely given, informed and specific.
Consent is freely given when it results from a positive action, like the click of a button. We can't assume visitors agree to any data collecting just because they continue to surf on our website. We'll delay loading the video until consent is given.
Let's build on to the video component we had earlier. We add a disclaimer and disable the iframe by turning the
src into a
data-src attribute. Notice how we're using the
youtube-nocookie.com domain anyway, which might not be good, but is still better for privacy.
We'll hide the iframe and show the notice by default. The notice will disappear when the iframe becomes active.
To ensure the notice doesn't overflow its container, we'll introduce a variation on the intrinsic ratio trick we used earlier. A pseudo-element ensures the aspect ratio of our video component is at least 16x9, but the container will grow if the notice grows taller, which might happen on smaller screens. A background color on the container offsets the video element from its surroundings, and the notice gets centered vertically with flexbox.
Then we style our notice:
Nailing the thumbnail
It'd be nice to replace the background color on the container with the preview image for our video. The thumbnail hints to the video's content and entices visitors to watch it.
YouTube delivers these thumbnail images from the
https://i.ytimg.com domain in different resolutions. The highest resolution image that's guaranteed to exist is
https://i.ytimg.com/vi/<VIDEO ID>/hqdefault.jpg, which measures 480px wide and 360px tall. Higher resolution
maxresdefault.jpg images might be available for your video, depending on its quality. For the video in our example, that's not the case.
Now, how do we know which image is available? We could check manually if higher resolution images exist by visiting the different URL's, but that method doesn't scale well. An automated method would use YouTube's Data API to retrieve a list of all the thumbnails available for a video. This requires quite a bit of setup, which we won't cover here.
For Cloudinary users, there's a simpler method. We retrieve the highest resolution thumbnail for any YouTube video using a URL in the format
https://res.cloudinary.com/<CLOUD NAME>/image/youtube/<VIDEO ID>.jpg. That image can then be scaled and altered using the array of image transformations that Cloudinary offers. Cloudinary probably uses YouTube's Data API behind the scenes, but does the hard work for us.
If you're willing to accept slightly grainy thumbnails, the easiest is of course to settle on the rather low-quality
hqdefault image, even for higher resolution videos. That's the path we'll take.
No matter which option you prefer, add the image as a background on the video container:
And make sure it covers the whole component:
We keep the background color on the container anyway; it'll be visible while the image loads. The result looks similar to this, where the button doesn't do anything yet:
Activating the videos
Clicking the button on any of our videos should unblock all of them. We'll create an
activateVideos function that does just that. We loop over all the iframes with a
data-src attribute pointing to the
youtube-nocookie.com domain, and set their
Then we add event listeners to the notices:
CSS will take care of hiding the notice and showing the now active iframe instead.
Storing the user's preference
Right now, the user has to approve of YouTube videos again each time the page reloads. Similar to a cookie banner, visitors probably expect us to remember their preference. We'll use a cookie, yes, to do that.
To not reinvent the wheel on this one, we'll make use of the lightweight js-cookie library. We'll store a
youtube-consent cookie when the user consents to YouTube videos. On every page load, we then check if the cookie's present, and show either the video or the notice depending on that.
The full script:
Our component is now fully functional.
It's important to be mindful of your users' privacy when embedding content from a third party. If, like Vimeo, the provider offers privacy controls, default to them; your users can only benefit from it. If not, ask for consent first, and load the content afterwards. Inform your visitors and provide an option to revoke consent.