StarterApp Docs
Troubleshooting

CSP Headers

Resolve Content Security Policy violations and script blocking

CSP violations prevent resource loading but provide exact diagnostic information. Check browser console for violation reports, then adjust CSP configuration in packages/app-shell/src/security/csp.ts.

Scripts Blocked by CSP

Symptoms: Browser console shows CSP violation. Scripts fail to load.

Diagnosis: Script source not whitelisted or missing nonce attribute.

Solution:

Dashboard app uses nonce-based CSP. Add nonce to custom scripts:

app/layout.tsx
import { headers } from "next/headers";

export default async function Layout({ children }) {
  const headersList = await headers();
  const nonce = headersList.get("x-nonce");

  return (
    <html>
      <head>
        <script src="/analytics.js" nonce={nonce} />
      </head>
      <body>{children}</body>
    </html>
  );
}

For external scripts, add domain to CSP builder:

packages/app-shell/src/security/csp.ts
const CONNECT_SRC_BASE = [
  "'self'",
  "https://*.convex.cloud",
  "wss://*.convex.cloud",
  "https://analytics.example.com", // Add here
];

Images Not Loading

Symptoms: Images from external domains blocked. Console shows img-src violations.

Diagnosis: Image domain not whitelisted in CSP.

Solution:

Add image domains to CSP builder:

packages/app-shell/src/security/csp.ts
const IMG_SRC = [
  "'self'",
  "data:",
  "blob:",
  "https://lh3.googleusercontent.com",
  "https://your-cdn.example.com", // Add here
];

Also add to Next.js image configuration:

next.config.ts
images: {
  remotePatterns: [
    { protocol: "https", hostname: "your-cdn.example.com" },
  ],
}

Fonts Not Loading

Symptoms: Fonts from Google Fonts or external CDNs blocked.

Diagnosis: Font domain not in font-src directive.

Solution:

Google Fonts already whitelisted. For additional font providers:

packages/app-shell/src/security/csp.ts
const FONT_SRC = [
  "'self'",
  "https://fonts.gstatic.com",
  "data:",
  "https://fonts.example.com", // Add custom font CDN
];

WebSocket Connection Blocked

Symptoms: Convex real-time updates fail. Console shows connect-src violations.

Diagnosis: WebSocket URL not in connect-src directive.

Solution:

Convex domains already whitelisted (wss://*.convex.cloud). For additional WebSocket connections:

packages/app-shell/src/security/csp.ts
const CONNECT_SRC_BASE = [
  "'self'",
  "https://*.convex.cloud",
  "wss://*.convex.cloud",
  "wss://realtime.example.com", // Add custom WebSocket
];

Frame-Ancestors Blocking Embed

Symptoms: Application cannot be embedded in iframe.

Diagnosis: CSP sets frame-ancestors 'none' which blocks all embedding.

Solution:

packages/app-shell/src/security/csp.ts
// Change from:
["frame-ancestors", ["'none'"]],

// To allow specific embedders:
["frame-ancestors", ["'self'", "https://trusted-embedder.com"]],

Heads up

Only allow trusted domains. frame-ancestors prevents clickjacking attacks.

Inline Styles Blocked in Production

Symptoms: Tailwind classes work in development but fail in production.

Diagnosis: Dashboard production CSP requires nonce for inline styles.

Solution:

Dashboard CSP allows style-src-attr 'unsafe-inline' for Tailwind and motion libraries. Inline <style> tags require nonce:

const nonce = headersList.get("x-nonce");
<style nonce={nonce}>{`.custom { color: blue; }`}</style>

Marketing app allows all inline styles via 'unsafe-inline'.