Sessions & Prefill
The visitor session lifecycle, identify and shutdown, unverified prefill, and bot protection
After the widget loads, it opens a session for the visitor. This page covers how that session works, how to switch or clear identity, how prefill differs from identity, and Turnstile bot protection.
Session Lifecycle
On mount, the widget resolves any VisitorIdentity you passed, then performs a handshake:
- Identity present. An identified handshake. The proof is verified and a verified session is issued.
- No identity. An anonymous handshake. A session is still issued. The visitor can read content, react, and browse.
Every visitor, anonymous or identified, gets a chat at handshake. The session is a token the widget sends on every request. It carries the contact id, an opaque visitor id, and whether the visitor is verified.
Sticky Visitor ID
The widget mints a random visitor id and stores it in localStorage, keyed by your public key. It persists across reloads. A returning visitor on the same browser lands back in the same conversation until shutdown clears it.
localStorage key | Purpose |
|---|---|
wexio:visitor-id:<pk> | The sticky visitor id. |
wexio:visitor-session:<pk> | The identified session blob (token + expiry). |
wexio:prechat-submitted:<pk> | Whether the prechat form was submitted. |
Silent Renewal
Identified sessions renew automatically ~30 seconds before expiry, and on tab focus, reusing the same visitor id for continuity. You don't refresh tokens yourself. Keep handing the widget a valid proof when it asks, for example by minting a fresh JWT on each page load.
Identify and Shutdown
To switch identity at runtime, or clear it, use the call for your embed:
// React - change the user prop
<WexioWidget user={{ jwt: newJwt, name: "Grace" }} /> // log in / switch
<WexioWidget user={undefined} /> // log out// Web Component
el.identify({ jwt: newJwt, name: "Grace" }); // log in
el.identify(null); // log out
// Script loader
window.Wexio("identify", { jwt: newJwt, name: "Grace" });
window.Wexio("shutdown"); // log outWith the script loader, call window.Wexio("shutdown") when a user logs out of your app, especially on shared computers. It forgets the sticky visitor id, clears the stored session and the prechat flag, wipes what the widget holds in memory, and starts a fresh anonymous session, so the next user can't inherit the previous user's conversation. identify(null) and an unset user prop log the identity out, but only shutdown does this wipe.
Prefill Is Not Identity
Prefill pre-populates the prechat form with name / email / phone. It is a convenience. It is never verified, never unlocks sensitive data, and never marks the visitor as identified.
| Embed | How to prefill |
|---|---|
| React | No prefill prop. Pass a verified user, or use the Web Component or script loader. |
| Web Component, Vue, Angular | prefill-name, prefill-email, prefill-phone attributes. |
| Script loader | window.wexioSettings.prefill = {…}, or Wexio("prefill", {…}), or wx_name / wx_email / wx_phone URL params. |
URL params (?wx_email=…) leak via history, logs, and the Referer header. For anything containing PII, use wexioSettings.prefill or props.
Require Sign-In
When Require sign-in is enabled, an anonymous visitor still gets a session and can browse Home, Help, and News. The messenger is gated. The backend refuses their outbound message and a sign-in panel replaces the composer.
To unlock messaging, identify the visitor or enable Google or passkey sign-in.
Bot Protection (Turnstile)
To turn it on, open Bot protection in the Widget settings, turn on Bot protection, and enter the Turnstile site key and Turnstile secret key. See Bot Protection. Turnstile is recommended for high-traffic public widgets. When on:
- The widget lazy-loads the Turnstile script and runs an interaction-only challenge anchored to the launcher corner.
- A token gates the handshake and prechat submission.
- On failure, a popup above the launcher says Couldn't verify your browser and offers Try again.
Your page does nothing. The widget reads the site key from the backend config, and the page doesn't inject it.
Server-Side Trust
For anything sensitive, such as returning PII or calling billing APIs from a flow or the AI assistant, hard-check verification server-side and key on the verified user id. Never trust the client or the model.
The read-only web_verified system field reflects verification and is safe for flows to branch on. The backend sets it only on a real verification, so it can't be forged. A tool that exposes sensitive data must still verify on the server.
Related
- Signed JWT - mint the proof the widget verifies.
- Google and passkey sign-in - let visitors sign themselves in.
- Authentication - compare the identity methods.
- Visitor Sign-In - the Require sign-in setting.