Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.cognite.com/llms.txt

Use this file to discover all available pages before exploring further.

When you deploy a Flows custom app, the platform applies a strict Content Security Policy (CSP) — a browser security feature that controls which external resources the app is allowed to load. CSP limits where scripts, styles, images, fonts, frames, workers, media, and network requests can come from. Most apps only need to change CSP when they call an external API, load map tiles, embed a frame, use a CDN, or add a dependency that creates workers or evaluates code at runtime. Add trusted sources in permissions.network in manifest.json.
Run the app locally first. The Flows Vite plugin applies CSP during development and logs a manifest snippet when the browser blocks a request.

How it works

Use manifest.json to add trusted sources to supported fetch directives:
{
  "manifestVersion": 1,
  "permissions": {
    "network": [
      {
        "sources": ["https://tiles.example.test"],
        "directives": ["img-src", "connect-src"]
      },
      {
        "sources": ["https://api.partner.test"]
      }
    ]
  }
}
If directives is omitted, the source is added to connect-src. Apps can’t remove baseline restrictions, such as object-src 'none', or widen document-level directives, such as default-src and frame-ancestors. Every Flows app starts with the production baseline.

Debug CSP violations

Run the app locally:
npm run dev
When the browser blocks a request, the Vite plugin logs a manifest.json snippet to the browser console (DevTools → Console tab):
Flows Apps [linked-app-sdk v2] blocked connect-src -> https://tiles.example.test
Update your manifest.json with the snippet below:
{
  "manifestVersion": 1,
  "permissions": {
    "network": [
      {
        "sources": ["https://tiles.example.test"],
        "directives": ["connect-src"]
      }
    ]
  }
}
Paste the rule into manifest.json. The dev server picks up the change without a restart.

Production baseline

Hosted production apps use this CSP baseline:
frame-ancestors https://*.fusion.cognite.com https://*.fusion.cogniteapp.com
base-uri 'self'
connect-src 'self' https://*.cognitedata.com wss://*.cognitedata.com
default-src 'self'
font-src 'self' data: https://fonts.gstatic.com
form-action 'self'
frame-src 'self'
img-src 'self' data: blob:
media-src 'self'
object-src 'none'
script-src 'self'
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com
worker-src 'self' blob:
Important details:
  • CDF API and WebSocket endpoints are already allowed in connect-src.
  • Production script-src allows 'unsafe-inline' to be added via manifest.json, but this is strongly discouraged. Use hash sources instead.
  • eval and new Function(...) are always blocked in production, regardless of manifest.json.
  • style-src includes 'unsafe-inline' because many UI libraries inject style tags.
  • Aura font sources are already allowed.
  • frame-ancestors is controlled by App Hosting and can’t be changed from manifest.json.

Development differences

Development uses the same baseline with a few additions for Vite and local framing:
  • script-src also includes 'unsafe-inline' and 'unsafe-eval' for Vite HMR and React Refresh.
  • http://localhost, http://127.0.0.1, ws://localhost, and ws://127.0.0.1 sources are accepted during development.
  • Local and preview CDF origins can frame the app.
These additions are removed in production. Dependencies that rely on development-only script relaxations will fail after deployment.

Choose the right directive

Use the browser CSP error to identify the blocked directive, then add the narrowest source that covers it.
RequirementDirective
External HTTPS APIconnect-src
WebSocketconnect-src with a wss:// source
Map tiles, images, SVGs, or canvas texturesimg-src
Web fontsfont-src
CDN stylesheetstyle-src
Embedded iframeframe-src
Audio or videomedia-src
Worker script from another originworker-src
JavaScript file from another originscript-src
Use script-src only for trusted script files. It can’t approve eval, new Function(...), or inline script tags in production.

Manifest reference

Each permissions.network entry has this shape:
type NetworkRule = {
  sources: string[];
  directives?: CspFetchDirective[];
};
If directives is omitted, the source is added to connect-src. The valid values for CspFetchDirective are the eight directives in Extensible directives.

Extensible directives

Only these fetch directives can be extended:
connect-src, font-src, frame-src, img-src, media-src, script-src, style-src, worker-src
Rules that only target unsupported directives are dropped. Unsupported examples include default-src, frame-ancestors, object-src, base-uri, and form-action.

Source formats

Production accepts:
  • HTTPS sources, for example https://api.example.test or https://api.example.test:8443/v1
  • Secure WebSocket sources, for example wss://stream.example.test
  • Host wildcards, for example https://*.example.test
Development also accepts local HTTP and WebSocket sources:
  • http://localhost:3000
  • http://127.0.0.1:3000
  • ws://localhost:5173
  • ws://127.0.0.1:5173
For script-src, production also accepts:
  • 'wasm-unsafe-eval'
  • 'strict-dynamic'
  • Hash sources such as 'sha256-...', 'sha384-...', and 'sha512-...'
The policy rejects sources with whitespace, control characters, semicolons, stray quotes, javascript: URLs, data: URLs, and broad wildcards, such as https://*. Nonces are not supported — the Flows custom apps service does not generate per-request nonces.
manifest.json can’t add 'unsafe-eval' to production script-src. Adding 'unsafe-inline' is technically allowed but strongly discouraged — use a hash source to allowlist only the specific script you need, or move the code to an external file bundled by Vite. See inline scripts.

Examples

External API

{
  "manifestVersion": 1,
  "permissions": {
    "network": [
      {
        "sources": ["https://api.partner.test"]
      }
    ]
  }
}
Because directives is omitted, the source is added to connect-src.

Map tiles

{
  "manifestVersion": 1,
  "permissions": {
    "network": [
      {
        "sources": ["https://tiles.example.test"],
        "directives": ["img-src", "connect-src"]
      }
    ]
  }
}
Some map libraries fetch tile metadata with fetch() and load tile images through <img> or canvas, so they need both directives.

CDN stylesheet

{
  "manifestVersion": 1,
  "permissions": {
    "network": [
      {
        "sources": ["https://cdn.example.test"],
        "directives": ["style-src"]
      }
    ]
  }
}

WebAssembly

{
  "manifestVersion": 1,
  "permissions": {
    "network": [
      {
        "sources": ["'wasm-unsafe-eval'"],
        "directives": ["script-src"]
      }
    ]
  }
}
Add this only when a library needs WebAssembly compilation at runtime.

Common library issues

Some libraries use runtime patterns that production CSP blocks.

Libraries that use eval or new Function

Templating, expression, charting, and schema libraries sometimes compile strings into functions at runtime. That requires 'unsafe-eval' in script-src, which production apps don’t allow. Use a build-time compiler, a precompiled distribution, or a different dependency.

react-pdf and pdfjs-dist

Configure the PDF worker as a same-origin asset bundled by Vite:
import { pdfjs } from "react-pdf";

pdfjs.GlobalWorkerOptions.workerSrc = new URL(
  "pdfjs-dist/build/pdf.worker.min.mjs",
  import.meta.url
).toString();
The URL resolves to the app’s own origin, which is covered by 'self' in worker-src.

troika-three-text and reagraph

troika-three-text, used by reagraph, probes worker support with a blob worker and can call importScripts() with generated URLs. If that path is blocked, force troika onto the main thread before any Text instances or reagraph renders are created:
import { configureTextBuilder } from 'troika-three-text';

configureTextBuilder({ useWorker: false });

Inline scripts in script-src

Adding 'unsafe-inline' to script-src allows any inline <script> tag in the app to run, which removes a meaningful layer of XSS protection. Prefer one of these alternatives: Hash source — allowlists one specific inline script by its content hash. Nonces are not supported; hashes are the equivalent approach here.
  1. Compute the SHA-256 hash of the script body (no <script> tags, whitespace-exact):
    echo -n 'your inline script content here' | openssl dgst -sha256 -binary | base64
    
  2. Add the result to manifest.json:
    {
      "manifestVersion": 1,
      "permissions": {
        "network": [
          {
            "sources": ["'sha256-<base64-hash>'"],
            "directives": ["script-src"]
          }
        ]
      }
    }
    
External file — move the inline code into a .ts or .js file imported by the bundle. The bundler includes it as a same-origin script, which is covered by 'self' and requires no manifest change. If neither option is feasible and the inline script comes from a third-party library, check whether the library offers a CSP-compatible build or configuration option before falling back to 'unsafe-inline'.

Troubleshooting

It works locally but fails in production

Check for one of these causes:
  • The source is localhost, 127.0.0.1, http://..., or ws://.... Those are development-only.
  • A dependency relies on development-only script-src relaxations, such as 'unsafe-eval'.
  • The deployed bundle doesn’t include the manifest.json change. Redeploy the app after updating the manifest.
  • The blocked request happens inside a worker, where the dev warning may not produce a manifest snippet. Use the browser console’s CSP violation details to identify the directive and source.

The manifest rule is ignored

Check that:
  • manifestVersion is 1.
  • sources isn’t empty.
  • directives contains at least one supported fetch directive.
  • The source uses an allowed scheme and doesn’t contain whitespace, semicolons, control characters, or stray quotes.

A library asks for 'unsafe-inline' in script-src

This can be added via manifest.json but is strongly discouraged — it bypasses script integrity for every inline script in the app. Use a hash source to allowlist only the specific script, or move the code to an external file. See inline scripts.

A library asks for 'unsafe-eval' in script-src

'unsafe-eval' can’t be added to production script-src. Use a CSP-safe build, precompile the dynamic code, or replace the library.
Last modified on May 26, 2026