livqenoDocs

Live StreamingRestream (RTMP Out)

Restream to YouTube & Twitch

Push a live stream to up to five RTMP or RTMPS destinations at once, alongside your own app.

Restream sends your live stream to other platforms, like YouTube, Twitch, Facebook or LinkedIn, at the same time as your own app. Your viewers keep watching in your app over RTC (or HLS for broadcast-mode streams), and each platform gets its own copy over RTMP or RTMPS.

Where this fits: you already create streams and add hosts from your backend (Streams & lifecycle). A restream destination is one more thing your backend attaches to a stream. Your app and your hosts don't change at all.

How it works

  • Livqeno joins the stream's room as a hidden viewer and mixes every host's audio. With a single H.264 host (OBS ingest, or a browser host, which publishes H.264 for live streams), that host's own video is copied, not re-encoded. With several hosts, or a screen share, they're composited onto one 1280×720 frame and encoded once (H.264 with 2-second keyframes, plus AAC audio).
  • That one encode is copied to every destination. Adding or removing a destination never restarts the encoder, so HLS viewers see no glitch.
  • Each destination is isolated. If YouTube rejects your key, Twitch and HLS keep going.
  • It works for both delivery modes. An RTC_ONLY stream starts the encoder when its first destination is enabled and stops it when the last one is removed.

The layout is a fixed grid: one host fills the frame, two sit side by side, three or four share a 2×2 grid, and a screen share takes the main area with cameras in a strip. Custom layouts aren't available.

Add a destination

You need two things from the platform: the server URL and the stream key. Pass them separately. Don't paste the key onto the end of the URL.

const destination = await livqeno.liveStreams.restreams.create(stream.id, {
  url: 'rtmps://a.rtmp.youtube.com/live2',
  streamKey: process.env.YOUTUBE_STREAM_KEY!,
  label: 'YouTube',
});

If the stream is already LIVE, Livqeno starts pushing right away. Otherwise the destination waits in IDLE and starts when the stream does.

The response is the destination, without its key:

{
  "id": "rst_8sW1qL0pZ3mXc2",
  "label": "YouTube",
  "url": "rtmps://a.rtmp.youtube.com/live2",
  "keyLast4": "xxxx",
  "enabled": true,
  "status": "IDLE",
  "lastError": null,
  "attempts": 0,
  "connectedAt": null,
  "createdAt": "2026-10-02T12:00:00.000Z",
  "updatedAt": "2026-10-02T12:00:00.000Z"
}

Server URLs for common platforms

PlatformServer URLWhere the key is
YouTubertmps://a.rtmp.youtube.com/live2YouTube Studio → Go live → Stream → Stream key
Twitchrtmp://live.twitch.tv/app (Twitch also lists RTMPS and regional ingest servers in its help center)Creator Dashboard → Settings → Stream → Primary stream key
Facebookrtmps://live-api-s.facebook.com:443/rtmpLive Producer → Streaming software → Stream key

Plain rtmp:// works too, but use rtmps:// wherever the platform offers it, so the key isn't sent in clear text.

List, pause and remove

const destinations = await livqeno.liveStreams.restreams.list(stream.id);
 
// Pause one destination mid-stream, then resume it.
await livqeno.liveStreams.restreams.update(stream.id, destination.id, { enabled: false });
await livqeno.liveStreams.restreams.update(stream.id, destination.id, { enabled: true });
 
// Stop pushing and remove it.
await livqeno.liveStreams.restreams.delete(stream.id, destination.id);

PATCH changes only enabled and label. To change the URL or the key, delete the destination and add it again.

The four routes are:

RouteDoes
POST /v1/live-streams/{streamId}/restreamsAdd a destination (url, streamKey, optional label)
GET /v1/live-streams/{streamId}/restreamsList destinations with their status
PATCH /v1/live-streams/{streamId}/restreams/{restreamId}Pause or resume (enabled), or rename (label)
DELETE /v1/live-streams/{streamId}/restreams/{restreamId}Stop and remove

Statuses

statusMeans
IDLEConfigured, but the stream isn't live yet
CONNECTINGLivqeno is connecting to the platform
ACTIVEThe platform is receiving video
RETRYINGThe connection dropped or was refused. Livqeno retries after 1, 2, 4 … seconds, up to 30 seconds apart
FAILED10 attempts in a row failed. Livqeno stops trying. lastError says why
STOPPEDPaused with enabled: false, or the stream ended

attempts counts consecutive failures, and goes back to 0 once a connection has stayed up for 30 seconds. The most common cause of FAILED is a wrong or expired stream key. Fix it on the platform, then delete the destination and add it again with the new key.

Webhooks

EventSent whendata
live_stream.restream_activeA destination started receiving videostreamId, restreamId, label, at
live_stream.restream_failedA destination reached FAILEDstreamId, restreamId, label, reason, at

A failed destination never affects the stream itself, HLS, or the other destinations, so restream_failed is something to show your host ("YouTube disconnected: check your stream key"), not a reason to end the stream. See Stream events for how to subscribe.

Limits

  • Up to 5 destinations per stream.
  • rtmp:// and rtmps:// URLs only. URLs that point at private, loopback or link-local addresses are rejected.
  • Output is a fixed-grid composite at 1280×720, 30 fps.
  • Each platform applies its own rules, for example YouTube's warning when the keyframe interval is above 4 seconds. Livqeno always sends 2-second keyframes, so that one never fires.

Next steps