huddlesDevelopers Blog Open Huddles
Technical

Troubleshooting

Most of what goes wrong with an embed goes wrong on the host page, before Huddles is asked anything — and from inside the frame it all looks the same: a button that does nothing. Start with the one-line diagnosis, then the list in the order it is written.

Start here: Huddles.diagnose()#

Open the browser console on your page and run it. It checks the common causes in order and prints a table — paste that table into any bug report.

js — in the console of your page
await Huddles.diagnose()
// { ok: false, checks: { secureContext: {…}, nested: {…}, policy.microphone: {…}, origin: {…}, frame: {…}, lastNotice: {…} } }

Each failing row says what to change. The rows, and what they mean, are the sections below.

The microphone or camera does not work#

The embed asks for media from inside an iframe on your page, and the browser lets it only if your page could have asked. Four things break that chain, and none of them is visible from inside the frame — which is why the card now flashes the browser's refusal across its top, and why this list exists.

  1. Your page is not https

    Microphone and camera exist only in a secure context, and an iframe is secure only if every frame above it is. An http:// host page, or a staging site on plain http, means getUserMedia is simply absent inside the embed. localhost is allowed; everything else needs https. diagnose: secureContext.

  2. A Permissions-Policy header denies media

    Many frameworks and hosts ship a header like Permissions-Policy: microphone=(), camera=() by default. That forbids the feature on your page and on every frame in it, no matter what the frame's allow says. Either drop those entries, or allow our origin explicitly:

    http — your page's response header
    Permissions-Policy: microphone=(self "https://huddles.space"), camera=(self "https://huddles.space"), autoplay=(self "https://huddles.space")

    diagnose: policy.microphone, policy.camera.

  3. Your app is itself inside an iframe

    A messenger rendered inside another page's iframe — a portal, a preview, an app shell — needs that outer frame to carry allow="microphone; camera; autoplay", or nothing below it can ask. The embed's own frame already has it; the one above it is yours. diagnose: nested.

  4. The person said no

    The browser asks once, for https://huddles.space, and remembers. A denied prompt shows as "Microphone blocked — allow it in your browser settings" — in the island's bar, and now across the top of the call card. The fix is the padlock in the address bar: allow the microphone for this site, reload. Nothing on your side can override a denial.

Muted on join is not a fault. Every huddle starts with the microphone muted — the first press on the mute verb is the person choosing to be heard. If the verb reads Unmute, the microphone is working and waiting. And the camera verb appears only once the room has handed the frame a media grant, a second or so after joining; it is not missing, it is early.

You can be heard, but hear nothing#

Browsers refuse to play sound that no gesture asked for. Opening the card is a gesture on your page, and most browsers pass that down through allow="autoplay"; Safari sometimes does not. When the embed cannot play, it shows its own tap for sound gate inside the frame — one press, and the room is audible. If the gate never appears and there is still no sound, check policy.autoplay in the diagnosis.

Nothing mounts, or the frame is blank#

  1. The origin is not registered

    The app document is framable only by the exact origins on the app — scheme and host, no path, no trailing slash: https://app.example.com, not https://app.example.com/ or app.example.com. A page from an unregistered origin gets a frame the browser refuses to show, silently. Add the origin in the hub under the app, including every staging and preview host you use. diagnose: origin.

  2. The app id is wrong or revoked

    Huddles.init({ embedder }) must be the id from the hub. A revoked app's id stops resolving; the frame is a 404.

  3. A content blocker

    Some ad and tracker blockers refuse third-party frames wholesale. There is nothing to configure on our side; the diagnosis will show the frame never saying hello.

  4. In button mode, nothing mounts until a press

    By design. A page with Huddles.button() or mode: 'button' has no bar; the card appears when the button is pressed.

The token is refused (the frame loads, then "could not sign you in")#

It works in Chrome and not in Safari (or in a private window)#

The session cookie is Partitioned; SameSite=None; Secure, which is what makes it survive inside another site now that third-party cookies are gone. Two consequences: it needs https on both sides, and a browser that blocks all cookies in frames (some privacy settings, some private windows) will sign the person in on every load and forget them on the next. That is the browser's choice, not a fault; the token exchange still works each time.

The huddle button#

Nothing connects on a corporate network#

Voice and video travel over WebRTC to the media server, which prefers UDP and falls back to TURN over TLS on 443. A network that blocks UDP works, more slowly; one that inspects and drops TLS to unknown hosts does not. Allow *.livekit.cloud and https://huddles.space.

Reporting a bug#

Paste the Huddles.diagnose() table, the browser and version, and whether the person saw any flash across the bar or the card. With those three things most reports are answered on the first reply.

huddles.space · Blog · For Mac · Premium · Terms · Privacy · © 2026 Huddles.Space