Blog
Guides 7 min read

Add video to your SaaS: a build-vs-buy decision guide

How to add video to a SaaS product: billing model, encoding, signed playback, and webhooks vs polling, compared across self-host, Stream, Mux, Bunny, rehelios.

rehelios

Engineering

At some point every SaaS product needs video: a demo on the marketing site, an onboarding walkthrough in the app, or a feature that lets customers upload their own clips. The search results for “how to add video to my SaaS” are thin — a Quora thread here, an agency listicle there — because the honest answer isn’t a single tool, it’s a decision with five variables that most guides skip entirely.

Adding video to a SaaS product comes down to five decisions: how the provider bills (per-minute vs per-GB), whether encoding is free or a line item, how you gate private playback per viewer, whether you get a webhook or have to poll for “is it ready yet,” and whether the provider gives you a real API/CLI/agent surface or just a dashboard. Get those five right for your usage shape and the rest — which specific vendor, which pricing tier — mostly falls out on its own.

1. Billing model: per-minute vs per-GB

This is the first fork, because it decides whether your bill tracks your catalog or your runtime. Some providers meter by the minute of video processed and stored; others meter by the gigabyte, the same way S3 or R2 does. Cloudflare Stream and Mux both bill per minute. Bunny Stream and rehelios both bill per gigabyte — $0.02 per GB-month stored, $0.005 per GB delivered on rehelios, with a $1/month minimum.

The distinction matters because SaaS video libraries rarely have a uniform shape. A product with lots of short demo clips behaves differently under each model than one with long onboarding recordings or a large, lightly-watched back catalog. Per-minute billing effectively caps your cost at runtime regardless of resolution; per-GB billing tracks actual bytes at rest and in transit. Neither is objectively better — match it to your content, not the other way around. We’ve laid out the full comparison across pricing models in a separate breakdown if you want the numbers side by side.

2. Free vs paid encoding

Ask specifically whether transcoding is a separate line item. Mux charges per-minute for encoding/ingest on top of storage and delivery, so a growing catalog compounds two costs at once. rehelios and Bunny don’t charge for encoding at all — transcoding a thousand videos costs the same $0 as transcoding one. That matters most for SaaS products where video volume grows with your customer count: every new user who uploads a clip shouldn’t add a new encoding fee on top of storage.

3. Private, per-viewer playback

Most SaaS video isn’t public. Onboarding recordings, customer-uploaded content, and paid course material all need to be gated so only the right viewer — not anyone with the URL — can watch. The two common mechanisms are a short-lived signed playback token issued per viewer, or a domain allowlist that restricts embedding to your own origin. rehelios supports both. Worth saying plainly: a signed token isn’t DRM. It stops casual link-sharing and hotlinking, not screen recording, and it won’t give you Widevine- or FairPlay-grade protection. If that distinction matters for your content, plan around it — we go deeper on how the mechanism actually works in how signed playback tokens work.

4. Webhooks vs polling for “is it ready?”

Transcoding isn’t instant, so your app needs to know when a video finishes processing. The lazy version of this is a polling loop that hits a status endpoint every few seconds until it flips to “ready” — it works, but it’s wasted requests and added latency in your own backend. The better version is an event: rehelios fires a video.ready webhook (and video.failed on error), both HMAC-signed, the moment transcoding completes. Your backend reacts to the event instead of babysitting a loop. If you’re evaluating a provider, ask specifically whether “ready” is a webhook or something you have to poll for — it’s a small detail that changes your entire ingestion architecture.

5. Developer surface: API, CLI, or agent tooling

The last factor is how you actually integrate: a REST API is table stakes, but the presence (or absence) of a CLI and agent tooling tells you a lot about who the provider is built for. rehelios ships a REST API, a typed SDK, a CLI (@rehelios/cli), and an MCP server that lets an AI agent upload, import, and publish video autonomously in a single tool call — no human approving each step. Mux ships an official MCP server too, but deliberately human-gates destructive operations, by their own stated reasoning that agents “reach for footguns.” Bunny and Cloudflare Stream don’t have official MCP servers as of this writing, only community repos in Bunny’s case. If any part of your SaaS pipeline is agent-driven — generating a video and publishing it without a human clicking through a dashboard — this factor alone can decide the shortlist.

The options, compared fairly

OptionBilling modelEncodingAgent/dev surface
Self-host (AWS)Compute + storage + egress, no bundled meter~$0.0075–0.015/min transcode (MediaConvert); egress typically dominates at scaleFull control, but you build the API, CLI, and any agent tooling yourself
Cloudflare StreamPer-minute: ~$5/1,000 min stored, ~$1/1,000 min deliveredBundled into the per-minute rateNo official MCP server
MuxPer-minute encoding (~$0.04/min baseline) plus per-minute storage/deliveryBilled separately, per minuteOfficial MCP server, but destructive actions are human-gated
Bunny StreamPer-GB storage + deliveryFreeNo official MCP; community repos only
reheliosPer-GB: $0.02/GB-month stored, $0.005/GB delivered, $1/mo minimumFreeREST API, typed SDK, CLI, and an MCP server built for full agent autonomy

Competitor figures above are per each vendor’s public pricing at the time of writing — verify current rates directly before budgeting off this table. rehelios’s own numbers are current.

Self-hosting gives you the most control and the least built-in tooling — every one of the five factors above becomes something you implement and maintain, and egress usually turns into the dominant cost once you’re serving real traffic. We’ve written a longer treatment of that tradeoff in the real cost of self-hosting video vs buying if that’s the path you’re weighing. For a side-by-side of every provider above against your specific use case, the comparison hub breaks out each one in more detail, and SaaS is one of the use cases we cover directly.

The concrete rehelios flow for a SaaS product

For a typical SaaS feature — a customer uploads a video, your app needs to store it and serve it back to the right viewer only — the flow looks like this: the user uploads, you get a video.ready webhook, you store the returned id against that user’s record, and when they come back to watch it you read playbackUrl and hand them a per-viewer signed token.

Kick off the upload from your backend (or during development, from the CLI):

npx @rehelios/cli upload ./demo-clip.mp4 --wait --json

In production, your webhook endpoint verifies the HMAC signature and reacts to video.ready:

import { createHmac, timingSafeEqual } from "node:crypto";

export async function handleReheliosWebhook(req: Request) {
  const signature = req.headers.get("x-rehelios-signature") ?? "";
  const body = await req.text();
  const expected = createHmac("sha256", process.env.REHELIOS_WEBHOOK_SECRET!)
    .update(body)
    .digest("hex");

  if (!timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return new Response("invalid signature", { status: 401 });
  }

  const event = JSON.parse(body);

  if (event.type === "video.ready") {
    await db.videos.update({
      where: { uploadId: event.data.id },
      data: { reheliosId: event.data.id, status: "ready" },
    });
  }

  return new Response("ok", { status: 200 });
}

When a viewer opens the video, your backend reads the metadata for the stored id:

const res = await fetch(`/v1/videos/${reheliosId}`, {
  headers: { Authorization: `Bearer ${process.env.REHELIOS_API_KEY}` },
});
const { playbackUrl } = (await res.json()).data;

Before handing playbackUrl to that specific viewer, mint a short-lived signed playback token scoped to them rather than serving the raw URL — that’s what keeps one customer’s upload from being watchable by anyone who guesses or shares the link. The mechanics of how that token is verified on the edge are covered in the signed playback tokens post linked above.

Making the call

None of the five factors above has a universally correct answer — they depend on your content shape, your traffic pattern, and whether any part of your pipeline is agent-driven. What they do give you is a checklist: before you pick a provider, know how it bills, whether encoding is free, how private playback works, whether “ready” is an event or a poll, and what your API surface actually looks like day to day. Run your own catalog through those five questions and the right answer for your SaaS usually becomes obvious well before you get to a pricing page. If you want to see where rehelios lands on your numbers specifically, the exact rates are on the pricing page.

Put your first video live today

Create an account, upload a file, and have a fast, embeddable video live in minutes. Pay only for what you store and stream.