Content Security Policy
If your site uses a strict Content Security Policy (CSP), you may need to adjust it for the FanID Widget. CSP rules
must allow your tenant domain — whichever URL you passed to baseUrl.
Required directives
When loading from unpkg CDN
Content-Security-Policy:
script-src 'self' https://unpkg.com;
style-src 'self' https://unpkg.com 'unsafe-inline';
connect-src 'self' https://your-org.fanid.co;
img-src 'self' https://your-org.fanid.co data:;
When self-hosting or bundling
Content-Security-Policy:
script-src 'self';
style-src 'self' 'unsafe-inline';
connect-src 'self' https://your-org.fanid.co;
img-src 'self' https://your-org.fanid.co data:;
Replace https://your-org.fanid.co with the exact baseUrl you pass to FanIDWidget.init(). If you use a custom
domain (e.g. https://fans.your-site.com), substitute that instead.
Directive breakdown
| Directive | Required for | Value |
|---|---|---|
script-src | Loading the widget script | CDN domain or 'self' if self-hosted |
style-src | Widget panel CSS + injected gate styles | 'unsafe-inline' required for injected <style> tag |
connect-src | API calls to your FanID tenant | The exact baseUrl (e.g. https://your-org.fanid.co) |
img-src | Organization logo in overlays | Same as connect-src |
connect-src covers both transports — bearer-mode requests that send an Authorization header (the normal case for
any page not served from the tenant host) and cookie-mode requests with credentials: 'include'. The browser does
not require 'Authorization' to be listed anywhere in CSP; custom request headers are governed by CORS, not CSP. If
your tenant runs on a different origin than baseUrl suggests (e.g. behind a custom domain), allowlist that origin
in connect-src and img-src instead.
CORS request headers
The Authorization header used in bearer transport is added automatically by the widget. Your tenant's CORS
configuration (managed by FanID) already lists Authorization and Content-Type as allowed request headers —
nothing extra is required from you. If you front the tenant with your own reverse proxy or WAF, make sure that
proxy preserves both headers on /api/subscriber/* requests.
Request telemetry and CSP
Every API request the widget sends carries widget_version and widget_transport query parameters
(see Cross-Domain Setup). No CSP directive is
needed for them. CSP source expressions match scheme, host, port, and path — never the query
string — so a connect-src entry that already allows your tenant origin allows these requests
unchanged.
What can break them is infrastructure, not policy: if you front your tenant with a reverse proxy,
CDN, or WAF, make sure it does not strip unknown query parameters from /api/subscriber/*.
'unsafe-inline' for styles
The gated content overlay injects a <style> tag into <head> with randomized CSS class names. This requires
'unsafe-inline' in style-src. The injected styles only affect elements with the generated random class names and do
not conflict with your existing stylesheets.
Troubleshooting
If the widget fails silently, check your browser console for CSP violation reports. Common issues:
- Blocked API calls: Add your tenant
baseUrltoconnect-src - Missing logo: Add your tenant
baseUrltoimg-src - Invisible overlay: Add
'unsafe-inline'tostyle-src Authorizationheader stripped: a custom proxy in front of the tenant may be dropping the header — verify the bearer reaches/api/subscriber/meend-to-end