Skip to main content
By default, the chat widget treats every session as anonymous. If a user is already logged into your app, you can tell the widget who they are. When a verified identity is passed, the AI agent:
  • Skips asking the user to confirm their email address
  • Uses the authenticated email automatically when escalating to a human agent
  • Has access to the user’s identity for the duration of the session
Never compute the HMAC on the client side. The secret key must stay on your server. Anyone who can read your client-side code or network requests can replay a user identity — the server-side signature is the only thing that prevents this.

How it works

  1. Your server computes HMAC-SHA256(secret, userEmail) using your widget secret.
  2. You pass the email and the hash to the embed script as data-* attributes.
  3. The widget’s iframe URL carries those values as query params.
  4. Layerup’s server verifies the hash using the same secret before trusting the email.
If the hash doesn’t match, the email is silently discarded and the session proceeds as anonymous.

Setup

1. Get your widget secret

Open your Chat Widget integration in the Layerup dashboard. In the Identity Verification section, click Generate to create a secret. Copy it and store it as an environment variable on your server.
Rotate the secret immediately in the dashboard if it is ever exposed. All existing authenticated sessions will become anonymous until users reload.

2. Compute the hash on your server

const crypto = require('crypto');

const hash = crypto
  .createHmac('sha256', process.env.LAYERUP_WIDGET_SECRET)
  .update(userEmail)
  .digest('hex');

3. Pass the values to the embed snippet

Add data-user-email and data-user-hash attributes to the script tag. These are rendered server-side into your HTML — they must never be hard-coded or sourced from client storage.
<!-- Rendered server-side with values from your backend -->
<script
  src="https://us.uselayerup.com/widget-loader.js"
  data-widget-key="YOUR_WIDGET_ID"
  data-user-email="<%= current_user.email %>"
  data-user-hash="<%= layerup_identity_hash(current_user.email) %>">
</script>

4. Mobile webview

For native apps, append the parameters to the webview URL. Compute the hash server-side and inject it into the URL before opening the webview — do not compute it in the app.
https://us.uselayerup.com/widget/YOUR_WIDGET_ID?ue=user%40example.com&uh=COMPUTED_HASH
// hash and email come from your API response, not client-side computation
let urlString = "https://us.uselayerup.com/widget/\(widgetId)?ue=\(encodedEmail)&uh=\(hash)"
let url = URL(string: urlString)!
webView.load(URLRequest(url: url))

Verification flow

Layerup uses a constant-time comparison (timingSafeEqual) to prevent timing attacks. An invalid hash produces no error — the session continues as anonymous.

What changes for verified users

Email confirmation skipped

The AI agent won’t ask the user to spell out or confirm their email address before escalating to a human agent.

Escalation pre-filled

When the AI creates a support ticket, it uses the authenticated email as the reply-to address automatically.

OTP not required

Users who are already authenticated in your app don’t need to re-verify their identity through an OTP inside the widget.

Session continuity

The authenticated email is attached to the session for its entire duration, across multiple messages.

Security checklist

1

Keep the secret server-side

Store it in an environment variable. Never include it in client JavaScript, mobile app binaries, or version control.
2

Compute the hash per-request

Generate the hash fresh for each page render or API response. Don’t cache hashes in the browser or in cookies.
3

Use HTTPS

The widget URL and all chat API calls require HTTPS. Don’t serve the embed script over HTTP.
4

Rotate on exposure

If you suspect the secret has been leaked, rotate it immediately in the dashboard. Generate a new secret and redeploy.