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.
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://(orrtsps://) 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://orrtsps://address of your camera/encoder. - Auth (optional) —
basicordigest, 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
viewablewhen you first configure → it defaults to on (viewable). - Omit it on a later update → your previous choice is kept.
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:
- State —
idle,running,failed, orstopped. - 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):
| Category | What it means | What to do |
|---|---|---|
source_unreachable | We couldn't reach your camera/encoder. | Check the URL, and that the device is online and reachable from the internet. |
auth_failed | The source rejected our credentials. | Check authType, username, and password. |
media_host_rejected | The source connected but the media host rejected the pull. | Often transient; retry. If it persists, contact support. |
broker_unreachable | A Native Frame internal component was temporarily unreachable. | Transient — auto-recovery will retry. |
internal | An 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
- You configure a source URL on a stream and start the pull (manually or on a schedule).
- 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.
- A health check watches the live pull. An unexpected drop flips it to
failedand the recovery loop retries it; a clean stop is left alone. - 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 thertsp://URL from outside your network. - It fails with
auth_failed. The source needs credentials, or they're wrong. SetauthType(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: falseon 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
| Method | Path | Description |
|---|---|---|
GET | /streams/{id}/rtsp-source | Get source config (404 if not configured) |
PUT | /streams/{id}/rtsp-source | Create or update source config (idempotent) |
DELETE | /streams/{id}/rtsp-source | Delete source (stops pull, removes schedules) |
POST | /streams/{id}/rtsp-source/start | Start pulling |
POST | /streams/{id}/rtsp-source/stop | Stop pulling |
GET | /streams/{id}/rtsp-source/status | Runtime status, health, error detail, schedules |
GET POST | /streams/{id}/rtsp-schedules | List / 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
}
| Field | Type | Required | Notes |
|---|---|---|---|
sourceUrl | string | Yes | Must be rtsp:// or rtsps:// |
authType | string | No | "basic" or "digest" |
authUsername | string | No | Required if authType is set |
authPassword | string | No | Required if authType is set. Write-only — never returned |
region | string | No | Preferred ingest region |
viewable | boolean | No | Default 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
errorobject is present only whensourceStatusisfailed; it's omitted otherwise.lastError(the raw string) is always retained alongside it. error.categoryis one ofmedia_host_rejected,broker_unreachable,auth_failed,source_unreachable,internal. Treat any unrecognized value asinternal— the set may grow.error.codeis 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
| Code | When |
|---|---|
200 | Configure / start / stop / status / get succeeded |
201 | Schedule created |
400 | Bad sourceUrl scheme, missing auth fields, invalid schedule times |
404 | No source configured on the stream |
409 | A schedule already active/pending (one at a time) |
New to streaming protocols? See Streaming Protocols for background on RTSP, RTMP, and how ingest works.