Widget

Widget Installation Boundary

How the Keva widget is published and installed, and its current availability

Keva builds the widget bundle from source on every deploy and serves it at <your-keva-origin>/widget/v1/keva-widget.js. Settings > Widget shows the exact snippet for each enabled installation; it is built from the address you are reading Settings from, so a widget installed from a preview talks to that preview.

Required authority

Current source uses two separate values:

  1. A non-secret publicId, created for one selected workspace and an exact set of HTTPS origins.
  2. A short-lived opaque session returned after an allowed browser origin exchanges the public ID. The SDK holds the token in memory and sends it only in an authorization header.

General REST credentials are not widget installation credentials and must not be placed in browser markup, public environment variables, URLs, analytics, or logs.

Dashboard state

In Settings > Widget, an authorized member can configure the tenant-wide widget settings and, once the schema exists, manage workspace-scoped public installations. A public installation requires:

  • a descriptive name;
  • the currently selected workspace;
  • one to ten exact HTTPS origins with no path, query, fragment, wildcard, or user information.

Revoking an installation also revokes its active sessions locally. The widget is not available for customer use until database setup, deployment, and browser behavior are ready.

Installing the widget

Each enabled, unrevoked installation shows an install snippet. Copy it and paste it before </body> on your site:

<script src="https://your-keva-origin/widget/v1/keva-widget.js"
        data-public-id="keva_widget_…"
        data-api-url="https://your-keva-origin"
        async></script>

data-api-url is required, and must be the origin the src points at. Without it the SDK falls back to production, so a widget installed from a preview would send its visitors' conversations to the wrong deployment.

The site's address must be in that installation's allowed origins, exactly: no path, query, fragment, or wildcard.

Strict content security policy

The widget does not require unsafe-inline. If the host page uses a CSP that requires a style nonce, put the response's nonce on the embed script:

<script src="https://your-keva-origin/widget/v1/keva-widget.js"
        data-public-id="keva_widget_…"
        data-api-url="https://your-keva-origin"
        nonce="YOUR_RESPONSE_NONCE"
        async></script>

The widget copies that nonce to its shadow stylesheet. The policy must allow the Keva script and API origin, and its style-src must allow the same response nonce. Keep the nonce generated per response; do not replace this contract with unsafe-inline. The widget's launcher, panel, form, media controls, saved brand colour, and bottom-left position are all rendered from that authorized stylesheet.

When using window.Keva.init, pass the same response nonce as nonce in the options object (see the SDK reference).

Integrity

The snippet has no integrity attribute. The bundle changes with every release, so a content hash pinned in page markup would make every installed site fail to load the widget until its owner edited their site — the opposite of what an integrity attribute is for. Integrity is checked on Keva's side instead: the published file is checked after each deploy and compared with the bundle built from source.

The published path is /widget/v1/, and it is served with Cache-Control: public, max-age=300. It is deliberately not private, no-store — a customer's visitors load it cross-origin, and no authority is involved, so no authentication runs on it.

What must be ready before availability

  1. Apply the supervised widget identity migration and confirm it completes correctly.
  2. Check the published bundle after each deploy, as described above.
  3. Create one clearly labelled Keva-owned fixture installation.
  4. Test exact-origin success and missing, sibling, and unlisted-origin denial.
  5. Test chat, structured form, follow-up, stream, revocation, expiry, and idempotent retry behavior.
  6. Check tenant, workspace, session, conversation, message, attachment, and outbox records separately.

A successful build or HTTP request alone does not make the widget ready for customers.