Skip to main content

By the end of this tutorial you’ll have a Next.js 15 app with two pages: a broadcaster that captures camera and microphone in the browser and ingests via WHIP, and a viewer that plays the same stream via WHEP with HLS fallback. Glass-to-glass latency runs 0.5 to 3 seconds with WebRTC end-to-end; 8 to 20 seconds when the viewer falls back to HLS. This is the Persona 4 activation moment: the sub-three-second path that the RTMP-and-HLS Transcoding Quickstart can’t deliver. The @livepeer/react library handles both sides; the orchestration is one Next.js project, two route components, and one environment variable.

Required Tools

  • Node.js 20 or later
  • A WebRTC-capable Livepeer Gateway endpoint (paid provider, self-hosted, or any third-party WHIP/WHEP endpoint)
  • A code editor
@livepeer/react works against any WHIP/WHEP-compliant endpoint. Self-hosted Gateways need WebRTC ingest enabled; see . Paid Gateway providers expose WHIP and WHEP out of the box.

Latency Budget

The three-second target breaks down across four hops. Total typically lands between 500ms and 2 seconds in good conditions. The three-second target absorbs jitter buffers, ICE renegotiation, and the worst geographic case. B-frames are the gotcha. If the encoder emits B-frames, WebRTC frame ordering breaks and the player falls back to HLS. Force bframes=0 and keyint=1 on any encoder you control. Browser-native WebRTC encoders default to compliant settings; OBS, FFmpeg, and other external encoders need explicit configuration.

Project Bootstrap

1

Create the project

2

Install @livepeer/react

@livepeer/react provides the Broadcast (WHIP) and Player (WHEP) primitives. The livepeer package is the Node SDK used server-side to create streams against your Gateway provider.
3

Configure environment variables

Save as .env.local:
The ingest and playback bases point at your Gateway’s WHIP and WHEP endpoints. Most Gateway providers expose both at predictable paths; check the provider’s documentation for the exact URLs. For self-hosted Gateways, see .

Stream Creation Endpoint

Streams are created server-side so the API key stays out of the browser. The handler returns a streamKey and a playbackId; the browser uses them to broadcast and play back. Save as src/app/api/streams/route.ts:
The record: false flag keeps the stream live-only. To save to a VOD asset for replay, set record: true; the Gateway records the stream to an asset that survives after the broadcaster disconnects.

Broadcaster Page

Save as src/app/broadcast/page.tsx:
getIngest(streamKey, { baseUrl }) builds the full WHIP URL by combining your Gateway’s base URL with the stream key. The Broadcast.Root component negotiates SDP, manages ICE, and sends media tracks via WebRTC. STUN/TURN servers come from the Gateway response.

Viewer Page

Save as src/app/watch/[playbackId]/page.tsx:
The Player accepts an array of source candidates, ordered by preference. WebRTC first; HLS as the fallback when the browser can’t negotiate WebRTC or the stream has B-frames. autoPlay paired with volume={0} is the browser-compatible autoplay pattern; some browsers block autoplay with sound.

First Stream

Open two tabs. Tab 1: http://localhost:3000/broadcast. Click Create Stream. The browser requests camera permission. Click Start to begin broadcasting. Tab 2: http://localhost:3000/watch/<playback-id> using the playback ID from tab 1. The viewer connects via WebRTC and the live feed appears with sub-three-second latency. To verify glass-to-glass, point the camera at a stopwatch and view both tabs side-by-side. The viewer should show roughly the same time as the broadcaster.

Production Considerations

Five things change between this local setup and a production deployment. Authentication. Add user authentication to the /api/streams endpoint so anonymous visitors can’t create streams. Pair stream creation with JWT-based access control on playback. Stream lifecycle. Streams persist on your Gateway even after the broadcaster disconnects. Add a cleanup task or use the Gateway’s automatic-cleanup setting to release inactive streams. Recording. Set record: true when creating streams that should survive as VOD assets. The Gateway records to an asset accessible via the playbackId after the live stream ends. Geographic distribution. A single-region Gateway adds latency for distant viewers. For global low-latency, use a Gateway provider with multi-region ingest and playback. Player fallback ordering. The player ranks sources by preference. On some networks (corporate firewalls, VPNs) WebRTC fails to negotiate; HLS fallback takes over. Test both paths under expected viewer network conditions. Full hardening guidance in .

Common Errors

Two likely causes. First, B-frames are enabled on the encoder; the browser-native encoder is compliant by default, but external encoders need bframes=0. Second, STUN/TURN is blocked by the network. Test on a different network or VPN to isolate.
forceEnabled defaults to false, which means the browser previews before transmitting. Click the Start trigger to begin broadcasting. To stream immediately on permission grant, set forceEnabled={true} on Broadcast.Root.
SDP negotiation succeeded but media isn’t flowing. Check the browser console for ICE failures. On restrictive networks, TURN relays are necessary; confirm your Gateway provider includes TURN servers in the SDP answer.
Network distance to the Gateway. Check the Gateway’s geographic location relative to broadcaster and viewer. For multi-region, use a provider with edge ingest and playback.
The stream key is intentionally client-side because the broadcaster needs it to ingest. Treat it as a session-scoped credential; rotate it on session start, never reuse across users. Consider one-time stream keys for high-value content.
You have sub-3-second glass-to-glass streaming using WHIP ingest and WHEP playback. For standard HLS delivery (higher latency, broader compatibility), the same stream object serves both transports simultaneously.

AI agent prompt

Next Steps

VOD Upload and Playback

Persist streams as VOD assets and play them back later.

Transcoding Quickstart

The lower-latency-floor RTMP+HLS path for self-hosted setups.

Gateway Setup

Self-host a WebRTC-capable Gateway end-to-end.

Production Hardening

Auth, rate limits, geographic distribution, observability.
Last modified on May 31, 2026