Version Pinning & Origins
Pin a CDN version, restrict allowed origins, and rotate the shared secret
Pin a CDN version, restrict which origins can load the widget, and rotate the shared secret.
Version Pinning
Unversioned bundle URLs serve the latest release (loader.js is cached for 5 minutes, widget.js for 1 minute). To lock a build, insert a version segment:
<!-- Latest - auto-updates -->
<script async src="https://cdn.wexio.io/widget/loader.js" data-public-key="pk_live_..."></script>
<!-- Pinned - immutable, never auto-updates -->
<script async src="https://cdn.wexio.io/widget/v1.7.9/loader.js" data-public-key="pk_live_..."></script>Pinned bundles are cached for a year and never invalidated, so a pin is reproducible. The same pattern works for widget.js and widget-react.js.
| Strategy | URL shape | When to use |
|---|---|---|
| Latest (recommended) | /widget/loader.js | You want bug fixes automatically. |
| Pinned | /widget/v1.7.9/loader.js | You need a reproducible build or are validating an upgrade. |
Legacy flat URLs resolve via CDN rewrites: /loader.js maps to /widget/loader.js, and /loader@1.7.9.js maps to /widget/v1.7.9/loader.js. Use the /widget/... paths for new embeds.
Allowed Origins
allowedOrigins restricts which website origins can load the widget with your public key. Each entry is a bare origin: scheme and host (and port), with no path, query, or hash:
https://example.com
https://app.example.comAn empty list allows any website to embed the widget, so fill it in. You can add up to 50 origins. Once it has entries, the backend enforces it on every visitor request, for the public key and for signed-in visitors alike:
- Exact match. The request's origin must match an entry exactly, ignoring case. There are no wildcards and no subdomain matching, so list each subdomain on its own line.
- HTTPS only. Use
https://origins, with a port when needed. - No origin, no access. A request without an origin is refused.
- Wexio domains. Wexio's own domains and the dashboard preview always pass.
Edit the list in the Widget settings under Security (in the Integration group). The list never appears in the widget's public config.
The allow-list also scopes WebAuthn. A passkey's relying-party id comes from the embedding origin and is checked against allowedOrigins. See Google & Passkey.
Rotating the Shared Secret
The shared secret is shown once at creation. If it leaked or you never copied it, open the Widget settings, go to Security, and click Rotate secret. Confirm Rotate the shared secret? with Rotate secret to get a new one.
- Copy the new secret. Rotation reveals it once. Update your server-side integration.
- Embeds keep working. They reference the public key, not the secret.
- Update your backend first. The old secret stops working at once, and rotation does not wait for Save.
After rotating, re-sign any JWT or HMAC proofs with the new secret.
Self-Hosting and CSP
The loader fetches the widget bundles from the Wexio CDN, which sends Access-Control-Allow-Origin: *, so you have no reason to re-host the JavaScript. If you have a strict CSP, allow https://cdn.wexio.io (script) and https://api.wexio.io (connect), plus https://challenges.cloudflare.com when Turnstile is enabled.
Related
- Install Methods - the CDN layout and cache policy.
- Integration settings - the dashboard controls for origins and the secret.
- Authentication - the proofs the shared secret signs.