Cloudflare Stream

How to use Cloudflare Stream to host videos for your website.

#cloudflare#webdev

Cloudflare Stream is a service that allows you to host videos for your website. It can be purchased as part of a $10/month plan that includes Cloudflare Images, with up to 1k minutes of video hosting and 5k minutes of video delivery included.

In my Workers GraphQL Server post, I included a video walkthrough of how to use the project. It’s hosted with Stream.

Integration

Here’s how I integrated it into my site:

  1. Upload the video to Stream
  2. Get the video ID
  3. Install the Cloudflare Stream React component:
Terminal window
$ npm install @cloudflare/stream-react
  1. Import the component into the blog post and use it (MDX supports JSX components):
blog/workers-graphql-server.mdx
8 collapsed lines
---
title: Workers GraphQL Server v2
description: Showing off some updates to my workers-graphql-server project.
pubDate: 'Nov 01 2024'
tags:
- cloudflare
- webdev
---
import StreamVideo from "@/components/StreamVideo";
12 collapsed lines
I've been working on updating the [`workers-graphql-server`](https://github.com/kristianfreeman/workers-graphql-server) project.
Five years ago, it was one of the first things I built after joining [Cloudflare](https://cloudflare.com). Since then, the way that we write Workers has changed a lot.
The [new v2 release](https://github.com/cloudflare/workers-graphql-server/releases/tag/2.0.0-alpha) is a complete rewrite. Some big changes:
1. Supports Wrangler v2 (better local dev, deployment, bindings, etc.)
2. Written as a module Worker (modern syntax for writing Workers)
3. Built on top of [Hono](https://honojs.dev/)
4. Examples for integrating external data sources, and service bindings
5. Updated implementation of the [Workers KV](https://developers.cloudflare.com/kv/) cache
I made a video showing how the new version works. Check it out!
<StreamVideo client:only="react" src="8e7113ab230ea2e352270dba1101b5f3" />

Note the usage of the client:only attribute. This is a feature of Astro that allows you to only hydrate the component on the client-side. This is important because the Stream component will try to create a new <video> tag on the client, so if it tries to render on the server, the video content won’t show up.

Captions

A recent feature that Stream added is the ability to add captions. The cool part is that it can use Workers AI to generate the captions automatically.

Stream Captions UI

Selecting this option will generate captions for the video in just a few minutes. Once the captions are generated, you can use them by providing a defaultTextTrack prop to the <Stream> component that matches the language of the captions:

import { Stream } from "@cloudflare/stream-react";
<Stream
client:only="react"
controls
defaultTextTrack="en"
src="$videoId"
/>

If you’re like me, you may be a little disappointed with the caption quality. Since Stream uses AI, it’s not perfect. Instead, generating your own caption locally, so you have the ability to easily tweak it, might be a good option.

To do this, I used MacWhisper to use a higher-quality Whisper AI model to generate a first pass of the captions. Then I opened the .vtt file in Vim and fixed some of the references to technical terms. The captions still aren’t perfect, but they’re decent and legible. After creating those captions, I re-uploaded them and replaced the generated captions inside of Stream.

My component

I created a component that I can use in my blog posts to make it easier to include a video. It allows me to style and space the video component to fit the design of my site. Here’s the code for components/StreamVideo.tsx:

components/StreamVideo.tsx
import { Stream } from "@cloudflare/stream-react";
export default function StreamVideo({ src }: { src: string }) {
return (
<div className="mt-4">
<Stream
controls
defaultTextTrack="en"
src={src}
/>
</div>
);
}