Skip to content

Content-Security-Policy ​

If your site sends a Content-Security-Policy, add your chat server to these directives:

DirectiveWhy
script-src https://chat.example.comwidget.js. With a nonce-based policy, also put your nonce on the script tag.
connect-src https://chat.example.comwidget.js fetches the bot's settings from the server.
frame-src https://chat.example.comThe chat window is an iframe on the server.
img-src https://chat.example.comThe launcher shows the agent's face picture, from /core/<hash>/assets/skins/ (or /v1/widget/faces/ for a face made from a photo).

That's all. The chat's WebSocket, audio and camera all belong to the chat window, which runs on the chat server under its own policy, so your connect-src doesn't need wss:.

A complete strict policy, with a nonce and Trusted Types enforced:

text
default-src 'self';
script-src 'nonce-RANDOM' https://chat.example.com;
connect-src 'self' https://chat.example.com;
frame-src https://chat.example.com;
img-src 'self' data: https://chat.example.com;
style-src 'self' 'nonce-RANDOM';
object-src 'none';
base-uri 'none';
require-trusted-types-for 'script';
trusted-types 'none'
html
<script nonce="RANDOM" src="https://chat.example.com/widget.js" data-bot="pk_your_bot_id" async></script>

examples/strict-csp/ in the repo serves a page with exactly this policy (headers.json), and the end-to-end tests check that the chat works there with no violations.

Styles ​

No style-src change is needed. The launcher's styles are constructable stylesheets inside a shadow root, which a CSP doesn't govern; positions are set through the CSSOM, not style attributes. In browsers without constructable stylesheets, widget.js falls back to a <style> element with the nonce from its own script tag. Only with no nonce in such a browser does it link https://chat.example.com/widget.css, which then needs the host in style-src.

Nonces and strict-dynamic ​

widget.js reads the nonce from its own <script> tag. With 'strict-dynamic', the nonce on the tag is enough (host lists are ignored under it). With the npm package, pass nonce to bootWirefaceChat() or loadWirefaceChat(): it goes on the script tag the package adds.

Trusted Types ​

widget.js never assigns HTML strings or script URLs: it builds its elements with createElement and textContent. It runs under require-trusted-types-for 'script' with trusted-types 'none'.

The npm package adds widget.js by setting a script element's src, which Trusted Types guards. Where the browser has Trusted Types, it makes the URL through a policy named wireface-chat, which only ever passes the widget.js URL built from your host. Allow that name in your policy:

text
require-trusted-types-for 'script';
trusted-types wireface-chat

(Add it to the names you already allow, e.g. trusted-types my-app wireface-chat.) If the name isn't allowed, the package doesn't create the policy and the browser blocks the script. The script tag in your HTML needs no policy at all.

The chat's own policy ​

The other direction is handled for you: the chat window is sent with frame-ancestors built from the bot's allowed origins, so other sites can't put your bot in a frame. Every page up the frame chain must be allowed, so a page of yours shown inside someone else's iframe can't show the chat.

Microphone and camera ​

The chat window's iframe asks for microphone, camera, autoplay and clipboard-write. If your site sends a Permissions-Policy header that limits those, delegate them to the chat host, for example:

text
Permissions-Policy: microphone=(self "https://chat.example.com"), camera=(self "https://chat.example.com")

Without that, voice fails with mic_denied and the camera with camera_denied.

Finding what's blocked ​

The browser console names each blocked request. Typical signs:

  • the launcher never appears and the console shows network: connect-src is missing the host;
  • the launcher appears but the window stays empty, then frame_blocked after 15 seconds: frame-src;
  • the launcher shows no face picture: img-src.

Try a new policy as Content-Security-Policy-Report-Only first to see what it would block.

Wireface Chat 0.1.0. These docs are served by your own server.