Skip to content

Cloudflare.Stream reference

Source: src/Cloudflare/Stream/LiveInput.ts

A Cloudflare Stream live input — an ingest endpoint (RTMPS/SRT/WebRTC) that accepts live video and optionally records it as a Stream video.

Live inputs are identified by an auto-assigned uid; every prop is mutable in place via Cloudflare’s PUT endpoint, so the resource is never replaced. Deleting a live input does not delete videos already recorded from it.

Requires the Stream subscription to be enabled on the account.

Basic live input

const input = yield* Cloudflare.Stream.LiveInput("Broadcast", {});

Live input with automatic recording

const input = yield* Cloudflare.Stream.LiveInput("Broadcast", {
meta: { name: "town-hall" },
recording: {
mode: "automatic",
timeoutSeconds: 10,
},
deleteRecordingAfterDays: 30,
});
const input = yield* Cloudflare.Stream.LiveInput("Broadcast", {
enabled: false,
});

Source: src/Cloudflare/Stream/LiveInputOutput.ts

A Cloudflare Stream live input output — restreams (simulcasts) live video received by a LiveInput to another RTMP(S) destination such as YouTube Live or Twitch.

The destination (url + streamKey) is immutable: Cloudflare’s update endpoint only toggles enabled, so changing the destination replaces the output. Toggling enabled updates the output in place.

Requires the Stream subscription to be enabled on the account.

const input = yield* Cloudflare.Stream.LiveInput("Broadcast", {});
const youtube = yield* Cloudflare.Stream.LiveInputOutput("YouTube", {
liveInputId: input.liveInputId,
url: "rtmps://a.rtmps.youtube.com/live2",
streamKey: youtubeStreamKey,
});
const youtube = yield* Cloudflare.Stream.LiveInputOutput("YouTube", {
liveInputId: input.liveInputId,
url: "rtmps://a.rtmps.youtube.com/live2",
streamKey: youtubeStreamKey,
enabled: false,
});

Source: src/Cloudflare/Stream/SigningKey.ts

A Cloudflare Stream signing key — an RSA key pair used to sign viewer playback tokens for videos that require signed URLs.

The key material (pem/jwk) is returned by Cloudflare only at creation time; it is persisted as redacted attributes in state and can never be re-read from the API. If the key is deleted out-of-band, reconcile creates a brand-new key with new material — anything derived from the old key (signed tokens) must be re-derived from the new attributes.

Requires the Stream subscription to be enabled on the account.

const key = yield* Cloudflare.Stream.SigningKey("PlaybackKey", {});
// key.pem / key.jwk are Redacted<string> — use them server-side to
// sign playback tokens for videos with requireSignedURLs enabled.
const pem = key.pem;

Source: src/Cloudflare/Stream/Stream.ts

A Cloudflare Stream binding for managing videos, captions, downloads and watermarks from Workers — a Worker-only binding with no backing cloud resource.

Stream is a single value that is at once the Binding.Service tag, the callable that produces a StreamBinding, and the type. Declare it on a Worker’s env (it flows through InferEnv → the runtime StreamBinding handle) or yield* it inside an Effect-native Worker to attach the binding and obtain the StreamClient.

In alchemy dev the binding is emulated locally: uploads land in a local video store and each video’s preview URL is served unmodified at {devUrl}/cdn-cgi/mf/stream/<id>/watch. The local store performs no transcoding (the hlsPlaybackUrl/dashPlaybackUrl point at a placeholder host), no signed URLs, and createDirectUpload is unsupported. Pipe the binding through Alchemy.remote() to proxy to the real Stream service instead.

import * as Effect from "effect/Effect";
Cloudflare.Worker(
"StreamWorker",
{ main: import.meta.url },
Effect.gen(function* () {
const stream = yield* Cloudflare.Stream.Stream("STREAM");
return {
fetch: Effect.gen(function* () {
const video = yield* stream.upload("https://example.com/video.mp4");
const details = yield* stream.video(video.id).details();
return yield* HttpServerResponse.json(details);
}),
};
}).pipe(Effect.provide(Cloudflare.Stream.StreamBinding)),
);
export const Worker = Cloudflare.Worker("Worker", {
main: "./src/worker.ts",
env: { STREAM: Cloudflare.Stream.Stream() },
});
export type WorkerEnv = Cloudflare.InferEnv<typeof Worker>;
// { STREAM: StreamBinding }
// Default: videos land in the local video store under `alchemy dev`.
// Alchemy.remote() opts the binding into the real Stream service
// instead — in an Effect-native Worker:
const stream = yield* Cloudflare.Stream.Stream("STREAM").pipe(Alchemy.remote());
// or declared on an async Worker's env:
env: { STREAM: Cloudflare.Stream.Stream("STREAM").pipe(Alchemy.remote()) }

Source: src/Cloudflare/Stream/Watermark.ts

A Cloudflare Stream watermark profile — a PNG image stamped onto videos at upload time.

Watermark profiles are create-only: Cloudflare exposes no update endpoint, so every prop change triggers a replacement (a new profile is created and the old one deleted). The image is downloaded by Cloudflare from the given URL at creation time.

Requires the Stream subscription to be enabled on the account.

Default watermark from an image URL

const watermark = yield* Cloudflare.Stream.Watermark("Logo", {
url: "https://example.com/logo.png",
});

Centered semi-transparent watermark

const watermark = yield* Cloudflare.Stream.Watermark("Logo", {
url: "https://example.com/logo.png",
position: "center",
opacity: 0.5,
scale: 0.3,
});

Source: src/Cloudflare/Stream/Webhook.ts

The Cloudflare Stream webhook — an account-level singleton that receives notifications when videos finish processing or live inputs connect/disconnect.

Each account has at most one Stream webhook, so creating this resource takes over the account’s webhook slot; an existing webhook configured outside Alchemy is only adopted when --adopt is set. Destroying the resource deletes the webhook configuration.

Requires the Stream subscription to be enabled on the account.

const webhook = yield* Cloudflare.Stream.Webhook("Notifications", {
notificationUrl: "https://example.com/hooks/stream",
});
// Verify the Webhook-Signature header with the HMAC secret:
const secret = webhook.secret; // Redacted<string>