Muro
Troubleshooting

Fix Content Security Policy errors

Allow Muro in your site's Content Security Policy so the script can load and send events.

A Content Security Policy (CSP) tells the browser which domains your pages may load scripts from and send data to. If your site has one and it doesn't list Muro, the browser blocks the script or its requests and no data arrives. Use this page when the console shows a "Refused to load" or "Refused to connect" error mentioning Muro.

What to allow

Muro needs two domains, and both are required:

DirectiveAddWhy
script-srchttps://api.muroanalytics.comLets muro.js load.
connect-srchttps://cdn.muroanalytics.comLets the script send events.

With only script-src, the script loads but every event is blocked. With only connect-src, the script never runs.

Signs you have a CSP problem

Open DevTools → Console and reload. Look for messages like:

  • Refused to load the script 'https://api.muroanalytics.com/muro.js' because it violates the following Content Security Policy directive: "script-src …"
  • Refused to connect to 'https://cdn.muroanalytics.com/collect' because it violates the following Content Security Policy directive: "connect-src …"

In the Network tab, a blocked request shows as (blocked:csp) or never appears.

Fix it

Find where your CSP is set

Open DevTools → Network, click the first request (your page itself) and look under Response Headers for content-security-policy. If it isn't there, search your page source for a <meta http-equiv="Content-Security-Policy"> tag.

Common places a CSP is defined: next.config.js, middleware.ts, vercel.json, a _headers file (Netlify, Cloudflare Pages), your web server config, or a security plugin in your CMS.

Add both Muro domains

Add https://api.muroanalytics.com to script-src and https://cdn.muroanalytics.com to connect-src. Keep every source that's already there.

If your policy has no script-src or connect-src, the browser falls back to default-src. Either add both domains to default-src, or add explicit script-src and connect-src directives. If you add explicit ones, include everything your site already loads (at least 'self'), because they replace default-src for those request types.

Deploy and reload

Ship the change, then hard-reload your site so the browser picks up the new header.

Examples

Merge these values into your existing policy. Don't paste them over it.

// next.config.js
const securityHeaders = [
  {
    key: 'Content-Security-Policy',
    value:
      "script-src 'self' https://api.muroanalytics.com; connect-src 'self' https://cdn.muroanalytics.com",
  },
];

module.exports = {
  async headers() {
    return [{ source: '/:path*', headers: securityHeaders }];
  },
};
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "Content-Security-Policy",
          "value": "script-src 'self' https://api.muroanalytics.com; connect-src 'self' https://cdn.muroanalytics.com"
        }
      ]
    }
  ]
}
# _headers
/*
  Content-Security-Policy: script-src 'self' https://api.muroanalytics.com; connect-src 'self' https://cdn.muroanalytics.com
<meta
  http-equiv="Content-Security-Policy"
  content="script-src 'self' https://api.muroanalytics.com; connect-src 'self' https://cdn.muroanalytics.com"
/>

Policies with nonces or strict-dynamic

If your script-src uses 'strict-dynamic', modern browsers ignore domain allowlists for scripts. Add your page's nonce to the Muro tag instead, for example <script async nonce="…" src="https://api.muroanalytics.com/muro.js" data-project-id="YOUR_PROJECT_ID"></script>, using the same nonce your other scripts get. You still need https://cdn.muroanalytics.com in connect-src.

A Content-Security-Policy-Report-Only header only reports problems and never blocks anything. If that's the only policy you have, CSP isn't what's stopping Muro. See No events are showing.

Verify it works

  1. Reload your site with DevTools open.
  2. The Console shows no "Refused to" errors that mention Muro.
  3. The Network tab, filtered to collect, shows a POST to https://cdn.muroanalytics.com/collect with status 202.
  4. Set your dashboard time range to Live. Your visit appears within a minute or so.

Next steps

On this page