User identity lets you connect chat conversations with your application’s user accounts. When you identify a user, their conversations become linked to their profile, forms can be pre-filled with known data, and the agent can personalize responses.
Quick Start
Identify a user when they log in:
ansa.identify({
userId: "user_abc123",
userMetadata: {
name: "Jane Smith",
email: "[email protected]",
plan: "pro"
}
});
Clear identity when they log out:
Identity Object
The identity object has two parts:
interface Identity {
/** Your internal user ID */
userId?: string;
/** Additional user properties */
userMetadata?: Record<string, unknown>;
}
| Property | Type | Description |
|---|
userId | string | Your internal user identifier. Should be stable and unique. |
userMetadata | object | Key-value pairs of user attributes |
User ID
The userId should be your internal identifier for the user:
// Good - stable internal IDs
ansa.identify({ userId: "user_abc123" });
ansa.identify({ userId: "550e8400-e29b-41d4-a716-446655440000" });
ansa.identify({ userId: "12345" });
// Avoid - unstable or sensitive
ansa.identify({ userId: "[email protected]" }); // Use metadata for email
ansa.identify({ userId: "session_xyz" }); // Sessions change
Pass any properties that help personalize the experience:
ansa.identify({
userId: "user_123",
userMetadata: {
// Contact info
name: "Jane Smith",
email: "[email protected]",
phone: "+1-555-123-4567",
// Account info
plan: "enterprise",
role: "admin",
company: "Acme Inc",
// Dates
signupDate: "2024-01-15",
lastLoginDate: "2024-12-20",
// Usage
totalOrders: 47,
lifetimeValue: 4999.99,
// Preferences
timezone: "America/New_York",
language: "en",
// Custom attributes
accountManager: "Bob Johnson",
industry: "Technology"
}
});
How Identity Is Used
1. Conversation Linking
Conversations are linked to the user ID, allowing:
- History continuity — Users see their past conversations across devices
- Agent context — The agent knows who they’re talking to
- Analytics — Track conversations per user in your dashboard
Forms automatically use metadata to pre-fill fields when the field name exactly matches a key in userMetadata:
// After identifying with email
ansa.identify({
userId: "user_123",
userMetadata: {
email: "[email protected]",
name: "Jane Smith",
company: "Acme Inc"
}
});
// This form will have fields pre-filled
ansa.showForm({
fields: [
{ name: "email", label: "Email", type: "email" }, // → [email protected]
{ name: "name", label: "Name", type: "text" }, // → Jane Smith
{ name: "company", label: "Company", type: "text" } // → Acme Inc
]
});
Field names must exactly match the keys in userMetadata. For example, a field named user_email will only be pre-filled if you have userMetadata.user_email, not userMetadata.email.
3. Agent Personalization
The agent receives user metadata and can use it in responses:
User: What's my current plan?
Agent: Hi Jane! You're on the Enterprise plan with Acme Inc.
You've been with us since January 2024.
For security, sensitive fields are automatically excluded from the agent’s context. Fields containing tokens, passwords, secrets, API keys, or credentials are filtered out. See Personalized Responses for details.
Form schema providers receive user context:
ansa.registerFormSchema({
"support_ticket": async (args, user) => {
// user.userId = "user_123"
// user.userMetadata = { name: "Jane", email: "...", plan: "enterprise" }
return {
fields: [
{
name: "email",
label: "Email",
type: "email",
defaultValue: user.userMetadata?.email,
disabled: true // Lock the field since we know it
},
{
name: "priority",
label: "Priority",
type: "select",
// Enterprise users get priority options
options: user.userMetadata?.plan === "enterprise"
? [
{ label: "Critical", value: "critical" },
{ label: "High", value: "high" },
{ label: "Normal", value: "normal" }
]
: [
{ label: "High", value: "high" },
{ label: "Normal", value: "normal" },
{ label: "Low", value: "low" }
]
}
]
};
}
});
Identity data can be passed to HTTP tools for authenticated API calls. This is useful when your tools need to access user-specific data from your backend.
// Identify with an auth token
ansa.identify({
userId: "user_123",
userMetadata: {
authToken: "eyJhbGciOiJIUzI1NiIs...", // User's JWT
email: "[email protected]"
}
});
Then configure your HTTP tool to use the token:
{
"name": "get_my_orders",
"description": "Get the user's recent orders",
"httpUrl": "https://api.yourstore.com/users/{{userId}}/orders",
"httpMethod": "GET",
"httpHeaders": {
"Authorization": "Bearer {{userMetadata.authToken}}"
}
}
The {{userId}} and {{userMetadata.path}} placeholders are replaced with the user’s identity data at runtime.
6. Personalized Responses
The agent receives sanitized user context to personalize its responses. This enables greetings, contextual answers, and tailored recommendations based on user data.
Initial Message Templating
The widget’s initial message supports template variables:
// Agent configuration
{
initialMessage: "Hello {{userMetadata.name}}! How can I help you today?"
}
If the user is identified:
Hello Jane! How can I help you today?
If no identity or the field is missing:
Hello ! How can I help you today?
Use conditional phrasing for optional fields: “Welcome back!” works whether or not you have the user’s name.
Template Syntax
| Template | Description | Example Output |
|---|
{{userId}} | The user’s ID | user_123 |
{{userMetadata.name}} | Top-level metadata field | Jane Smith |
{{userMetadata.company.name}} | Nested field (dot notation) | Acme Inc |
If a field is undefined, it renders as an empty string.
Security: Excluded Fields
To protect sensitive data, certain fields are automatically excluded from the agent’s context. Fields with keys matching these patterns (case-insensitive) are filtered:
token
secret
password
apikey / api_key
accesstoken / access_token
refreshtoken / refresh_token
auth
credential
private
// What you pass to identify()
ansa.identify({
userId: "user_123",
userMetadata: {
name: "Jane Smith",
email: "[email protected]",
authToken: "eyJhbGciOiJIUzI1NiIs...", // Contains "auth" + "token"
apiKey: "sk-1234567890", // Contains "apikey"
plan: "enterprise"
}
});
// What the agent sees
{
userId: "user_123",
userMetadata: {
name: "Jane Smith",
email: "[email protected]",
plan: "enterprise"
}
}
Sensitive fields are only filtered from the agent’s LLM context. They are still available for HTTP tool substitution (see section 5) and are sent to your backend.
Implementation Patterns
On Login
async function onLoginSuccess(authResult) {
// Fetch user profile from your API
const user = await fetch("/api/me", {
headers: { Authorization: `Bearer ${authResult.token}` }
}).then(r => r.json());
// Identify in Ansa
ansa.identify({
userId: user.id,
userMetadata: {
name: user.name,
email: user.email,
plan: user.subscription?.plan,
company: user.company?.name,
role: user.role
}
});
}
On Logout
function logout() {
// Clear Ansa identity
ansa.resetUser();
// Rest of logout logic
auth.signOut();
router.push("/login");
}
React Context
import { createContext, useContext, useEffect } from "react";
import { useAuth } from "./auth";
const AnsaContext = createContext(null);
export function AnsaProvider({ children }) {
const { user, isAuthenticated } = useAuth();
useEffect(() => {
if (isAuthenticated && user) {
window.ansa?.identify({
userId: user.id,
userMetadata: {
name: user.name,
email: user.email,
plan: user.plan
}
});
} else {
window.ansa?.resetUser();
}
}, [isAuthenticated, user]);
return (
<AnsaContext.Provider value={null}>
{children}
</AnsaContext.Provider>
);
}
Next.js App Router
// app/providers.tsx
"use client";
import { useEffect } from "react";
import { useSession } from "next-auth/react";
export function AnsaIdentityProvider({ children }) {
const { data: session, status } = useSession();
useEffect(() => {
if (status === "authenticated" && session?.user) {
window.ansa?.identify({
userId: session.user.id,
userMetadata: {
name: session.user.name,
email: session.user.email,
image: session.user.image
}
});
} else if (status === "unauthenticated") {
window.ansa?.resetUser();
}
}, [session, status]);
return children;
}
Vue Composition API
<script setup>
import { watch } from 'vue';
import { useUserStore } from '@/stores/user';
const userStore = useUserStore();
watch(
() => userStore.isLoggedIn,
(isLoggedIn) => {
if (isLoggedIn) {
window.ansa?.identify({
userId: userStore.user.id,
userMetadata: {
name: userStore.user.name,
email: userStore.user.email,
plan: userStore.user.plan
}
});
} else {
window.ansa?.resetUser();
}
},
{ immediate: true }
);
</script>
Visitors vs Users
Ansa tracks two types of identities:
| Type | Identifier | Persistence | Use Case |
|---|
| Visitor | visitorId | LocalStorage | Anonymous users, stored per browser |
| User | userId | Your identity | Logged-in users, cross-device |
Getting Visitor ID
const visitorId = ansa.getVisitorId();
// "v_1703347200000_abc123def"
Visitor IDs are:
- Generated automatically on first visit
- Stored in localStorage
- Persisted until cleared
- Unique per browser/device
Linking Visitors to Users
When a visitor logs in, their anonymous conversations become linked to their user account:
// Before login: conversations stored under visitorId
// User browses, asks questions...
// On login
ansa.identify({
userId: "user_123",
userMetadata: { name: "Jane" }
});
// After login: previous conversations now linked to user_123
// Future conversations also linked to user_123
Privacy Considerations
Only pass data that’s necessary for personalization. Avoid sensitive information like passwords, SSNs, or financial details.
What to Include
- Name, email (for personalization)
- Account type, plan (for context)
- Preferences (for customization)
- Non-sensitive IDs
What to Avoid
- Passwords or secrets
- Full credit card numbers
- Social security numbers
- Health information
- Any data you wouldn’t want logged
GDPR Compliance
If a user requests data deletion:
- Use the API to delete their conversations
- Their identity data is automatically cleared
- Consider calling
clearIdentity() to clear client state
SDK Usage
The SDK provides the same identity functions:
import { identify, clearIdentity } from "@ansa/sdk";
// Identify
identify({
userId: "user_123",
userMetadata: {
name: "Jane Smith",
email: "[email protected]"
}
});
// Clear identity
clearIdentity();
Debugging
Check the current identity state in the console:
// Identity is sent with each request
// Check Network tab for X-Ansa-User-Id header
// Or listen for identity events
window.addEventListener("message", (e) => {
if (e.data.type === "ansa:identityUpdate") {
console.log("Identity updated:", e.data.data);
}
});
Best Practices
Identify early, update often. Call identify() as soon as you know who the user is, and update metadata when it changes.
- Use stable IDs — Don’t use session IDs or emails as
userId
- Keep metadata current — Update when user profile changes
- Reset on logout — Always call
resetUser() when signing out
- Be selective — Only pass metadata you’ll actually use
- Match field names — Use standard names for automatic form pre-fill
Next Steps