Skip to main content

RTSP Ingest

Native Frame can pull a live feed from an RTSP source — an IP camera, an encoder, or any rtsp:// endpoint — directly into a stream, with no push setup on your side. Point a stream at the source URL and Native Frame connects out to it, ingests the feed, and treats it like any other live stream (playback, recording, overlays, restream, etc.).

You can start and stop the pull on demand, schedule automated pull windows, watch the pull's health and errors in real time, and choose whether the raw camera feed is viewable to your audience or used only as an input to a composed program.

Pull vs. push

With RTSP pull, Native Frame reaches out to your camera. You don't run an encoder pushing into us — you just give us the source URL. The camera must be reachable from the public internet (port-forwarded / on a routable address) for us to connect.

What you'll need

  • A Native Frame stream (existing or new).
  • An RTSP source reachable from the internet: its rtsp:// (or rtsps://) URL, and credentials if it requires authentication.
  • For scheduled or auto-recovering pulls: nothing extra — it's built in.

Step 1 — Point a stream at your RTSP source

Configure the source on a stream. This is idempotent — the same call creates the source the first time and updates it after.

You provide:

  • Source URL (required) — the rtsp:// or rtsps:// address of your camera/encoder.
  • Auth (optional) — basic or digest, with a username and password, if your source needs it. The password is write-only — Native Frame stores it but never returns it.
  • Region (optional) — a preferred ingest region (for example us-east-1) to pull from.
  • Viewable (optional, default on) — see Show or hide the raw source.

Configuring a source does not start pulling — it just saves the connection details. Start it manually (Step 2) or on a schedule (Step 3).

Step 2 — Start and stop the pull

  • Start — Native Frame connects to the source and begins ingesting. The stream goes live as the feed arrives.
  • Stop — Native Frame disconnects from the source and the stream ends.

A manual stop is final for that run — Native Frame won't restart a source you explicitly stopped (see Auto-recovery for what does restart).

Step 3 — Schedule automated pull windows

Instead of starting by hand, give the pull a window: a name, a start time, and an end time (all UTC). Native Frame starts the pull at the start time and stops it at the end time automatically.

  • Times must be in the future, and the end must be after the start.
  • One window at a time. A stream can have a single active-or-pending schedule; trying to add a second overlapping one is rejected until the first finishes or is removed.
  • You can create a schedule disabled and enable it later.

Deleting a schedule that's currently running stops the pull.

Show or hide the raw source

When Native Frame pulls your camera, the raw feed shows up as a selectable source in the viewer manifest by default. Sometimes you don't want that — for example, the camera is only an input to a composed program (a multi-camera show, a scoreboard composition) and your audience should only see the finished product, not the raw camera.

Set viewable: false on the source and Native Frame hides the raw pull from the viewer manifest — it still feeds your composition/recording, it just isn't directly watchable. Leave it on (the default) and the camera is viewable as a normal source.

  • Omit viewable when you first configure → it defaults to on (viewable).
  • Omit it on a later update → your previous choice is kept.
What "viewable" exposes — and the audio caveat

The raw pull surfaces in the manifest as a WebRTC-derived source — viewers see a WebRTC source even though the true origin is RTSP. WebRTC playback needs Opus audio. If your project does not transcode the feed (it's only remuxed), the camera's AAC audio is never converted, so the WebRTC-derived source plays video only — no audio. If that's your setup, you almost certainly want the source hidden (viewable: false); projects with a transcode profile get full audio + video.

In the dashboard this is the "Include WebRTC-derived source" toggle on the RTSP source form. It defaults to off for new sources — the opposite of the API default (true when the field is omitted) — precisely because of the audio caveat above.

Watch the pull: status, health, and errors

The status view tells you, in real time:

  • Stateidle, running, failed, or stopped.
  • Health — whether the live pull is healthy or degraded.
  • Uptime — how long the current pull has been running.
  • Active / next schedule — the window running now and the one coming up.
  • Error detail — when a pull is failed, a clean, structured reason (not a raw log line):
CategoryWhat it meansWhat to do
source_unreachableWe couldn't reach your camera/encoder.Check the URL, and that the device is online and reachable from the internet.
auth_failedThe source rejected our credentials.Check authType, username, and password.
media_host_rejectedThe source connected but the media host rejected the pull.Often transient; retry. If it persists, contact support.
broker_unreachableA Native Frame internal component was temporarily unreachable.Transient — auto-recovery will retry.
internalAn unexpected error.Contact support with the timestamp.

Each error also carries a display-ready message and, when the failure came with one, an upstream status code. The full raw error is still available for support.

Auto-recovery: unplanned drops heal themselves

If a running pull drops unexpectedly — the camera blips, the network hiccups — Native Frame retries it automatically with a backoff, and resumes the moment the source is reachable again. This holds until you explicitly stop the pull (a clean stop stays stopped). Recovery is bounded by a give-up timeout, after which the source stays failed and waits for you.

In short: an unplanned outage recovers on its own; a deliberate stop stays stopped.

How it works behind the scenes

  1. You configure a source URL on a stream and start the pull (manually or on a schedule).
  2. Native Frame connects out to your RTSP source, ingests the feed, and publishes it into the platform as a live stream — at which point it behaves like any other Native Frame stream.
  3. A health check watches the live pull. An unexpected drop flips it to failed and the recovery loop retries it; a clean stop is left alone.
  4. If you marked the source non-viewable, Native Frame keeps it out of the viewer manifest while still feeding compositions/recordings.

Troubleshooting

  • The pull won't start / immediately fails with source_unreachable. The most common cause is reachability — the camera isn't exposed to the public internet, the URL/port is wrong, or a firewall blocks the connection. Verify you can reach the rtsp:// URL from outside your network.
  • It fails with auth_failed. The source needs credentials, or they're wrong. Set authType (basic/digest) and the matching username/password.
  • It dropped and came back on its own. That's auto-recovery doing its job after an unplanned outage — no action needed.
  • I stopped it but it didn't restart. Correct — a manual stop is final for that run. Start it again (or let a schedule start it).
  • My audience can see the raw camera and shouldn't. Set viewable: false on the source.
  • The source plays video but no audio. Your project isn't transcoding — the WebRTC-derived source can't carry the camera's AAC audio without an AAC→Opus transcode. Either enable a transcode profile for the project, or hide the raw source (viewable: false) and serve viewers a composed/transcoded output instead.

Program API reference

Everything above is backed by the Program Service HTTP API — see the Program API reference (the RTSP section under Program). Base path: /program/api/v2. Every call requires a Bearer JWT whose audience/role includes service-account; the project is taken from the token's projectID claim.

Endpoints

MethodPathDescription
GET/streams/{id}/rtsp-sourceGet source config (404 if not configured)
PUT/streams/{id}/rtsp-sourceCreate or update source config (idempotent)
DELETE/streams/{id}/rtsp-sourceDelete source (stops pull, removes schedules)
POST/streams/{id}/rtsp-source/startStart pulling
POST/streams/{id}/rtsp-source/stopStop pulling
GET/streams/{id}/rtsp-source/statusRuntime status, health, error detail, schedules
GET POST/streams/{id}/rtsp-schedulesList / create schedules
GET PUT DELETE/streams/{id}/rtsp-schedules/{scheduleId}Get / update / delete a schedule

Configure a source — PUT /streams/{id}/rtsp-source

{
"sourceUrl": "rtsp://192.168.1.100:554/stream1",
"authType": "basic",
"authUsername": "admin",
"authPassword": "secret",
"region": "us-east-1",
"viewable": true
}
FieldTypeRequiredNotes
sourceUrlstringYesMust be rtsp:// or rtsps://
authTypestringNo"basic" or "digest"
authUsernamestringNoRequired if authType is set
authPasswordstringNoRequired if authType is set. Write-only — never returned
regionstringNoPreferred ingest region
viewablebooleanNoDefault true. false hides the raw source from the manifest. Omit on update to keep the current value

The configure and status responses echo the current viewable value. authPassword is never returned.

Status — GET /streams/{id}/rtsp-source/status

{
"sourceStatus": "failed",
"isRunning": false,
"uptimeSeconds": 0,
"healthStatus": "unhealthy",
"lastError": "broker returned status 502",
"error": {
"category": "media_host_rejected",
"message": "The media host rejected the pull request.",
"code": 502
},
"activeSchedule": null,
"nextSchedule": { "id": "uuid", "name": "Afternoon Feed", "startsAt": "...", "endsAt": "..." }
}
  • The structured error object is present only when sourceStatus is failed; it's omitted otherwise. lastError (the raw string) is always retained alongside it.
  • error.category is one of media_host_rejected, broker_unreachable, auth_failed, source_unreachable, internal. Treat any unrecognized value as internal — the set may grow.
  • error.code is the upstream status code when the failure carried one; omitted otherwise.

Schedules — POST /streams/{id}/rtsp-schedules

{ "name": "Morning Feed", "startTime": "2026-04-23T08:00:00Z", "endTime": "2026-04-23T12:00:00Z", "enabled": true }

Times are UTC; startTime must be in the future and endTime after it. Returns 409 if the stream already has an active-or-pending schedule (one at a time).

Status codes

CodeWhen
200Configure / start / stop / status / get succeeded
201Schedule created
400Bad sourceUrl scheme, missing auth fields, invalid schedule times
404No source configured on the stream
409A schedule already active/pending (one at a time)
Related

New to streaming protocols? See Streaming Protocols for background on RTSP, RTMP, and how ingest works.