Skip to main content

What is a Content Security Policy (CSP)?

A Content Security Policy (CSP) contains data about what origins can be used to load and execute various resources inside your web application. A CSP essentially serves as an allowlist. Developers can define a CSP in their web applications to minimize the vector of attack against the app and its visitors. For example, you can specify a script-src directive to dictate which sources the user agent is allowed to execute JavaScript from while using your app. If you make use of a CSP in your web application, this guide will summarize the adjustments you might need to make to have it work with daily-js.

Enabling the CSP

The CSP is enabled in one of two ways:
  • By adding a Content-Security-Policy HTTP response header
  • By adding a Content-Security-Policy meta element to the site header

Daily Prebuilt

If using Daily Prebuilt, a minimal functional CSP can look like this:
The above policy contains two Daily-specific directives:
  • It allows the user agent to create an iframe with the Daily domain as the source, via the frame-src directive. Daily Prebuilt is also served from Daily’s fallback domains, so all three are listed.
  • It allows daily-js to be loaded and executed from Unpkg via the script-src directive.
If you are loading daily-js from a local source or somewhere other than Unpkg, you’ll need to adjust the origin in script-src accordingly. For example, if you are using npm and bundling the library into your app, only the 'self' origin should be needed.

Custom call object

If using call object mode, the CSP will require some different allowances. A minimal call object CSP can be defined as follows:
The above policy allows:
  • Loading daily-js from UNPKG (only needed if you’re loading daily-js via a script tag)
  • Loading relevant resources from Daily domains, including the fallback domains
  • Connecting to Daily calls
  • Connecting to Banuba, Daily’s video processing provider (only needed if you’re using virtual backgrounds or background blur)
Every daily.co host in your policy needs Daily’s fallback domains listed alongside it. A policy that lists only *.daily.co blocks the failover, and the call then fails at the moment the failover was meant to save it.

Avoiding the 'unsafe-eval' requirement

Call object mode in daily-js uses a code path that loads the call object bundle from Daily’s CDN and makes a Function() call to execute it, which results in an eval. You can create the call object via a code path that does not require 'unsafe-eval':
  1. Enable this alternative with the avoidEval property:
  1. Replace 'unsafe-eval' in your script-src directive with:
All three domains are needed here. With avoidEval turned on, the bundle is loaded with a script tag, so it is script-src that has to allow the fallback domains. Without avoidEval, the bundle is fetched instead, and connect-src covers it.

Listing hosts instead of a bare wss:

The examples above use a bare wss: in connect-src. That is a scheme source, so it matches on scheme alone. It lets the page open a WebSocket to any host, not just Daily’s. If your security review does not allow a whole scheme, narrow it to Daily’s domains instead:
Do not narrow those wss entries to the signaling hosts. The Networking guide lists those hosts in two forms for every base domain: *.wss.daily.co and *-wss.daily.co, plus the same pair on each fallback domain. That works for a firewall allowlist, but none of it translates to a CSP, for two reasons:
  • A CSP wildcard only works as a whole leading label. That rules out every *-wss. form: wss://*-wss.daily.co is not a valid source expression, so browsers drop the token and it allows nothing at all.
  • The *.wss. forms are valid but not enough on their own. When a socket to <server>.wss.daily.co fails, daily-js retries the same server as <server>-wss.daily.co, and wss://*.wss.daily.co does not match that retry host, so the join fails.
wss://*.daily.co matches both host shapes, which is why the example uses it. Note that it does not match the bare daily.co apex, only its subdomains.
Each base domain needs its own entry. A wildcard on one does not reach the others. See Daily fallback domains.You do not need to add ports. Signaling runs on 443, which is the default for wss, so a source expression without a port matches it. The other port ranges in the Networking guide carry WebRTC media, which a CSP does not govern, so they have no CSP equivalent.Listing hosts also means pinning to a list that can change as we add hosts. Treat the Networking guide as the canonical list and check it when you upgrade daily-js. The machine-readable IP list has the current call server hostnames, IPs, and port ranges, so you can diff it on a schedule instead of by hand.

CSP changes for noise cancellation

When using Krisp noise cancellation with Daily, your CSP must include blob: in the script-src directive. Krisp creates a worker using a blob: URL, and this ensures the browser permits loading such scripts. The CSP examples above already include this.

Wrapping up

Please contact us if you have any questions.