Fix CSP Errors on Next.js

CSP errors on Next.js usually show as Refused to load the script or Refused to execute inline script in the console. The fix depends on whether you need a static policy or nonce-based CSP for inline scripts.

Option 1 — Static CSP via next.config.js

Best for sites with no inline scripts. Add to next.config.js:

/** @type {import('next').NextConfig} */ const nextConfig = { async headers() { return [ { source: '/(.*)', headers: [ { key: 'Content-Security-Policy', value: [ "default-src 'self'", "script-src 'self' https://www.googletagmanager.com", "style-src 'self' 'unsafe-inline'", "img-src 'self' data: https:", "font-src 'self' https://fonts.gstatic.com", "connect-src 'self' https://www.google-analytics.com", "frame-ancestors 'none'", "object-src 'none'", "base-uri 'self'", ].join('; '), }, ], }, ]; }, }; module.exports = nextConfig;

Option 2 — Nonce-based CSP via Middleware (App Router)

Required when you have inline scripts that you can't remove. Generates a unique nonce per request:

// middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { v4 as uuidv4 } from 'uuid'; export function middleware(request: NextRequest) { const nonce = Buffer.from(uuidv4()).toString('base64'); const csp = [ "default-src 'self'", `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'`, "style-src 'self' 'unsafe-inline'", "img-src 'self' data: https:", "font-src 'self'", "frame-ancestors 'none'", "object-src 'none'", "base-uri 'self'", ].join('; '); const requestHeaders = new Headers(request.headers); requestHeaders.set('x-nonce', nonce); requestHeaders.set('Content-Security-Policy', csp); const response = NextResponse.next({ request: { headers: requestHeaders } }); response.headers.set('Content-Security-Policy', csp); return response; } export const config = { matcher: '/((?!_next/static|_next/image|favicon.ico).*)' };
// app/layout.tsx — read nonce and pass to Script tags import { headers } from 'next/headers'; export default function RootLayout({ children }) { const nonce = headers().get('x-nonce') ?? ''; return ( <html> <body> {children} <script nonce={nonce} src="/my-script.js" /> </body> </html> ); }

Report-only mode first

Always deploy as Content-Security-Policy-Report-Only first. Check the browser console for violations before switching to enforcing mode.

Scan your Next.js site for CSP issues → CSPFixer →