skip to main content

YouTube Play Image Links in Hugo

published icon  |  category icon webdesign

When I asked Ruben how his lovely image-with-play-button thingies were scripted in his Hugo-powered site over at, Ruben was quick to respond. He unfolded the idea and implementation in a separate blog post—thanks, Ruben! In a nutshell, it’s a simple cobbled-together shell script that leans on both youtube-dl and convert to do the heavy lifting. The script takes an argument, and it’s not exactly clear how it is executed, but I wanted to somehow completely integrate it into my Hugo workflow, so it should be called automagically.

Back up a minute.

What exactly is the problem? Hugo—or any other CMS, for that matter—allows you to easily embed external (YouTube) videos by using a shortcode ({{ < youtube HLM9VzWv1GM > }}) or even copy-pasting an url ( The result is an embedded video your visitors can click on without having to surf to the third party itself. However. The (not so) big reveal: of course Google smacks your visitors around with the usual cookies coming from multiple suspicious looking domains. Even by resorting to, there’s still too much visitor activity siphoned off from your site towards Alphabeat’s data center. As an example, here’s a screenshot of my uBlock Origin window from my retro gamer E3 2021 blog post that used to embed YouTube videos:

uBlock Origin tracks outbound traffic.

Domains that should not be there, excluding the subdomains:

  • (it’s worse by default!)

Wow. Time for some coding action. I created another JS module in jam-my-stack, the Node utilities project I use on my Jamstack sites where I’ve written about before. I basically converted Ruben’s ideas into a JS file that automatically gets called via a Git commit hook. In sum, this does more or less the following:

  1. Collect YouTube embed IDs: scan a dir for .md files, and scan those for Hugo YouTube shortcode embeds. Pry out the single argument.
  2. For each id, if it was not done already, download the thumbnail, and merge it with a transparent .png that represents the play button using ImageMagick.

Inspect the thumbify.js source for more details. Since the JS script only downloads thumbnails into a designated folder, I let a custom Hugo shortcode overwrite the default behavior of embedding the video to showing the thumbnail instead:

    <a href="{{ index .Params 0 }}" class="lbox">
        <img loading="lazy" class="img-responsive" src="/img/yt/{{ index .Params 0 }}.jpg" alt="YouTube video {{ index .Params 0 }}">

The result: (I’ll actually use the shortcode here)

YouTube video HLM9VzWv1GM

Clicking on the image redirects to the video on Neat huh? Now what about our uBlock nastiness? Well, that’s also gone:

This not only makes my websites less dependable on external services and removes tracking, but also increases the speed since these resources are no longer dragged along. Granted, Google’s CDN will probably be much more optimized than my own tiny VPS, but it’s the thought that counts, right? I’ve also noticed that embedded YouTube videos are not handled well in various RSS readers.

The only downside I can come up with is perhaps a slight reduced usability of the site, as the actual playing video is one step further removed from viewers. I somewhat counter this by self-hosting small self-made videos, such as Sonic’s SEEGGAAA intro tune.

tags icon hugo website

I'm Wouter Groeneveld, a Brain Baker, and I love the smell of freshly baked thoughts (and bread) in the morning. I sometimes convince others to bake their brain (and bread) too.

If you found this article amusing and/or helpful, you can support me via PayPal or Ko-Fi. I also like to hear your feedback via Mastodon or e-mail. Thanks!