> ## Documentation Index
> Fetch the complete documentation index at: https://docs.servicebooked.ca/llms.txt
> Use this file to discover all available pages before exploring further.

# Voice calls not working

> Fix the "Call failed" message on the widget's voice call button — usually a security header on your website blocking the microphone.

If the **Call** button in your chat widget shows **Call failed** instead of connecting, this page walks through the causes in the order they actually happen.

Text chat is never affected by any of this. A visitor who can't start a voice call can always type instead.

## We'll usually tell you first

If your website blocks the microphone, a warning appears at the top of **Dashboard → Widget** naming the site involved — you don't have to wait for a customer to report it.

The warning clears itself. Once you've fixed the header, the next visitor to your site tells us the policy is fine and it disappears; there's nothing to dismiss or mark as done.

It only appears when **Voice calls** is switched on for your widget, since a text-only widget doesn't use the microphone.

## Start here: read the message

The widget tells you which problem you have. Match the wording:

| What the visitor sees                                               | What it means                                                   | Who fixes it        |
| ------------------------------------------------------------------- | --------------------------------------------------------------- | ------------------- |
| "This website's settings block microphone access for embedded chat" | Your website sends a security header that blocks the microphone | **You** — see below |
| "No microphone found"                                               | No mic on the device                                            | The visitor         |
| "Your microphone is in use by another app"                          | Another app has the mic open                                    | The visitor         |
| "This browser can't access a microphone"                            | Old or unsupported browser                                      | The visitor         |
| Browser popup, then nothing                                         | The visitor declined the mic prompt                             | The visitor         |

Only the first one is something you can fix. It's also the only one that fails for **every** visitor, so if nobody can call, start there.

## Your website blocks the microphone

<Warning>
  This one is easy to miss because **it usually works in Firefox and fails in Chrome**. Chrome enforces the header strictly; Firefox does not. "It worked on my laptop" is not a test.
</Warning>

### Why it happens

Websites can send a `Permissions-Policy` header that lists which browser features are allowed. A very common security recommendation is to paste in this line:

```
Permissions-Policy: geolocation=(), microphone=(), camera=()
```

`microphone=()` is an **empty allowlist**. It doesn't mean "ask first" — it means *no origin may use the microphone*, including anything embedded on the page. The chat widget is embedded, so the call is refused before the visitor is ever asked.

If a developer or agency built your site, or you followed a security-headers checklist, there's a real chance this line is on it. Site builders like Wix, Squarespace, GoDaddy, and WordPress.com don't add it, so most businesses are unaffected.

### Check your site

Open your website in Chrome, press <kbd>F12</kbd>, go to the **Network** tab, reload the page, click the first request, and look under **Response Headers** for `permissions-policy`.

If the value contains `microphone=()`, that's your problem. If there's no `permissions-policy` header at all, you're fine — the cause is something else on this page.

### Fix it

Change **only** the `microphone` part, so it names the widget's address. Leave the rest of your security headers exactly as they are.

Replace `microphone=()` with:

```
microphone=(self "https://app.servicebooked.ca")
```

Then find where your headers are set and apply it.

<AccordionGroup>
  <Accordion title="Netlify">
    In `netlify.toml`. Note the **single** quotes around the whole value — the value contains double quotes, so a double-quoted string won't parse.

    ```toml theme={null}
    [[headers]]
      for = "/*"
      [headers.values]
        Permissions-Policy = 'geolocation=(), microphone=(self "https://app.servicebooked.ca"), camera=()'
    ```

    Or in a `_headers` file in your publish directory:

    ```
    /*
      Permissions-Policy: geolocation=(), microphone=(self "https://app.servicebooked.ca"), camera=()
    ```
  </Accordion>

  <Accordion title="Vercel">
    In `vercel.json`:

    ```json theme={null}
    {
      "headers": [
        {
          "source": "/(.*)",
          "headers": [
            {
              "key": "Permissions-Policy",
              "value": "geolocation=(), microphone=(self \"https://app.servicebooked.ca\"), camera=()"
            }
          ]
        }
      ]
    }
    ```

    If your site is Next.js and sets headers in `next.config.js` instead, edit it there — don't add a second copy in `vercel.json`.
  </Accordion>

  <Accordion title="Cloudflare">
    If you enabled **Security Headers** under Rules → Transform Rules → Managed Transforms, edit the response-header rule that sets `Permissions-Policy` and change the microphone entry.

    If you use a Cloudflare Worker, find the `Permissions-Policy` line in the Worker script and change it there.
  </Accordion>

  <Accordion title="Nginx">
    In your server block:

    ```nginx theme={null}
    add_header Permissions-Policy 'geolocation=(), microphone=(self "https://app.servicebooked.ca"), camera=()' always;
    ```

    Reload with `nginx -s reload` after editing.
  </Accordion>

  <Accordion title="Apache / cPanel / .htaccess">
    In `.htaccess` or your vhost config:

    ```apache theme={null}
    Header always set Permissions-Policy "geolocation=(), microphone=(self \"https://app.servicebooked.ca\"), camera=()"
    ```

    Some shared hosts (HostGator and similar) add a restrictive policy for you at the server level. If your `.htaccess` change doesn't take effect, ask your host's support to allow the microphone for `https://app.servicebooked.ca`.
  </Accordion>

  <Accordion title="WordPress">
    WordPress doesn't add this header by default — a plugin or your host does.

    Check your security plugin first (Wordfence, Really Simple SSL, iThemes/Solid Security, All In One WP Security). Look for a "security headers" or "Permissions-Policy" setting and edit the microphone entry there.

    If no plugin is responsible, the header is coming from your host — see the Apache section above, or ask your host.
  </Accordion>

  <Accordion title="Wix, Squarespace, GoDaddy, Weebly, Duda">
    These platforms don't send a `Permissions-Policy` header, so this problem almost certainly isn't yours. Check the header as described above to confirm, then work through the other causes on this page.

    These builders don't let you set custom headers, so if you do somehow see a blocking policy, contact their support — it would be coming from the platform, not from your site.
  </Accordion>
</AccordionGroup>

### Confirm the fix

After your site redeploys, reload it with <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>R</kbd> (<kbd>Cmd</kbd>+<kbd>Shift</kbd>+<kbd>R</kbd> on Mac). Chrome reads this header when the page loads and holds onto it, so an ordinary refresh can keep using the old rule and make a correct fix look broken.

Then open the widget and tap **Call**.

<Note>
  Editing the header is safe: you're allowing the microphone for one specific address, not for the whole internet. Your other locked-down features — camera, location — stay exactly as they were.
</Note>

## The visitor declined the microphone

Browsers ask permission the first time, per website. If a visitor picks **Block**, the browser remembers it and the widget can't re-prompt.

They can undo it by clicking the padlock (or the camera/mic icon) in the address bar and setting Microphone back to **Ask** or **Allow**, then reloading.

Nothing to fix on your end — but it's worth knowing that this is per visitor, not a site-wide fault.

## Corporate and school networks

Some office and school networks block WebRTC, which voice calls use. Those visitors fall back to text chat automatically and see no error worth acting on.

This is invisible to you and not fixable from your side. It's another reason the widget always keeps text chat available.

## Nothing above matches

Check the widget's own settings before assuming a bug:

* Your plan is **Growth or Pro**
* The AI Receptionist has a voice assistant configured — see [AI Receptionist](/phone-and-voice/voice-ai-assistant)
* **Voice calls** is switched on under Dashboard → Widget → Content
* You haven't used up the month's voice minutes

If the **Call** button isn't visible at all, it's one of those four — not a microphone problem. See [Web call button](/chat-widget/web-call-button) for the full list of conditions.

Still stuck? [Contact support](/troubleshooting/contact-support) and include your website address plus which browser you tested in. The browser matters — it's often the first clue.
