OpenPWAStore
Back to News
Guide · May 19, 2026

CSP won't break PWA installability if configured correctly

CSP is compatible with PWA install prompts when you configure it to allow your service worker and app origins.

OpenPWA Editorial7 min read
CSP won't break PWA installability if configured correctly cover

Content Security Policy (CSP) is a security layer that prevents cross-site scripting (XSS) and injection attacks by defining which sources of content are safe to load. Some PWA developers worry that CSP headers might blocking service worker registration or install prompts, but CSP doesn't break PWA installability if you configure it correctly.

The key is understanding what CSP controls and what it doesn't. CSP governs what resources can be loaded from where, but it doesn't directly block browser features like PWA installation prompts or service worker lifecycle operations—those are controlled by permissions and app manifest validation.

What CSP actually restricts for PWAs

CSP affects these PWA-relevant operations:

  • Script loading — which origins can run JavaScript in your app
  • Service worker importsimportScripts() calls in your service worker code
  • Worker-src directives — which origins can spawn worker processes
  • Frame and connect sources — where your app can fetch data or embed iframes
  • Inline scripts and event handlers — whether onclick or eval()-like code is allowed

CSP does NOT affect:

  • PWA install prompt eligibility (that's based on manifest validation and HTTPS)
  • Service worker registration itself (you can register a SW file from your origin)
  • Service worker lifecycle events (install, activate, fetch)
  • Background sync or push notification permissions
  • Manifest file loading from your origin

If your PWA fails to show an install prompt, CSP is almost never the culprit—check your manifest, service worker registration timing, and HTTPS setup first.

How CSP and service workers work together

Service workers have a special relationship with CSP:

  1. Service workers run in a worker context with their own CSP evaluation
  2. The service worker file itself must load from your origin (or be same-origin)
  3. Scripts imported via importScripts() must satisfy CSP's worker-src or script-src directives
  4. The controlled page's CSP applies to page resources, not necessarily the service worker's execution

A common misconception is that CSP blocks service worker registration entirely. In reality, CSP blocks what the service worker can load, not whether it can be registered.

Minimal CSP for PWA installability

Here's a baseline CSP that works with PWAs without breaking installability:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'unsafe-inline';
  worker-src 'self';
  connect-src 'self' https://your-api.com;
  frame-src 'self';
  img-src 'self' data: https:;

Why this works:

  • 'self' allows your app's origin
  • worker-src 'self' allows service workers from your origin
  • script-src 'self' 'unsafe-inline' allows inline scripts (many frameworks need this)
  • connect-src allows API calls where you expect them
  • No overly restrictive script-src or worker-src that would block your SW file

You can tighten this over time, but start with something permissive enough that doesn't block known resources.

Common CSP mistakes that break PWAs

These CSP patterns cause PWA or service worker failures:

  1. Blocking your own origin:
Content-Security-Policy: script-src https://cdn.example.com 'unsafe-inline';

Why it fails: Your app's origin isn't in script-src, so your main app scripts fail to load.

Fix: Add 'self' or your specific origin.

  1. Confusing script-src with worker-src:
Content-Security-Policy: script-src 'self'; worker-src 'none';

Why it fails: worker-src: 'none' blocks service worker imports and execution.

Fix: Use worker-src 'self' or omit worker-src (defaults to script-src).

  1. Blocking importScripts() in service workers:
Content-Security-Policy: worker-src 'self' https://trusted-libs.com;

But the service worker does:

importScripts('https://untrusted-lib.com/sw-lib.js');

Why it fails: Import origin isn't in worker-src.

Fix: Add https://untrusted-lib.com to worker-src or move the script to your origin.

  1. Mixing local development with production CSP:
Running dev server at http://localhost:3000
CSP header: default-src 'self'; // blocks mixed localhost/https

Why it fails during dev: localhost:3000 requests get blocked by CSP meant for https://yourapp.com.

Fix: In development, either disable CSP or use permissive http://localhost:* in your dev build.

CSP and service worker debugging checklist

Use this checklist when troubleshooting CSP-related PWA issues:

  • [ ] Check your current CSP in DevTools → Application → Headers or Response headers
  • [ ] Look for CSP violations in Console → Violations tab
  • [ ] Verify service worker file loads successfully in Service Worker tab
  • [ ] Check if importScripts() calls are failing with CSP errors
  • [ ] Test with CSP disabled to confirm CSP is the issue
  • [ ] Check if inline scripts in your app need unsafe-inline
  • [ ] Verify default-src doesn't block 'self' (your own origin must be allowed)
  • [ ] Confirm worker-src allows your SW origin (usually 'self')
  • [ ] Check for external font/icon CDNs that need font-src or img-src exemptions
  • [ ] Test in installed PWA mode—CSP can behave differently in standalone windows

Framework-specific CSP patterns

Different PWA frameworks have CSP requirements:

React (Create React App):

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'unsafe-inline' 'unsafe-eval';
  style-src 'self' 'unsafe-inline';
  connect-src 'self';

React often needs unsafe-inline for development-time hot reloading and inline styles.

Vue.js (Vite/CRA):

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'unsafe-inline';
  style-src 'self' 'unsafe-inline';
  worker-src 'self';

Vue templates compile to inline scripts, so unsafe-inline is typically required in dev.

Next.js App Router:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval';
  style-src 'self' 'unsafe-inline';
  worker-src 'self';

Next.js uses WebAssembly and dynamic imports, which require specific CSP directives.

Static site generators (Hugo, Jekyll):

Content-Security-Policy:
  default-src 'self';
  script-src 'self';
  style-src 'self';
  worker-src 'self';

SQL sites can use the strictest CSP since there's no runtime framework.

CSP migration strategy

If you're adding CSP to an existing PWA:

  1. Start with Content-Security-Policy-Report-Only to see violations without blocking anything
  2. Monitor violations for 1-2 weeks to understand your app's resource usage
  3. Add required origins to CSP directives based on violation reports
  4. Gradually tighten CSP by removing overly broad directives like unsafe-inline
  5. Test after each change to ensure PWA still functions and installs correctly
  6. Switch from Report-Only to enforced once violations stabilize

Never switch directly from no CSP to a locked-down policy—you'll break your own app.

CSP and mixed content

PWA installability HTTPS requirements sometimes conflict with legacy CSP patterns:

Problem: CSP headers block http:// resources, but your app loads fonts or images from non-HTTPS URLs.

Result: Browser blocks the resource, potentially breaking app rendering or install prompt.

Fix:

  • Migrate allResources to HTTPS
  • If must load HTTP resources, request protocol-relative URLs (//example.com/resource)
  • Add specific HTTP origins to CSP temporarily, but plan HTTPS migration
  • Check DevTools console for mixed content warnings

Note: PWA install prompts require HTTPS origin, so HTTP resources inside a HTTPS PWA are already suspect.

CSP reporting and monitoring

For production PWAs, enable CSP violation reporting:

Content-Security-Policy-Report-Only:
  default-src 'self';
  script-src 'self' 'unsafe-inline';
  worker-src 'self';
  report-uri /csp-violations;
  report-to csp-endpoint;

Set up a Report-To endpoint to collect violations:

// In your service worker or app
self.addEventListener('report', (event) => {
  if (event.type === 'cspViolation') {
    // Log or send to your analytics
    console.log('CSP Violation:', event.violation);
  }
});

This helps you catch CSP regressions before they break PWA functionality.

Legacy browser fallbacks

Older browsers have incomplete CSP support:

  • Old Edge (EdgeHTML): Limited CSP 1 support
  • IE 11: No CSP support
  • Old Safari: Missing some CSP 3 directives

If your PWA targets older browsers:

  1. Feature detect CSP before assuming certain directives work
  2. Use meta CSP tags for maximum compatibility (incomplete directive syntax may be ignored)
  3. Avoid the newest CSP features (like script-src-elem, script-src-attr) unless you check browser support
  4. Provide graceful degradation if CSP breaks app functionality

For modern PWAs, you can safely assume CSP 2+ support, but test on your target browsers.

Practical OpenPWA angle

From an installability and security perspective:

  • CSP adds security without breaking install prompts when configured correctly
  • Security and installability aren't tradeoffs—both are required for user trust
  • Users notice security warnings in the browser console, even if they don't read them
  • IT security reviews often require CSP for enterprise PWA approval
  • App store reviewers for PWAs (where applicable) may check for security headers

A PWA with a well-configured CSP is more likely to pass security reviews, work reliably on enterprise-managed devices, and avoid unexpected breakages from browser security updates.

Next steps

If you're building a new PWA:

  1. Add CSP during initial development, not as an afterthought
  2. Use Report-Only mode initially while figuring out required origins
  3. Document any required CSP exemptions for external services
  4. Test in installed PWA mode—CSP can behave differently than in browser tabs

If you're adding CSP to an existing PWA:

  1. Start with Report-Only CSP to collect violations without blocking
  2. Fix legitimate violations by migrating resources or updating CSP
  3. Gradually migrate from unsafe-inline to stricter script-src policies
  4. Monitor production CSP violations for regressions after deployment

CSP doesn't break PWAs—it makes them more secure when you understand what it controls and how to configure it for your app's needs.