Content Security Policy (CSP) Violations | Blue Frog Docs

Content Security Policy (CSP) Violations

Diagnose and fix CSP violations that block scripts, styles, and resources on your website

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:

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)

  1. Open your website
  2. Open DevTools (F12)
  3. Navigate to Console tab
  4. 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

  1. Open DevTools → Network tab
  2. Reload the page
  3. Look for blocked requests (red or canceled)
  4. Check Status column for "(blocked:csp)"

Method 3: Security Tab

  1. Open DevTools → Security tab
  2. Review the security overview
  3. Click "View certificate" for details

Method 4: CSP Evaluator

  1. Navigate to Google CSP Evaluator
  2. Enter your CSP header value
  3. 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:

  1. Clear browser cache and reload

  2. Check Console for violations:

    • No CSP errors should appear
    • All scripts should load
    • Analytics should function
  3. Test analytics:

    • Check GA4 Realtime reports
    • Verify GTM Preview mode works
    • Test Meta Pixel Helper
  4. Monitor for new violations:

    • Set up CSP reporting endpoint
    • Review reports regularly
    • Update CSP as you add services

Common Mistakes

  1. Too restrictive default-src - Blocks unexpected resources
  2. Missing connect-src - API calls fail silently
  3. Forgetting data: for images - Blocks inline images
  4. Not including 'self' - Blocks your own resources
  5. Using 'unsafe-inline' carelessly - Reduces security
  6. Forgetting wildcard subdomains - Need *.google.com not just google.com
  7. Not testing in Report-Only first - Breaking production
  8. Missing frame-src for embeds - YouTube/Vimeo fail
  9. Ignoring style-src - Widget styles break
  10. 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.

Additional Resources

// SYS.FOOTER