Content Security Policy (CSP) Violations
What This Means
Content Security Policy (CSP) is a security header that controls which resources can load on your website. CSP violations occur when a resource is blocked because it doesn't match the policy rules. This can prevent scripts (including analytics), styles, images, and third-party integrations from working.
Impact on Your Business
Analytics and Tracking:
- Google Analytics blocked - No visitor data collected
- GTM container fails - All tags stop working
- Meta Pixel blocked - Facebook ad tracking breaks
- Conversion tracking disabled - Revenue attribution fails
Website Functionality:
- Third-party widgets won't load
- Embedded content (videos, maps) may be blocked
- Payment processors might not function
- Chat widgets and support tools fail
Security Benefits (When Configured Correctly):
- Prevents cross-site scripting (XSS) attacks
- Blocks unauthorized script injection
- Protects against data exfiltration
- Mitigates clickjacking attacks
How to Diagnose
Method 1: Browser Console (Primary)
- Open your website
- Open DevTools (
F12) - Navigate to Console tab
- Look for CSP errors:
Refused to load the script 'https://www.googletagmanager.com/gtm.js'
because it violates the following Content Security Policy directive:
"script-src 'self'".
What to Look For:
- "Refused to load the script" - Script blocked
- "Refused to load the stylesheet" - CSS blocked
- "Refused to connect to" - API/fetch blocked
- The directive name that blocked it (script-src, style-src, etc.)
Method 2: Network Tab
- Open DevTools → Network tab
- Reload the page
- Look for blocked requests (red or canceled)
- Check Status column for "(blocked:csp)"
Method 3: Security Tab
- Open DevTools → Security tab
- Review the security overview
- Click "View certificate" for details
Method 4: CSP Evaluator
- Navigate to Google CSP Evaluator
- Enter your CSP header value
- Review findings and recommendations
Method 5: Check Response Headers
// View CSP header in console
fetch(window.location.href)
.then(res => {
console.log('CSP:', res.headers.get('content-security-policy'));
console.log('CSP Report Only:', res.headers.get('content-security-policy-report-only'));
});
Or check in DevTools → Network → Select main document → Headers tab.
Understanding CSP Directives
Common Directives
| Directive | Controls | Example Blocked Resource |
|---|---|---|
script-src |
JavaScript files | GTM, GA4, third-party scripts |
style-src |
CSS stylesheets | Font libraries, widget styles |
img-src |
Images | External images, tracking pixels |
connect-src |
Fetch/XHR/WebSocket | API calls, analytics beacons |
font-src |
Web fonts | Google Fonts, custom fonts |
frame-src |
Iframes | YouTube embeds, payment forms |
media-src |
Audio/video | Hosted media files |
object-src |
Plugins (Flash, Java) | Legacy embeds |
default-src |
Fallback for all | Anything not specifically defined |
Common Sources
| Source | Meaning |
|---|---|
'self' |
Same origin only |
'unsafe-inline' |
Inline scripts/styles allowed |
'unsafe-eval' |
eval() and similar allowed |
'none' |
Block everything |
https: |
Any HTTPS source |
data: |
Data URIs allowed |
blob: |
Blob URLs allowed |
*.domain.com |
Wildcard subdomain |
https://specific.com |
Specific domain |
'nonce-abc123' |
Scripts with matching nonce |
'sha256-...' |
Scripts with matching hash |
General Fixes
Fix 1: Add Required Domains to CSP
For Google Analytics and GTM:
Content-Security-Policy:
script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com https://ssl.google-analytics.com;
img-src 'self' https://www.google-analytics.com https://www.googletagmanager.com;
connect-src 'self' https://www.google-analytics.com https://analytics.google.com https://region1.google-analytics.com;
For Meta Pixel:
Content-Security-Policy:
script-src 'self' https://connect.facebook.net;
img-src 'self' https://www.facebook.com https://www.facebook.com/tr/;
connect-src 'self' https://www.facebook.com;
For Google Fonts:
Content-Security-Policy:
style-src 'self' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
Fix 2: Complete CSP for Common Analytics Stack
Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval'
https://www.googletagmanager.com
https://www.google-analytics.com
https://ssl.google-analytics.com
https://connect.facebook.net
https://www.googleadservices.com
https://googleads.g.doubleclick.net;
style-src 'self' 'unsafe-inline'
https://fonts.googleapis.com
https://tagmanager.google.com;
img-src 'self' data:
https://www.google-analytics.com
https://www.googletagmanager.com
https://www.facebook.com
https://www.google.com
https://www.google.com/ads
https://googleads.g.doubleclick.net;
font-src 'self'
https://fonts.gstatic.com;
connect-src 'self'
https://www.google-analytics.com
https://analytics.google.com
https://region1.google-analytics.com
https://stats.g.doubleclick.net
https://www.facebook.com;
frame-src 'self'
https://www.google.com
https://www.youtube.com
https://www.facebook.com;
Fix 3: Use Report-Only Mode for Testing
Test CSP changes without breaking your site:
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' https://www.googletagmanager.com;
report-uri https://your-report-endpoint.com/csp;
This logs violations without blocking resources.
Fix 4: Add Nonces for Inline Scripts
Server-side (generate unique nonce per request):
<!-- In your HTML, with server-generated nonce -->
<script nonce="abc123xyz">
// Inline script content
gtag('config', 'G-XXXXXXXXXX');
</script>
CSP header:
Content-Security-Policy: script-src 'self' 'nonce-abc123xyz';
Fix 5: Platform-Specific Configuration
Apache (.htaccess):
Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com;"
Nginx:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com;";
Node.js/Express:
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://www.googletagmanager.com"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "https://www.google-analytics.com"],
connectSrc: ["'self'", "https://www.google-analytics.com"]
}
}));
Netlify (netlify.toml):
[[headers]]
for = "/*"
[headers.values]
Content-Security-Policy = "default-src 'self'; script-src 'self' https://www.googletagmanager.com;"
Vercel (vercel.json):
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; script-src 'self' https://www.googletagmanager.com;"
}
]
}
]
}
Fix 6: Use Meta Tag Fallback
When you can't set HTTP headers:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' https://www.googletagmanager.com;">
Note: Meta tag CSP has limitations:
- Cannot use
report-uri - Cannot use
frame-ancestors - Must be in
<head>early
Platform-Specific Guides
| Platform | Troubleshooting Guide |
|---|---|
| Shopify | Shopify CSP Guide |
| WordPress | WordPress CSP Guide |
| Webflow | Webflow CSP Guide |
Verification
After updating CSP:
Check Console for violations:
- No CSP errors should appear
- All scripts should load
- Analytics should function
Test analytics:
- Check GA4 Realtime reports
- Verify GTM Preview mode works
- Test Meta Pixel Helper
Monitor for new violations:
- Set up CSP reporting endpoint
- Review reports regularly
- Update CSP as you add services
Common Mistakes
- Too restrictive default-src - Blocks unexpected resources
- Missing connect-src - API calls fail silently
- Forgetting data: for images - Blocks inline images
- Not including 'self' - Blocks your own resources
- Using 'unsafe-inline' carelessly - Reduces security
- Forgetting wildcard subdomains - Need
*.google.comnot justgoogle.com - Not testing in Report-Only first - Breaking production
- Missing frame-src for embeds - YouTube/Vimeo fail
- Ignoring style-src - Widget styles break
- Not updating for new services - New tools blocked
Security vs. Functionality Balance
Strictest (Most Secure) ─────────────────────────────> Most Permissive
Strict CSP Balanced CSP Permissive CSP
- No inline - Nonce-based - 'unsafe-inline'
- Hash-based - Specific domains - 'unsafe-eval'
- Specific URLs - Wildcards limited - Broad wildcards
- No 'unsafe-*' - Report violations - Everything allowed
Recommendation: Start with Report-Only mode to identify all required resources, then implement the strictest policy that allows your site to function.