Skip to content
GitHub
Get started →

Mic permission denied

When a visitor clicks the orb, the browser asks for microphone access. If they deny (or it’s blocked at the browser / OS level), the orb shows “Microphone access needed” and sits idle.

The user’s flow

  1. User clicks orb
  2. Browser shows the permission prompt (Chrome: top-left; Safari: top-right; Firefox: top-left)
  3. User clicks Allow → mic works → session begins
  4. If Block → prompt doesn’t reappear on future clicks (browser remembers)

Common issues

”Allow” is greyed out

The page isn’t served over HTTPS. Modern browsers refuse mic prompts on insecure origins. Fix: serve your site over HTTPS. Localhost is exempt; see below.

Prompt never appears, just “blocked”

The user previously blocked mic for this origin. They need to re-enable it:

  • Chrome — click the lock icon → Site settingsMicrophoneAllow
  • Safari — Safari menu → Settings for this websiteMicrophoneAllow
  • Firefox — click the shield / lock icon → Permissions → toggle Microphone

The widget can detect this state (via the Permissions API) and shows a tooltip: “Mic access is blocked — click the lock icon to re-enable.”

Permission granted but no audio

  • No mic plugged in. Laptop mic only; no USB / Bluetooth mic connected. Browser may pick an empty input.
  • Wrong default input. The OS has a different default than the user expects. Have them check System Settings → Sound → Input.
  • OS-level mic block. macOS System Settings → Privacy & Security → Microphone → make sure the browser is allowed. iOS / Android have similar toggles under Settings → Privacy.

Inside iframes

The widget doesn’t run inside iframes — even with allow="microphone" on the iframe. This is intentional because iframe mic delegation is fragile across browsers. Install at the top level.

Corporate MDM policies

Some enterprise IT policies block microphone access in browsers entirely. We’ve seen this at call centers and regulated industries. The user will need to file a request with IT to allow the origin.

VPN / proxy

Some VPNs (especially DPI / inspection proxies) break WebRTC’s audio negotiation. If mic works on plain Wi-Fi but not on VPN, that’s the cause. Disable the VPN or use a VPN with stun/turn passthrough.

Diagnostics

Open DevTools → Console. The widget logs:

[Spelo] navigator.permissions.query({ name: 'microphone' }) → state: 'denied'

The state field tells you what’s happening:

  • granted — should be working; check device-level issues
  • denied — explicitly blocked; user must re-enable
  • prompt — will ask on next user gesture

Custom error messages

You can override the “Mic access needed” text via custom_instructions:

If you detect that mic access is denied, tell the user:
"I can't hear you yet — click the lock icon in your address bar and enable microphone."

Designing around denial

Some sites want a fallback when mic access fails. Build a text-only chat UI for those cases; point to it from the widget’s error state. Enterprise plans can customize this UI.

On mobile

  • iOS Safari — works, but mic permission has a quirk: the prompt only fires in response to a user gesture (tap). The orb’s click handler is a gesture, so this works.
  • Android Chrome — works identically to desktop.
  • Mobile web apps added to Home Screen — the mic permission is scoped differently; users may need to re-grant even if they previously allowed in the browser.

Permission after refresh

Granting mic is per-origin, per-browser-profile. It persists across page reloads and sessions (until the user explicitly revokes). The widget doesn’t re-prompt on each click — it only prompts the first time.

Testing

From DevTools Console:

await navigator.mediaDevices.getUserMedia({ audio: true })

If this succeeds, mic is accessible. If it throws, the error message tells you why (NotAllowedError, NotFoundError, NotReadableError).

Accessibility

  • Users who can’t grant mic access (no device, low-vision users with screen readers, users with tremors that prevent clicking the orb) should have an alternate path on your site. The widget doesn’t replace conventional contact forms — it augments them.

See also