How to Debug and Trace MoQT Player Issues with WebTransport Inspector
By moqtap team
You’ve built a MoQT player (or integrated one) and something isn’t working. Playback stalls. Subscriptions fail silently. Objects arrive but the player doesn’t render them. The relay closes the connection with an opaque error code.
If you’ve worked with HTTP-based video (HLS, DASH), you know how to debug it — open the Network tab, inspect manifest requests, check segment responses. But MoQT is a binary protocol over QUIC streams. The browser’s Network tab doesn’t understand it. You’re flying blind.
This guide shows you how to use the WebTransport Inspector browser extension to diagnose the most common MoQT player issues — step by step, entirely within your browser’s DevTools.
Install the extension
WebTransport Inspector is a free browser extension that adds a MoQT-aware panel to your browser’s DevTools.
- Install for your browser:
- Chrome Web Store (also works in Edge, Brave, and other Chromium browsers)
- Firefox Add-ons
- Open DevTools (F12 or Cmd+Opt+I on macOS)
- Navigate to the WebTransport Inspector tab
That’s it. No proxy to configure, no server-side changes, no extra processes to run.
Verify the connection is established
The first thing to check when a MoQT player isn’t working is whether a WebTransport connection was established at all.
- Open or reload the page with the MoQT player
- In the WebTransport Inspector panel, look at the connection list in the sidebar
- Each connection shows its URL, status (open/closed), and the detected MoQT draft version
What to look for:
- No connections visible? The player may not be creating a WebTransport session. Check the browser console for connection errors.
- Connection shows “closed” immediately? Check the close reason — it might be a TLS certificate issue, a CORS problem, or the relay rejecting the client setup.
- Connection is open but no draft version detected? The extension auto-detects the MoQT draft from the CLIENT_SETUP message. If detection fails, the connection may not be using MoQT, or the handshake may be stalling.
If you opened DevTools after the page loaded, the extension may show a mid-session warning banner and still pick up active connections.
Inspect the MoQT handshake
Once you see an open connection, click on it and go to the Messages tab to see the control message log.
- Look for the
CLIENT_SETUPmessage (sent by the player) and theSERVER_SETUPmessage (sent by the relay) - Expand each message to see the negotiated parameters — supported versions, role, max subscribe ID, path
Common issues:
- No CLIENT_SETUP? The WebTransport session opened but the player never sent its setup message. This is a player bug.
- No SERVER_SETUP response? The relay may be rejecting the connection silently or timing out.
- Version mismatch? The setup messages will show which draft versions were proposed and accepted. If the relay doesn’t support the player’s draft version, the connection may close after setup.
Diagnose subscription failures
Most MoQT player issues boil down to subscriptions — the player subscribes to audio and video tracks, and if those subscriptions fail or stall, playback breaks.
Using the Tracks tab
Switch to the Tracks tab for a high-level view of all subscriptions:
- Each track shows its namespace, track name, status (pending, active, error, done), and direction (TX/RX)
- Use the “Active only” filter to hide completed or errored tracks and focus on what’s live
- Use “Group by NS” to organize tracks by namespace — most players subscribe to multiple tracks under a shared namespace (e.g., one for audio, one for each video quality)
What to look for:
- Tracks stuck in “pending”? The SUBSCRIBE was sent but no SUBSCRIBE_OK or SUBSCRIBE_ERROR came back. The relay may be slow, or the track may not exist.
- Tracks in “error”? Expand the track to see the error reason. Common:
Track does not exist,Unauthorized, or the relay’s max subscribe ID was exceeded. - Tracks in “done” unexpectedly? The relay sent SUBSCRIBE_DONE, which means it stopped sending objects. Check the reason — it might be
Track ended,Publisher left, or an internal error.
Timing matters: The timestamps on each track show you exactly how long the relay took to respond. A slow SUBSCRIBE_OK may mean the relay is waiting for the publisher to connect.
Using the Messages tab
For more detail, switch to the Messages tab and look at the subscription lifecycle:
- Find
SUBSCRIBEmessages sent by the player (marked with ↑) - Look for the matching
SUBSCRIBE_OKorSUBSCRIBE_ERRORresponse (marked with ↓) - If a subscription was accepted, look for subsequent
SUBSCRIBE_DONEorSUBSCRIBE_UPDATEmessages
Trace stalled playback
The player is subscribed and objects should be arriving, but playback stalls. This is the hardest class of problem to debug without a protocol-aware tool.
Check stream activity
Switch to the Streams tab:
- Look for data streams associated with the subscribed tracks
- Each stream shows its direction, byte count, and chunk count
- Use the footer stats bar to see total TX/RX bytes and stream counts
What to look for:
- No data streams for a subscribed track? The relay accepted the subscription but isn’t delivering data. The publisher may not be sending, or the relay may have an internal routing issue.
- Streams are present but byte counts are low or stopped growing? The publisher may have paused, or a QUIC flow control window may be stalling delivery.
- Many streams opening and closing rapidly? This can indicate a mismatch between the publisher’s group/object structure and what the player expects.
Check datagram delivery
Some MoQT implementations use WebTransport datagrams for low-latency delivery instead of streams. The extension intercepts these too:
- In the Streams tab, look for entries with negative IDs — these are datagram groups
- Each datagram group shows the track alias, group ID, and byte totals
- Click to inspect individual datagram payloads
If the player expects stream delivery but the relay is sending datagrams (or vice versa), playback will break silently.
Inspect media payloads
When objects are arriving but the player can’t render them, the problem is usually in the payload format.
How each track is read
The Tracks tab shows what each track is read as in its Media column: one badge, then the codec and size the catalog gives. A track whose MSF or CMSF catalogs agree on loc, cmaf, mediatimeline or eventtimeline is read that way. Any other track is read by what its bytes show: fMP4 or CMAF boxes, H.264 or H.265 frames, JSON, CBOR or MsgPack.
On a track whose catalog says loc, or whose objects carry Object Properties, the badge has a ▾: click it to pick the LOC draft (LOC ietf-04, LOC mzanaty-05, …).
Click on a data stream to open the stream data viewer. Its toolbar offers the views that fit the track:
- Catalog — on a catalog track: what the catalog says across all its streams, and the tracks it declares
- LOC — each object’s LOC properties (timestamps, frame marking, audio level, video config) and its payload’s NAL unit framing
- CMAF — each object’s boxes, track_IDs, first sample, SAP type and earliest presentation time, read against the CMAF header from the catalog
- Fragments — on a track with ISO BMFF boxes and no catalog: each object’s boxes, track_IDs, decode time and first sample
- NAL units — on a track with H.264 or H.265 frames and no catalog: each NAL unit’s type and size, keyframes marked
- Media timeline, Event timeline, SAP timeline — each object’s records
- JSON, CBOR or MsgPack — structured payloads as a tree
- Hex — the raw bytes, always
On tracks without catalog packaging, the streams list labels each stream by its first bytes: fMP4 or CMAF for ISO BMFF boxes (hover for box names like moof and mdat), H.264 or H.265 for Annex-B frames, and JSON, CBOR or MsgPack. CMAF there means a styp or ftyp names a CMAF brand; a moof + mdat fragment carries no brand and shows as fMP4.
Check the Problems list
The Details tab lists every problem in the session in one place, by severity: catalog objects that break their draft’s rules, catalogs that disagree on a track, CMAF objects that break CMSF, LOC tracks whose property types fit no LOC draft, timeline records that don’t read, and a SAP timeline that disagrees with its media. Where they apply, a problem cites the spec section that states the rule and links to the objects, catalog objects or control messages where it was seen.
Hex viewer deep inspection
For binary payloads, switch to the hex viewer:
- Object boundary banners appear inline between MoQT objects, showing content description and byte offset
- Use the object navigator (
‹ 1/5 ›) in the sticky bar to jump between objects - Byte-level annotations highlight MoQT framing headers, object boundaries, and payload regions in distinct colors
Common issues:
- CMAF track the player can’t initialise? CMSF carries the CMAF header in the catalog (
initData, or aninitDataListentry), not in an object. The CMAF view shows the header it read for the track; the Problems list reports a track without one, a header that doesn’t parse, and atrack_IDthat notrakof the header has. - Playback starts late or glitches after a join? CMSF requires each Group’s first Object to begin with SAP type 1 or 2. The CMAF view shows each object’s SAP type, and the Problems list flags a Group that starts with another.
- LOC track that fits no LOC draft? The publisher and the player may be on different LOC drafts. Pick a LOC draft from the track’s badge in the Tracks tab to see the properties under it.
- CBOR/MessagePack payload on a track the player treats as media? The player may be subscribing to a catalog track by mistake, or the namespace structure changed.
Export a trace for deeper analysis
If the issue is intermittent or you need to share it with your team:
- Click the export button in the WebTransport Inspector toolbar
- The session is saved as a
.moqtracefile — a complete recording of all control messages, stream data, object headers, and datagram payloads - Share the file with colleagues — they can import it into their own WebTransport Inspector or into the moqtap CLI for deeper analysis with QUIC transport stats
Traces are timestamped to microsecond precision and include the full decoded message content, making them ideal for bug reports and post-mortem analysis.
Use recording controls during long sessions
For long-running player sessions (live streams, 24/7 channels), you don’t want the extension to accumulate unlimited data:
- Use the recording toggle (red dot) in the Streams tab to pause data capture — control messages and track lifecycle still update, but stream payloads stop accumulating
- When you’re ready to investigate, resume recording
- Use the clear button to wipe accumulated stream data and free memory without losing the session state
Summary
Here’s a quick checklist for debugging MoQT player issues:
| Symptom | Where to look | What to check |
|---|---|---|
| No playback at all | Connection list | Is there an open WebTransport connection? |
| Connection drops immediately | Messages tab | CLIENT_SETUP/SERVER_SETUP exchange, close reason |
| Player connects but no media | Tracks tab | Are subscriptions stuck in pending or errored? |
| Subscriptions active but playback stalls | Streams tab | Are data streams present? Are bytes growing? |
| Objects arrive but don’t render | Tracks tab, stream data viewer, Details | Is the track read as the packaging the player expects? What does the Problems list report for it? |
| Intermittent issues | Trace export | Export a .moqtrace file and analyze offline |
Get started
Install the WebTransport Inspector for free:
For native QUIC debugging, QUIC transport stats, and active subscribe/fetch capabilities, see the moqtap CLI. Read the full extension documentation at WebTransport Inspector docs.