Welcome to the first engineering blog post on The Thundering Herd!
We recently enabled tagged feeds on the Herd Works company blog. If you are using an RSS feed reader to follow our progress and you’re primarily interested in new product announcements, you can now follow the Announcements feed and ignore everything else. If you’re here for all the technical mumbo jumbo, then welcome! 🍿
Since announcing the new company in December, then preparing for and launching our first app, we at Herd Works have been looking for an embedded-video hosting solution for product demos and other promotional content on herd.works and themagichighlighter.com. After looking around at a few different options, we decided to give Cloudflare Stream a try. It was surprisingly easy to use, but not in the way Cloudflare recommends, so we wanted to document our experience in case it helps someone else.
But first, allow us to explain how we got here and why you might want to explore a similar path. And since it’s practically impossible to talk about internet streaming video without talking about YouTube, let’s start there.
Why not YouTube?
YouTube has historically been my personal go-to solution for literally-anything-to-do-with-video.
It’s practically ubiquitous, ever present as we navigate across the web.
And for good reason — it’s the gold standard for embedded video that Just Works™.
But all that value isn’t without a cost.
Those YouTube embeds enable AlphabetGoogle to track our every move.1
One of the themes we’re investing in at Herd Works is user privacy. For a company that is just over 100 days old, we’ve already starting to learn an important lesson: most of the free tools we’ve grown accustomed to over the years are extracting value in the form of user data instead of cash. Need analytics for your new website? No problem, just use Google Analytics! How about video? YouTube for the win!
There’s nothing inherently wrong with this approach. These services are incredibly valuable! In fact, we’d venture to say that the vast majority small/personal website projects might be untenable if they had to build or buy these services themselves! But when for-profit companies use these services, they’re effectively passing costs on to their customers to pay for with their personal data, with or without the customers’ explicit consent! That’s not an acceptable trade off for Herd Works, so we need alternative solutions.2
Embedded-video hosting criteria
With YouTube off the table, we jotted down a few simple criteria for embedded-video hosting:
- Backed by a CDN (required)
- No trackers (required)
- HTML5
<video>
player support (optional)
We admittedly didn’t look very far for providers that might fit this criteria.3 At Herd Works, we’ve been spending a lot of time exploring the Cloudflare platform as our primary cloud provider. We’re already using Cloudflare Pages, Cloudflare Pages Functions, and Cloudflare Workers for website hosting and serverless compute. And of course, these are all backed by the impressive Cloudflare CDN. Since CDN was our #1 criteria for embedded video hosting, looking at Cloudflare’s offering in this space was an obvious first step.
Cloudflare Stream
Cloudflare Stream is a “serverless live and on-demand video streaming” service, that is backed by “Cloudflare’s global network” (requirement #1). Plans start at $5/mo for 1000 minutes of storage and 1000 minutes of streaming (egress), with additional streaming minutes charged at $0.001 per minute, billed in increments of $1 per 1000 minutes. Video uploads and processing are free, so you’re only charged for storage and views. If you host a 1 minute video that gets viewed one million times, it’s going to cost you $1004 ($5 for the service and the first 1000 views/minutes, and $999 for the subsequent 999,000 views/minutes; see Billing for Cloudflare Stream for more information). This is actually quite reasonable in the context of a for-profit use case!
We’re happy to report that Cloudflare Stream does provide undocumented support for video playback via HTML <video>
elements
We are video newbies, so when we started skimming the Cloudflare Stream documentation we immediately ran into terminology that was new to us.
Our goal was to find an embedded-video hosting service that would work with the HTML5 <video>
player (requirement #3) and let us stream video from the CDN in one of the supported formats (e.g. H.264 video in an MP4 container).
So we were excited when we found the Use your own player documentation, as we assumed this would explain how to do just that.
Instead, the documentation described how to do what we suspect is a better solution, but different than what we were hoping for: using video players that support HLS (HTTP Live Streaming) and DASH (Dynamic Adaptive Streaming over HTTP; also called MPEG-DASH).4
As far as we can tell, this did not include the HTML5 video
player.5
This meant we’d need to use a third-party Javascript library — potentially including Cloudflare’s Stream Player — which meant we’d need to understand the privacy implications of that code (requirement #2).
For video newbies like us, this was a little intimidating, so the first time we looked at Cloudflare Stream, we stopped here and put all of our website video content on the back burner until post-launch.
How to stream MP4 video
After deciding to put video content on the back burner, we were able to finish launching The Magic Highlighter last month, followed by the first and second major updates to the app. With those releases behind us, we returned to video content in preparation for a concerted marketing effort.
For our second attempt with Cloudflare Stream we dug a little deeper into the documentation and discovered that it offers support for video downloads. This makes videos available to download in MP4 format via a simple HTTP URL, and it can be enabled on a per-video basis. Voila!
The thing that was initially unclear from the “Use your own player” documentation suddenly seemed viable.
And sure enough, we’re happy to report that Cloudflare Stream does provide undocumented support for playing video via HTML <video>
elements, thanks to video downloads.
Testing this is very simple – just uploaded a video via the web console, wait for it to be processed, then check the box to “enable MP4 downloads”.
The web console will provide a status indicator showing the progress of the MP4 download as it is being generated.
Once MP4 processing is completed, an additional “Download URL” becomes available – this URL can in turn be used as an HTML <video>
element source.
<video class="video" controls="" preload="metadata" poster="/thumbnail.png">
<source type="video/mp4" src="https://customer-xxxxxxxxxxxxxxxx.cloudflarestream.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/downloads/default.mp4">
<div id="video-controls" class="controls" data-state="hidden">
<button id="playpause" type="button" data-state="play">Play/Pause</button>
<button id="stop" type="button" data-state="stop">Stop</button>
<div class="progress">
<progress id="progress" value="0" min="0">
<span id="progress-bar"></span>
</progress>
</div>
<button id="mute" type="button" data-state="mute">Mute/Unmute</button>
<button id="volinc" type="button" data-state="volup">Vol+</button>
<button id="voldec" type="button" data-state="voldown">Vol-</button>
<button id="fs" type="button" data-state="go-fullscreen">Fullscreen</button>
</div>
</video>
Success!
Using the native HTML5 <video>
player means no third-party trackers to worry about (requirement #2).
To see the player in action, checkout The Magic Highlighter homepage, or just click below!
Embedded video backed by the Cloudflare Stream (global CDN), no tracking pixels (privacy++), and HTML5 <video>
player support (requirement #3).
Next Steps
Even though it’s clear that there are superior methods for delivering embedded video (e.g. HLS or DASH), we’re happy to be starting with a simpler implementation.
We were able to satisfy all of our initial business requirements, and everything just works™.
This project is one of our first times using the HTML5 <video>
element, and we’re already finding that using it offers a lot of flexibility in terms of the player UX, not to mention inheriting built-in platform features like picture-in-picture on iOS, iPadOS, and macOS.
From here we aim to collect user feedback about the video player experience, and we anticipate that we’ll eventually need to upgrade the player to something that supports HLS and/or DASH.
Starting with the HTML <video>
gives us a solution that works while we take a closer look at alternative players like the Stream Player, the open source Video.js project, and many others.
It’s great to know that our cloud provider already has all the tools we’ll need as we grow.
We’d love to hear your feedback on our process and end result. If you have any pointers or recommendations on our current implementation, or suggestions on what to consider as we evaluate players that support HLS and DASH, we’d be grateful for the input! Give us a mention on Mastodon, or just drop us a line via our contact page.
-
Yes, we are aware that YouTube offers a “Privacy-Enhanced Mode” for the embedded player. But Google’s own documentation on this feature effectively admits that it’s still tracking you:
The Privacy Enhanced Mode of the YouTube embedded player prevents the use of views of embedded YouTube content from influencing the viewer’s browsing experience on YouTube. This means that the view of a video shown in the Privacy Enhanced Mode of the embedded player will not be used to personalize the YouTube browsing experience, either within your Privacy Enhanced Mode embedded player or in the viewer’s subsequent YouTube viewing experience.
Google wouldn’t have to explicitly discard records about your viewing of an embedded YouTube video on some third-party website if they didn’t know you were watching it in the first place! For them do do that means that they know it’s you, they know what video(s) you’re watching, and the know what website(s) you’re watching the video(s) on! Also note that they are only promising to omit the embedded video viewing in the calculation of your personal recommendation algorithm; no promises are made about what else they might do with the data.
↩︎ -
Not to mention the growing prevalance of privacy-oriented browsers like Safari that are reporting and/or blocking third-party trackers, including Google Analytics.
For example, take a look at Safari’s Privacy Report or Brave Browser’s Shields results for something like https://notion.so versus https://herd.works and https://themagichighlighter.com. If you have browsed through enough pages on Notion’s website, you’ll see upwards of a dozen third-party trackers for google.com, google-analytics.com, googletagmanager.com, and/or doubleclick.net (Google Analytics and Ad services); youtube.com (embedded video trackers); twitter.com and t.co (embedded Tweet trackers); and many more.
On the Herd Works company website and The Magic Highlighter product website, you should see zero trackers contacted. How did we accomplish this? We built a custom analytics engine that we intend to open source after a few more months of battle testing in the wild. But that’s a story for another day… (coming soon)
↩︎ -
We would consider this to be a net positive, frankly. The fact that we didn’t have to look beyond our cloud provider for a solution suggests to us that there are likely competitive offerings from other providers — and that’s a good thing! ↩︎
-
Both HLS and DASH are standard formats for making streaming media available in multiple resolutions. They allow video players to apply adaptive bitrate logic by estimating the viewer’s available bandwidth and select the optimal resolution (quality) to play. Higher quality video means larger files to download. In cases where the viewer has an excellent internet connection, “optimal” means the highest possible quality. In cases where the viewer has a slower internet connection, “optimal” means a lower quality which will allow them to view the video much sooner (ideally immediately) than if they had to wait for the highest quality version of the content to download. ↩︎
-
See Livestreaming web audio and video for more information.
↩︎