How to Use Content Security Policy in Shopify Hydrogen for Domain-Specific Media Access

Control which domains can serve fonts, images, and styles in your Hydrogen app using createContentSecurityPolicy.

Import createContentSecurityPolicy:Hydrogen provides a utility to easily configure CSP headers.

import {createContentSecurityPolicy} from '@shopify/hydrogen';

entry.server.tsx

Configure Allowed Sources:Pass CSP directives into createContentSecurityPolicy. You can specify domains for specific media types:

const {nonce, header, NonceProvider} = createContentSecurityPolicy({
  fontSrc: [
    `'self'`,
    'fonts.googleapis.com',
    'fonts.gstatic.com'
  ],
  imgSrc: [
    `'self'`,
    'data:',
    'https://cdn.shopify.com',
    'https://d22po4pjz3o32e.cloudfront.net'
  ],
  styleSrc: [
    `'self'`,
    'fonts.googleapis.com',
    'fonts.gstatic.com',
    `'unsafe-inline'` // Required for inline styles
  ],
  shop: {
    checkoutDomain: context.env.PUBLIC_CHECKOUT_DOMAIN,
    storeDomain: context.env.PUBLIC_STORE_DOMAIN,
  },
});

entry.server.tsx

Apply the CSP Header to the Response:Inject the CSP header into the outgoing response.

responseHeaders.set('Content-Security-Policy', header);

entry.server.tsx

Wrap the Rendered App with NonceProvider:Ensures nonce support for inline scripts/styles if needed.

const body = await renderToReadableStream(
  <NonceProvider>
    <RemixServer context={remixContext} url={request.url} nonce={nonce} />
  </NonceProvider>,
  { nonce, signal: request.signal }
);

entry.server.tsx

Final Response Setup:

return new Response(body, {
  headers: responseHeaders,
  status: responseStatusCode,
});

entry.server.tsx