What this means
Chrome prints: Refused to load the script '<URL>' because it violates the following Content Security Policy directive: "script-src ...". A CSP is an allow-list the server sends to the browser. The browser blocks any script whose source is not on the list. The message names the blocked URL and the directive that blocked it, which is all you need to fix it. Related messages for inline code start with 'Refused to execute inline script'.
Why it happens
- You added a third-party script (analytics, payments, chat, maps, captcha) after the policy was written.
- The policy was generated by an AI tool or copied from a template and lists only 'self'.
- The framework injects inline scripts, as Next.js does, and the policy has no nonce or hash for them.
- The policy is set in two places, for example a meta tag and a hosting header. When several policies apply, a resource must pass all of them.
- The third party loads further scripts from a second domain that is not listed.
How to fix it
- 1Copy the blocked URL and the directive from the console message.
- 2Decide whether you trust and need that script. If you do not recognise it, leave it blocked and find out what is loading it.
- 3Find where the policy is set: next.config.js headers, middleware, vercel.json, a Netlify _headers file, or a meta tag.
- 4Add the script's scheme and host to script-src. Be specific: https://js.stripe.com, not https: or *.
- 5For inline scripts, generate a nonce per request and add it to both the policy and the script tags. The Next.js CSP guide shows the middleware for this.
- 6Deploy, reload with the console open and repeat for any further blocked sources. Check connect-src, img-src and frame-src too, because the same widget often needs those.
Content-Security-Policy: default-src 'self'; script-src 'self'
Content-Security-Policy: default-src 'self'; script-src 'self' https://js.stripe.com; frame-src https://js.stripe.com; connect-src 'self' https://api.stripe.comHow to confirm the fix
- Reload your page with devtools open. The console should show no 'Refused to' messages and the feature that depends on the script should work.
- Check the policy your server really sends, using the curl command below. Look for duplicates.
- Test the policy still blocks what it should: in the console on your own site, run the snippet below. The browser should refuse the script.
curl -s -D - -o /dev/null https://www.yourapp.com | grep -i content-security-policy
const s = document.createElement('script');
s.src = 'https://example.com/not-allowed.js';
document.head.appendChild(s);Frequently asked questions
I never set a CSP. Where did it come from?
Check your framework config, middleware, hosting config files and the HTML head for a meta tag. Starter templates and AI tools often add one. Some embedded environments and browser extensions add their own.
Can I test a policy change without breaking the site?
Yes. Send the new policy in the Content-Security-Policy-Report-Only header first. The browser reports violations in the console without blocking anything.
Should I just remove the CSP?
No. It is a useful second layer against cross-site scripting. Adjusting it for one trusted host takes a few minutes.