# Script blocked by CSP

The exact Content-Security-Policy lines ProductLense needs, the hash for the inline queue stub, and the extra entries for proxied setups.

If your site sends a `Content-Security-Policy` header, the browser blocks anything the policy does not allow. When it blocks ProductLense, the console shows a message such as *Refused to load the script 'https://api.productlense.app/a.js' because it violates the following Content Security Policy directive*, and the Network tab shows the request as blocked.

## The lines to add

ProductLense needs two things: loading the script, and sending events to the same origin.

```text
script-src 'self' https://api.productlense.app 'sha256-QAzHnEuzZp5XrZOqqqgzRNwN4NNwWRVKhMNT7BOq49o=';
connect-src 'self' https://api.productlense.app;
```

- `https://api.productlense.app` in `script-src` allows `a.js`.
- The `sha256-` hash allows the inline queue stub exactly as written in the install snippet: `window.productlense=window.productlense||function(){(window.productlense.q=window.productlense.q||[]).push(arguments)}`. If you change one character or add whitespace inside the tag, the hash no longer matches. If you do not use the stub, leave the hash out.
- `connect-src` allows the event requests to `/api/e`, and the visitor id request to `/api/vid` used by cross-domain links and checkout tracking.

Add these values to your existing directives. Do not add a second `script-src`: when a directive appears twice, browsers use only the first.

## With a nonce instead of a hash

If your framework adds a nonce to inline scripts, give the stub the nonce and keep `https://api.productlense.app` in `script-src`:

```html
<script nonce="{{ csp_nonce }}">window.productlense=window.productlense||function(){(window.productlense.q=window.productlense.q||[]).push(arguments)}</script>
<script defer data-site="SITE_ID" src="https://api.productlense.app/a.js"></script>
```

With `'strict-dynamic'` in your policy, host allowlists are ignored; give the ProductLense tag the nonce too.

## When the script is proxied

If you serve the script from your own domain and send events through it (see the [proxy guides](/docs/proxy/overview)), `'self'` covers both and `https://api.productlense.app` can be removed. If you serve only the script and keep `data-api="https://api.productlense.app"`, keep `https://api.productlense.app` in `connect-src`.

## Check it works

1. Reload the page with the developer tools open. The console shows no CSP violation that mentions ProductLense.
2. The Network tab shows `a.js` with status `200` and a `POST` to `/api/e` with status `204`.
3. Your visit appears on the Live page in the ProductLense dashboard.
