Real-Time and Media on Cloudflare: Stream, Images, RealtimeKit, TURN and SFU

Quick answer: Use Stream when you want to upload a video file and have it play, without building an encoding ladder. Use Images when you need automatic resizing and format optimisation. Use RealtimeKit when you need conferencing or a virtual classroom with UI components included, and drop down to the SFU and TURN only if your team genuinely knows WebRTC. The structural advantage underneath all of it is R2: zero egress fees, always. But if your contract requires DRM, or you need an advanced video workflow, Cloudflare is not the answer (pricing as of July 2026).

Media is the one category where bandwidth, not compute, eats your budget. A web app can serve a million requests for a few dollars. A video platform or an image-heavy marketplace pays for the bytes going out the door, and on most clouds that is the single largest line on the bill.

Cloudflare has five products in this space: Stream (on-demand and live video), Images, and the Realtime family made up of RealtimeKit, the SFU and TURN. They sit at different levels of abstraction, and picking the wrong level means either paying many times more than you need to, or writing many times more code than you need to.

Cloudflare Stream: billed per minute, not per byte

The thing that makes Stream different from every other video service you have priced: it does not care how large your file is. It bills on exactly two dimensions โ€” minutes of video stored and minutes of video delivered. Ingest and encoding are free. Bandwidth is already inside “video delivered” with no additional egress fee.

That means a 4K master and a low-bitrate 480p file of the same duration cost the same to store. This is simultaneously the best and the worst thing about Stream. Best, because you can forecast the bill without modelling bitrates. Worst, because you pay the same whether or not you are actually shipping high quality.

Service Billing unit Price (July 2026) Free tier
Stream โ€“ minutes stored Minutes of video (prepaid) $5 per 1,000 minutes โ€“
Stream โ€“ minutes delivered Minutes delivered $1 per 1,000 minutes โ€“
Media Transformations Unique transformation $0.50 per 1,000 5,000/month
Images โ€“ Transformed Unique transformation $0.50 per 1,000 5,000/month
Images โ€“ Stored Images stored $5 per 100,000 images/month Paid plan only
Images โ€“ Delivered Images delivered $1 per 100,000 images/month Paid plan only
RealtimeKit โ€“ audio/video participant Participant-minute $0.002 per minute None
RealtimeKit โ€“ audio-only participant Participant-minute $0.0005 per minute None
RealtimeKit โ€“ Export (recording, RTMP, HLS) Minute $0.010 per minute None
Realtime SFU Egress GB $0.05 per GB 1,000 GB/month
TURN Egress GB Free with Realtime SFU, otherwise $0.05/GB 1,000 GB/month
R2 โ€“ storage GB-month $0.015 per GB-month 10 GB-month
R2 โ€“ egress โ€“ $0, always โ€“

The Stream constraints you must know before signing anything

A single video upload can be at most 30 GB by default, and you can have at most 120 videos queued or encoding simultaneously. That 120 concurrency limit is raisable via support, but for a platform where creators all upload at once, it is worth checking before you launch, not after.

HDR video uploaded to Stream is re-encoded and delivered in SDR, to maximise device compatibility. If your business is selling HDR content, that is a dealbreaker.

Access control is via signed URLs and tokens. A token cannot have an expiry more than 24 hours in the future from when it is signed. You get at most 5 entries in the accessRules array, which can allow or block by country or by IP range, and you can hold up to 1,000 signing keys and rotate them. There is also Allowed Origins, which restricts which domains can embed or fetch the manifests.

But Cloudflare’s documentation does not describe DRM support โ€” Widevine, FairPlay or PlayReady โ€” for Stream. The documented access-control mechanisms are signed URLs, geo/IP rules and allowed origins. If a content licence you have signed requires DRM, Stream cannot satisfy it. Full stop.

Use Stream when / do not use Stream when

Use it when: you want to upload a file and have it play, without owning the transcoding, the ABR ladder, the manifests or the player. This is the right call for a course platform, an in-app content library, or any site where users upload their own video.

Do not use it when: you need DRM; you need to deliver HDR; you need to control the encoding ladder or the codec (for example, you want to ship AV1, or do per-title encoding); or you need complex workflows such as server-side ad insertion, clipping, or multiple language audio tracks in a single file.

Cloudflare Images: billed per unique transformation

Images has two modes that people routinely conflate. In the first, you store the originals somewhere else (usually R2) and use Cloudflare only to transform them; you are billed for Images Transformed and nothing else. In the second, you store the images inside Images itself, and you are billed for Images Stored and Images Delivered.

The word “unique” is load-bearing. Transforming thumbnail.jpg at 100×100 counts as one unique transformation; serving that same transformation a million times in the same month costs nothing extra. Transforming it at 200×200 is a separate unique transformation. Helpfully, format=auto counts as only one billable transformation even if some users get AVIF and others get WebP.

The trap most teams fall into: if you call Images through the Workers binding, every call counts as a transformation, whether or not the image and parameters are unique. Use the binding on a hot path without caching the result and your bill will climb fast.

Use Images when / do not use Images when

Use it when: you have product photography or user uploads that must be served at many sizes and many formats, and you do not want to run ImageMagick. Pairing it with R2 is the strong play: keep the originals in R2, transform through Images, pay only for transformations, and pay nothing twice for storage.

Do not use it when: you need real image editing โ€” layers, masks, Photoshop-grade filters โ€” or when you have a combinatorial explosion of transformation permutations with a low cache-hit rate, because unique transformations are exactly what you are billed for.

RealtimeKit, SFU and TURN: three layers of real-time

These three are not competitors. They stack. RealtimeKit sits on top of the SFU, and TURN is the bottom layer that makes the connection succeed at all when a user is behind a hostile NAT or firewall.

RealtimeKit: when you do not want to learn WebRTC

RealtimeKit gives you SDKs and pre-built UI components, plus high-level primitives: Meetings, Sessions, Participants, Presets (roles), Stage and Waiting Room. It also ships recording, chat, polls, breakout rooms, virtual backgrounds and transcription.

Billing is per participant-minute: $0.002 per minute for a participant with audio and video, $0.0005 per minute for audio-only. Exporting โ€” recording, RTMP or HLS streaming โ€” costs $0.010 per minute, or $0.003 per minute for audio-only. Real-time transcription is charged at standard Workers AI model pricing. There is no free tier for RealtimeKit.

The SFU: when you want full control

The Realtime SFU is a low-level media server that routes tracks between peers. It is deliberately unopinionated โ€” Cloudflare says explicitly that there is no rooms concept. You get Sessions (PeerConnections) and Tracks in a pub/sub model, and you build presence, roster and signalling yourself.

The limits worth memorising: 50 API calls per second per session; up to 64 tracks added per API call; tracks are garbage-collected after 30 seconds of inactivity (no media packets received); and any operation on a session requires the PeerConnection to be in the connected state, blocking up to 5 seconds while it waits.

Supported codecs are H264, H265, VP8, VP9 and AV1 for video, and Opus plus G.711 PCM (A-law and ยต-law) for audio.

TURN: the layer people forget

TURN relays traffic when the client cannot connect directly. It is free when used together with the Realtime SFU; used on its own it costs $0.05 per real-time GB egressed from Cloudflare to the TURN client, with a free tier of 1,000 GB per month.

turn.cloudflare.com is anycast, so clients automatically reach the nearest Cloudflare location. It supports TURN over UDP (3478), TCP (3478 or 80) and TLS (5349 or 443). That last one matters enormously for users inside corporate networks that block everything except 443.

A caveat that matters specifically for Thai teams: Cloudflare Realtime TURN runs on the global network with the notable exception of Cloudflare’s China Network. If a meaningful share of your users are in mainland China, plan for that explicitly.

TURN also enforces per-allocation limits: more than 5 new IPs per second, packet rates above roughly 5โ€“10 kpps, and data rates above roughly 50โ€“100 Mbps will result in dropped packets. These limits apply per allocation, not per account.

Which layer, when

Use RealtimeKit when: you are building conferencing, a virtual classroom, a webinar or social video chat, and nobody on the team specialises in WebRTC. Do not use it when: your media topology does not fit the standard meeting shape.

Use the SFU when: your team already has WebRTC expertise and needs an architecture that does not map onto rooms and participants. Do not use it when: the team has never shipped WebRTC, because you will be building presence, signalling, roster and recording from scratch.

Worked example: a Thai e-learning platform delivering 20 TB of video a month

Take a Thai online course platform with 500 hours of course video (30,000 minutes) delivering 600,000 minutes a month to students. Using Cloudflare’s own recommended 720p bitrate of 4.8 Mbps, that is roughly 21.6 TB โ€” call it 20 TB a month.

Option Calculation Monthly cost
A: Cloudflare Stream
Minutes stored 30,000 minutes x $5/1,000 $150
Minutes delivered 600,000 minutes x $1/1,000 $600
Encoding + ingest + egress All free $0
Stream total $750
B: R2 + your own encoder and player
R2 storage Ladder of 1080p+720p+480p (8+4.8+2.4 Mbps) across 30,000 min = ~3,420 GB x $0.015 ~$51
R2 egress 21.6 TB $0
Class B operations 4-second segments at ~2.4 MB = ~9,000,000 GETs (under the 10M free tier) $0
R2 total ~$51

The gap is roughly 15x. But do not read that as “R2 is cheaper, obviously use R2.” The $750 you pay Stream is buying the encoder, the ABR ladder, the manifest generation, a production-ready player and analytics. Choose R2 and you are committing engineering headcount to building and operating a media pipeline. For many teams that trade is a bad one.

We are deliberately not quoting S3 and CloudFront numbers here, because every price in this article comes from a Cloudflare page we actually read. Check the AWS calculator for their side. The structural point stands on its own: CloudFront charges per GB egressed and R2 charges $0 per GB egressed. At 20 TB a month, that line is the whole argument. We compared the two object stores directly in Cloudflare R2 vs S3.

Worked example: a 31-person virtual classroom

One teacher, 30 students, 60-minute sessions, 20 sessions a month, each one recorded.

RealtimeKit: participant-minutes = 31 x 60 x 20 = 37,200 minutes x $0.002 = $74.40. Recording export = 60 x 20 = 1,200 minutes x $0.010 = $12.00. Total $86.40 per month, plus the $5 Workers Paid subscription.

Raw SFU: billed on egress GB. Assume only the teacher sends video, at 1 Mbps (that is our own modelling assumption, not a Cloudflare figure). Thirty students x 60 minutes x 60 seconds x 1 Mbit = 13.5 GB per class. Twenty classes = 270 GB, which sits inside the 1,000 GB free tier, so $0 in egress.

So RealtimeKit costs about $86 a month to buy the SDK, the UI kit, recording, chat, polls and breakout rooms. The raw SFU at this scale is effectively free โ€” but you write all the WebRTC yourself. That is a straight trade of money against your team’s time. If you already have engineers who know WebRTC, the SFU is far better value. If you do not, RealtimeKit is much cheaper than the alternative.

Decision matrix: if you need X, use Y

If you need Use Why
Upload a video and have it play, with no pipeline work Stream Encoding, ABR ladder and player included; billed per minute
Store video yourself, control everything, pay the least R2 + your own encoder $0 egress, but you build the entire pipeline
DRM (Widevine / FairPlay) Mux, AWS Elemental (not Cloudflare) Cloudflare’s docs do not describe DRM support for Stream
Automatic image resizing and format optimisation Images (+ R2) Billed per unique transformation; no egress charge
Conferencing or classrooms with a team that does not know WebRTC RealtimeKit SDK, UI, recording and breakout rooms included
An unusual media topology that is not a meeting Realtime SFU Track-level pub/sub with full control; you build presence
Users behind restrictive corporate firewalls TURN over TLS on port 443 Free alongside the SFU; 1,000 GB/month free tier
Per-room state such as roster or chat presence Durable Objects One instance per key; WebSocket hibernation cuts idle cost
Server-side ad insertion, clipping, multi-language audio Mux or AWS Elemental Stream has no workflow for any of these

When Mux, AWS Elemental or a dedicated media pipeline wins

This is the section a vendor would skip. It is also the section that actually decides things.

DRM is the clearest dealbreaker

If you licence content from a studio or a rights holder, the contract very likely requires Widevine or FairPlay. Cloudflare’s documentation does not describe DRM support for Stream. The mechanisms it does have โ€” signed URLs, geo and IP rules โ€” will keep casual users out, but they are not a DRM system. In that situation Mux or AWS Elemental is the answer, not Cloudflare, and no amount of architecture cleverness changes it.

Advanced video workflows

Server-side ad insertion, cutting clips from a live stream into VOD, multiple language audio tracks in one file, per-title encoding, choosing your own codec โ€” these are the home turf of Mux, AWS Elemental and Bitmovin. Stream is deliberately simple. Simplicity is its strength, and also its limit.

You already have a WebRTC stack

If you already run LiveKit, Janus or mediasoup and the team is comfortable with it, moving to the Cloudflare SFU buys you anycast routing and no servers to manage โ€” but costs you features you have already built. Do the migration maths before you decide.

For per-room state such as a roster or chat presence, Durable Objects is the right fit, because one instance per key is the authoritative owner of that state, and WebSocket hibernation dramatically cuts the cost of idle connections. We compared it directly in Durable Objects vs Redis, and the wider storage picture is in Cloudflare storage services explained.

Summary for the person who has to decide

First question: does your content licence require DRM? If yes, stop โ€” Stream is out. If no, second question: do you want to own the encoding ladder? If yes, use R2 and build the pipeline. If no, use Stream and get on with the rest of your product.

Cipher designs and implements systems on the Cloudflare Developer Platform for businesses in Thailand. If you are weighing Stream against R2 with your own encoder, or against another media platform entirely, we can assess the architecture and work out the real numbers against your actual volume.

Frequently Asked Questions

Does Cloudflare Stream support DRM

Cloudflare’s documentation does not describe DRM support such as Widevine, FairPlay or PlayReady for Stream. The access control it does offer is signed URLs and tokens, which can carry up to 5 geo or IP access rules, plus Allowed Origins. If your content licence requires DRM you will need another tool such as Mux or AWS Elemental.

How does Cloudflare Stream bill

On exactly two dimensions: $5 per 1,000 minutes of video stored (prepaid) and $1 per 1,000 minutes of video delivered. File size does not affect the price. Ingest and encoding are free, and there is no separate egress charge (pricing as of July 2026).

What is the difference between RealtimeKit and the Realtime SFU

RealtimeKit sits on top of the SFU and gives you SDKs and UI components, billed per participant-minute at $0.002 for audio and video. The SFU is a low-level media server billed at $0.05 per GB of egress with a 1,000 GB per month free tier, and you must build presence and signalling yourself.

What does Cloudflare TURN cost

TURN is free when used together with the Realtime SFU. Used on its own it costs $0.05 per GB egressed from Cloudflare to the TURN client, with a free tier of 1,000 GB per month. One caveat that matters for Thai teams: Cloudflare Realtime TURN runs on the global network with the notable exception of Cloudflare’s China Network.

Is storing video in R2 actually cheaper than Stream

Much cheaper on paper, because R2 storage is $0.015 per GB-month and egress is always $0. But you have to build the transcoding, the ABR ladder, the manifests and the player yourself. What you pay Stream for is a media pipeline you never have to build or operate.

Scroll to Top