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:
| Directive | Add | Why |
|---|---|---|
script-src | https://api.muroanalytics.com | Lets muro.js load. |
connect-src | https://cdn.muroanalytics.com | Lets 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
- Reload your site with DevTools open.
- The Console shows no "Refused to" errors that mention Muro.
- The Network tab, filtered to
collect, shows aPOSTtohttps://cdn.muroanalytics.com/collectwith status202. - Set your dashboard time range to Live. Your visit appears within a minute or so.