# Content Security Policy

> What to allow in your CSP so the analytics script and the widgets work, and how to need nothing at all by serving them from your own domain.

If your site sends a `Content-Security-Policy` header, the browser only loads scripts and makes requests you have allowed. Everything from Launch runs from our domains, so a policy that lists only your own site blocks it. Nothing breaks visibly: the script simply never runs, and a widget may render without its styles.

This page lists exactly what to allow. It was checked in Chrome against a page with a strict policy on 19 September 2026.

## What to allow

Add only the parts you use.

| You use | Directive | Value |
|---|---|---|
| Web analytics | `script-src` | `https://e.nordva.dev` |
| Web analytics | `connect-src` | `https://e.nordva.dev` |
| A widget (waitlist, feedback, changelog, notification bell, feedback board) | `script-src` | `https://cdn.nordva.dev` |
| A widget, or your own form calling the API | `connect-src` | `https://api.nordva.dev` |
| Changelog entries with cover images or images in the text | `img-src` | The host your images are on (Launch stores no images) |

A policy for a site using the analytics script and the waitlist widget:

```
Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://e.nordva.dev https://cdn.nordva.dev;
  connect-src 'self' https://e.nordva.dev https://api.nordva.dev;
```

Keep the rest of your policy as it is.

### Styles

The widgets style themselves with a constructed stylesheet, which a policy treats as script, not as an inline style, so `style-src` needs nothing. Browsers without that feature (before Chrome 73, Safari 16.4 or Firefox 101) fall back to a `<style>` element, which a strict `style-src` blocks; the widget still works, without its styling. Widget versions: waitlist 1.4.0, feedback 1.2.0, changelog 1.2.0 and later; the notification bell and changelog 2.0 (every display mode, the launcher, the count on your own menu item and the announcement) work this way inside their own shadow roots, and were checked in Chrome under `default-src 'none'; script-src 'self'; style-src 'self'`; so was the feedback board widget (`board.js` 1.0.0, 30 September 2026). None of them sets a `style` attribute or writes HTML.

### Nonces and hashes

Launch's script tag carries no inline code, so a `nonce` on it is optional. If your policy uses `strict-dynamic`, a nonce on the tag is the simplest way to let it load.

## Or allow nothing: serve it from your own domain

If you would rather not name our hosts in your policy, pass the analytics script and its requests through a path on your own domain. Then `script-src 'self'` and `connect-src 'self'` are enough, and ad blockers that block analytics hosts stop dropping visits as well.

Open **Insights** in the dashboard: under the script tag, "Serve it from your own domain" creates the proxy key and shows the tag for the proxied path. The server recipes are in [Serve analytics from your own domain](/guides/analytics-proxy).

This covers analytics. Widgets still load from `cdn.nordva.dev` and post to `api.nordva.dev`, so a site that uses them needs those two in the policy.

## Checking it

1. Open your site with the developer console visible.
2. A blocked resource says so plainly: "Refused to load the script 'https://e.nordva.dev/v1/s.js' because it violates the following Content Security Policy directive".
3. Fix the directive it names, reload, and confirm the console is quiet.

To find out what a new policy would break before you enforce it, send it as `Content-Security-Policy-Report-Only` first: the browser reports violations without blocking anything.

## Where the policy comes from

Some hosts add a policy for you. If you didn't write one and still see violations, look at:

- **Cloudflare:** Rules, then Transform Rules, then Response Header Transform Rules.
- **Vercel and Netlify:** the `headers` section of your project's configuration file.
- **A framework or plugin** that sets security headers by default.

Browser extensions that block trackers are a different thing: they block requests without any policy, and the person using the browser decides that. Serving the script from your own domain is what keeps those visits counted.

Source: https://docs.nordva.dev/guides/content-security-policy/
