Skip to content
Widget SDK

Identify Signed-in Visitors

Recognise signed-in visitors: the WordPress plugin, your identity provider, or a token signed on your server.

On this page

Identify Signed-in Visitors#

When a shopper or member is signed in to your site, your chatbot can answer questions only that person should see — “where is my order?”, “what’s on my account?” — without asking them to prove who they are again. Your website tells Gydr who is signed in, in a way only your site can do.

You need this only if a connected plugin looks up personal data (for example WooCommerce order status). A chatbot that only answers general questions works without it.

Pick how your customers sign in#

In the Console, open Settings → Signed-in visitors and press Add sign-in source. It asks one question: “Where do your customers sign in?” Each answer is set up in the same panel, without leaving the page.

Your website
A WordPress site
What you do
Type your site address, install the WordPress plugin and press Connect WordPress.
What you never touch
Code, wp-config.php, script tags, token signing.
What you do
Register the provider in the Console and hand the widget the token your page already holds.
What you never touch
Secrets, token signing, a token endpoint.
What you do
Create a key, sign a short token on your server, and serve it from a same-origin endpoint.
What you never touch
Nothing is hidden — you own the signing code.

A WordPress site#

The Gydr WordPress plugin puts the chat widget on your site and tells Gydr who is signed in. There is no code to edit.

  1. In Console → Settings → Signed-in visitors, press Add sign-in source, choose WordPress or WooCommerce and type your site’s address.
  2. Download the plugin (a zip file), press Open your WordPress upload page, choose the zip, then Install and Activate.
  3. Press Connect WordPress. Your site asks “Connect this site to …?” — press Connect, then Approve on your dashboard. Your site and your dashboard exchange the connection directly: nothing is copied or pasted.

The plugin updates itself through the normal WordPress updater. After the first signed-in chat, the Console shows “Recognised a visitor on” with the date. A plugin such as WooCommerce Storefront only recognises customers from the sign-in sources it trusts; the WordPress site on its store address is ticked for you. For a full WooCommerce walk-through, see WordPress & WooCommerce setup.

The connection code#

If your host blocks outbound requests, or your plugin is older than 1.1.0, use the fallback: in the Console panel open Have an older plugin? Paste a connection code instead. The connection code is one line that starts with gydr1.. It carries your account id, a signing key and the public key of the widget you chose, so the plugin has everything it needs.

The code is shown once. Treat it like a password: paste it only into your WordPress settings, never into a page, a chat or a code repository. If it is lost or leaks, create a new one and remove the old connection.

An identity provider#

If your customers sign in through Auth0, Clerk, Firebase, Supabase, Amazon Cognito, or any provider that signs tokens with RS256 or ES256 and publishes its public keys (a JWKS), Gydr can verify the provider’s own tokens. You keep no secret on your side.

  1. In Console → Settings → Signed-in visitors, add your provider with its issuer, its public keys URL (JWKS) and the audience your tokens carry. If your provider names the user in a different claim, set the optional user-id claim (for example cognito:username).
  2. Gydr fetches the key set live when you save, so a wrong URL is caught straight away.
  3. On your page, hand the widget the token the page already holds:
Gydr.setIdentityTokenProvider(async () => (await auth.getToken()) ?? null)
  • Prefer a token minted with a Gydr-specific audience, so your site’s own API token is not shared with Gydr.
  • Claims the provider adds that are not plain values are ignored. email counts only when the token says email_verified is true.
  • The same limits, sign-out behaviour and tester apply as below; see supplying the token from JavaScript.

An account can have at most 4 connections in total (WordPress sites, providers and keys together).

Sign it yourself#

For a custom site with its own sign-in, your server signs the token. The rest of this page covers that path in detail; the token format, claims and limits also describe what a provider’s tokens must contain (with RS256 or ES256 instead of HS256).

How the token works#

  1. You create an identity key in Console → Settings → Signed-in visitors (Add sign-in source → “Your own sign-in”). The key has an id (the kid, e.g. idk_7Qm2) and a secret. The secret is shown once — store it in your server’s configuration.
  2. When a visitor is signed in, your server signs a small JSON Web Token (JWT, HS256) with that secret, naming the user and your Gydr account.
  3. The widget fetches the token from your site, keeps it in memory, and sends it with each chat message. It never puts it in a URL or in browser storage.
  4. Gydr checks the signature, the account and the expiry. A valid token proves who the visitor is; anything else is treated as a guest.
Sign tokens only on your server. Anyone holding the secret can sign in as any of your users. Never put it in browser JavaScript, never send it to the page, never commit it to a code repository. See Guests & data never to send.

The token#

A standard JWT: a header, a payload of claims, and a signature.

Header
{ "alg": "HS256", "typ": "JWT", "kid": "idk_7Qm2" }
Payload
{
  "sub": "42",
  "aud": "<your Gydr account id>",
  "iat": 1790000000,
  "exp": 1790003600,
  "email": "siti@example.com",
  "email_verified": false,
  "name": "Siti Rahman",
  "attrs": { "crm_id": "c_91" }
}

Claims#

Claim
sub
Required
Yes
What to put in it
Your user id for this person — 1 to 255 printable characters. It must never change for the same person.
Claim
aud
Required
Yes
What to put in it
Your Gydr account id, shown in Console → Settings → Signed-in visitors.
Claim
iat
Required
Yes
What to put in it
When you signed it, in whole Unix seconds. Most JWT libraries add it for you.
Claim
exp
Required
Yes
What to put in it
When it expires, in whole Unix seconds. At most 24 hours after iat; 1 hour is recommended.
Claim
email
Required
No
What to put in it
The person's email address.
Claim
email_verified
Required
No
What to put in it
true ONLY if your site confirmed the person owns that address (for example with a confirmation link). Plugins use the email only when this is true.
Claim
name
Required
No
What to put in it
The person's display name.
Claim
phone_number
Required
No
What to put in it
A phone number, if a plugin needs it.
Claim
attrs
Required
No
What to put in it
An object of extra ids other plugins need, e.g. a CRM id. Plain values only (text, numbers, true/false).

Limits Gydr enforces

  • The whole token is at most 8 KB, with at most 50 claims, each at most 256 characters.
  • Claims are plain values only — text, numbers, true/false — also inside attrs. No lists or nested objects.
  • alg must be HS256 for a website key (RS256 or ES256 for an identity provider). Tokens carrying a crit, jku, jwk, x5u or x5c header are refused.
  • Up to 60 seconds of clock difference is allowed.

Sign the token on your server#

Keep the account id, key id and secret in server configuration (environment variables, a secrets manager).

// npm install jsonwebtoken
import jwt from 'jsonwebtoken';

export function gydrIdentityToken(user) {
  return jwt.sign(
    {
      sub: String(user.id),
      aud: process.env.GYDR_ACCOUNT_ID,
      name: user.name,
      email: user.email,
      email_verified: user.emailVerified === true,
    },
    process.env.GYDR_IDENTITY_SECRET,
    {
      algorithm: 'HS256',
      expiresIn: '1h', // sets exp; iat is added automatically
      header: { kid: process.env.GYDR_IDENTITY_KID },
    },
  );
}

Give the widget a token endpoint (recommended)#

Add one URL on your own site that returns the current visitor’s token, and point the widget at it with data-identity-endpoint. The widget calls it itself — with the visitor’s cookies, never cached — before the first message and again whenever the token is under a minute from expiring.

<script
  src="https://cdn.gydr.ai/widget.js"
  data-api-key="pk_live_YOUR_KEY"
  data-identity-endpoint="/gydr/identity-token"
  async
></script>
  • The endpoint must be on the same site (same origin) as the page. A path like /gydr/identity-token is simplest.
  • Return { "token": null } for a guest. An error status or a network failure changes nothing — the widget keeps what it has and tries again shortly, so a blip never signs anyone out.
  • Never let a page cache or CDN store this response — it belongs to one person.

Or supply the token from JavaScript#

For a single-page app or a site where a plain endpoint doesn’t fit, register a function with Gydr.setIdentityTokenProvider(). Register it from the script tag’s load event so it is in place before the first message. Return the token, or null when nobody is signed in. Throw on errors instead of returning null — null means “signed out” and clears the conversation.

const script = document.createElement('script');
script.src = 'https://cdn.gydr.ai/widget.js';
script.dataset.apiKey = 'pk_live_YOUR_KEY';
script.async = true;
script.addEventListener('load', () => {
  window.Gydr.setIdentityTokenProvider(async () => {
    const res = await fetch('/api/gydr-token', { credentials: 'same-origin', cache: 'no-store' });
    if (!res.ok) throw new Error('token unavailable'); // keeps the current state
    const { token } = await res.json();
    return token; // a string, or null for a guest
  });
});
document.head.appendChild(script);

A site with no way to refresh can pass a fixed token with Gydr.identify({ identityToken }) or the data-identity-token attribute. It stops working when it expires, so prefer the endpoint. All options are listed in the JavaScript API and Data Attributes references.

Sign-out is automatic#

You don’t need to tell the widget when someone signs out. It starts a fresh visitor and a new, empty conversation when:

  • your endpoint or provider returns null;
  • a token was active and now none is supplied;
  • the token names a different person (a different sub).

A conversation that began signed in continues only for that same person — if someone else signs in on the same browser, it is cleared. A signed-in person’s past chats are shown only while they are signed in, and conversations that showed an order are never listed in past chats. Gydr.reset() still clears everything on demand.

Test a token in the Console#

Console → Settings → Signed-in visitors has a token check in each source’s details. Paste a token your server produced; it tells you whether Gydr accepts it and, if not, why (see Troubleshooting). Then open your site signed in, ask the chatbot something personal (“where is my order?”), and ask again signed out.

That is the whole setup

For this path: an identity key, the signing code, the endpoint and one attribute on the script tag. The rest of this page — key rotation and troubleshooting — is reference for later.

Rotate a key without signing anyone out#

An account can have two active keys at once, so you can switch without a gap:

  1. Create a second key in the Console.
  2. Deploy its kid and secret to your server; new tokens are signed with it.
  3. Once the old tokens have expired (1 hour if you follow the recommendation), retire the first key.

A lost secret can’t be shown again — create a new key and retire the old one. If you think a secret leaked, rotate immediately.

Troubleshooting#

Each reason the Console tester reports, and the fix:

Tester says
bad_signature
Why
The token was signed with a different secret, or changed after signing.
Fix
Use the secret for the key named in kid; check nothing trims or re-encodes the token.
Tester says
expired
Why
exp is in the past (beyond the 60-second allowance).
Fix
Sign a fresh token for each request to your endpoint; check your server clock.
Tester says
wrong_audience
Why
aud is not your Gydr account id.
Fix
Copy the account id from Settings → Signed-in visitors.
Tester says
unknown_key
Why
kid is missing, mistyped, or the key was retired.
Fix
Put the active key's id in the header's kid.
Tester says
unknown_issuer
Why
The token's iss is not a registered identity provider.
Fix
Register the provider in Settings → Signed-in visitors with exactly the issuer its tokens carry.
Tester says
jwks_unavailable
Why
The provider's public keys URL (JWKS) could not be fetched.
Fix
Check the URL opens in a browser and the provider is up, then try again.
Tester says
too_many_claims
Why
More than 50 claims.
Fix
Send only what a connected plugin needs.
Tester says
lifetime_too_long
Why
exp is more than 24 hours after iat.
Fix
Use a lifetime of 1 hour.
Tester says
missing_subject
Why
No sub, or it is empty or over 255 characters.
Fix
Set sub to the user's id as text.
Tester says
unsupported_algorithm
Why
alg is not allowed for this connection (for example none, or RS256 on a website key).
Fix
Sign a website key's tokens with HS256; a provider's with RS256 or ES256.
Tester says
invalid_claims
Why
A claim is a list or nested object, or longer than 256 characters.
Fix
Use plain values; put extra ids in attrs as text.
Tester says
too_large
Why
The token is over 8 KB.
Fix
Remove claims no plugin uses.
Tester says
not_yet_valid
Why
iat (or nbf) is more than 60 seconds in the future.
Fix
Fix your server clock (use NTP).
Tester says
forbidden_header
Why
The header carries crit, jku, jwk, x5u or x5c.
Fix
Send only alg, typ and kid in the header.
Tester says
malformed
Why
Not three base64url parts, not JSON, or iat/exp missing or not whole seconds.
Fix
Use a JWT library, or copy the PHP example exactly.

Next: Guests & data never to send · WordPress & WooCommerce setup

Ready to get started?

Create a free account and deploy your first chatbot in minutes.