# Publish

Send a broadcast to the MoQ CDN from OBS, FFmpeg, a WHIP or SRT encoder, or a native MoQ client.

Every protocol lands as the same MoQ broadcast, so viewers, recordings, and usage do not care how it arrived. The dashboard's **Guides** page fills in the URLs below for your project and broadcast.

## Before you start

You need a project id and a publish token for the broadcast. The [quickstart](/quickstart) creates both, and [Tokens](/tokens) covers scoping one. Skip the token if [public access](/tokens#public-access) already lets anyone publish the path.

In the URLs below, replace `<project>` with the project id, `<broadcast>` with a name of your choice, and `<jwt>` with the token. Drop `?jwt=<jwt>` (or SRT's `,jwt=<jwt>`) for a public path. End the name in `.hang` so the dashboard can preview it and recordings line up.

| Protocol | Use it for | Video | Audio |
| --- | --- | --- | --- |
| [RTMPS](#rtmps) | OBS, FFmpeg, and most hardware encoders | H.264, H.265, VP9, AV1 | AAC, MP3, Opus |
| [SRT](#srt) | Contribution encoders on lossy links | H.264, H.265 | AAC, Opus |
| [WHIP](#whip) | Browsers and WebRTC publishers | H.264, VP8, VP9 | Opus |
| [MoQ](#moq) | The lowest latency, with no conversion | What the client sends | What the client sends |

## RTMPS

```text
rtmps://cdn.moq.pro:1935/<project>/<broadcast>.hang?jwt=<jwt>
```

RTMPS uses port 1935; port 443 is QUIC and fails the RTMP handshake. A broadcast name cannot contain `?`. Upstream's [RTMP page](https://doc.moq.dev/bin/rtmp) covers the bridge.

### OBS

In **Settings → Stream**, set **Service** to **Custom**, paste the URL as the **Server**, and leave **Stream Key** empty: the token rides in the URL. If an encoder insists on a stream key, drop `?jwt=<jwt>` from the Server and use the token as the stream key instead.

### FFmpeg

Set `RTMP_URL` to the URL above. This publishes a test pattern with a tone. Replace the two `lavfi` inputs with your source:

```sh
ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 -f lavfi -i sine=frequency=440 \
  -c:v libx264 -preset veryfast -tune zerolatency -g 60 -pix_fmt yuv420p \
  -c:a aac -f flv "$RTMP_URL"
```

Quote the URL: an unquoted `?` or `&` is shell syntax.

## SRT

```text
srt://cdn.moq.pro:877?streamid=#!::r=<project>/<broadcast>.hang,jwt=<jwt>
```

SRT has no path, so the broadcast and token ride in the `streamid`, as upstream's [SRT page](https://doc.moq.dev/bin/srt) describes. A broadcast name cannot contain `,`. The handshake sends the token in the clear, so avoid SRT on networks you do not trust.

To raise the receive buffer above its 200 ms floor, add `latency` before `streamid`. FFmpeg and OBS read it in microseconds (`latency=500000&streamid=...` for 500 ms); GStreamer reads milliseconds.

## WHIP

```text
https://cdn.moq.pro/whip/<project>/<broadcast>.hang?jwt=<jwt>
```

Paste it into any [WHIP](https://www.rfc-editor.org/rfc/rfc9725.html) publisher. WebRTC carries no AAC, so send Opus audio. Upstream's [WebRTC page](https://doc.moq.dev/bin/rtc) covers the bridge.

## MoQ

Native MoQ clients publish straight to the relay with no conversion. Connect to `https://cdn.moq.pro/<project>?jwt=<jwt>` and publish `<broadcast>.hang`:

- The [`moq` CLI](https://doc.moq.dev/bin/cli) pipes FFmpeg's output in, as the [quickstart](/quickstart#publish-with-the-upstream-cli) shows.
- The [OBS plugin](https://doc.moq.dev/bin/obs) adds a **MoQ** dock to OBS 32 or newer. Paste the URL without the token as **Relay URL**, the token as **Publish token**, and the name as **Broadcast name**, then **Go Live**.
- The [GStreamer plugin](https://doc.moq.dev/bin/gstreamer) publishes with `moqsink`.
- The [`<moq-publish>` element](https://doc.moq.dev/lib/js/publish) publishes a camera or screen from a browser.

[doc.moq.dev](https://doc.moq.dev) covers each client, the media formats, and the protocol.

## Check it

While the encoder runs, the project's **Broadcasts** page lists the broadcast with a live preview. To watch it elsewhere, see [Embed playback](/embed).
