Identify users
Attach signed-in user context to SDK submissions.
Use this when your app already knows who the user is and you want feedback attributed to them.
How it works
Call identify() on the client (or useIdentify() in React) after login. The SDK stores that context and includes it on the next submit() call.
sequenceDiagram
participant App as Your app
participant SDK as @landedso/sdk
participant API as Landed API
App->>SDK: identify({ id, email, name })
App->>SDK: submit({ text })
SDK->>API: POST /submissions { user: { id, email, ... }, text }
API->>API: Resolve identity, create or continue a conversationHeadless client
import { LandedClient } from "@landedso/sdk";
const landed = LandedClient.create({ publishableKey: "wk_pub_..." });
landed.identify({
id: "user_123",
email: "jane@example.com",
firstName: "Jane",
lastName: "Doe",
avatar: "https://example.com/avatar.jpg",
});Clear identity without rotating the visitor session:
landed.identify(null);Log out to rotate the visitor token and leave prior conversations attached:
await landed.logout();React hooks
import { useEffect } from "react";
import { useIdentify } from "@landedso/sdk/react";
function AuthSync({ user }: { user: User | null }) {
const identify = useIdentify();
useEffect(() => {
if (user) {
identify({
id: user.id,
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
});
} else {
identify(null);
}
}, [user, identify]);
return null;
}Fields
| Field | Required | Notes |
|---|---|---|
id | Yes | Unique user id from your system |
email | Yes | Used to attribute the submission |
name | No | Full display name |
firstName / lastName | No | Alternative to name |
avatar | No | Profile image URL |
organization | No | Explicit organization with externalId and name. Never inferred from email. |
payment | No | Display-only billing summary on the identity (B2C) or on organization.payment (B2B), not both. |
Without identify
If you do not call identify(), pass guest details on submit:
await landed.submit({
text: "Feature request",
newUser: {
email: "guest@example.com",
name: "Guest User",
},
});Or submit anonymously when your workspace allows it:
await landed.submit({ text: "Anonymous feedback" });Anonymous submissions require allowAnonymous: true in your widget settings.
What Landed does on submit
When an identified user submits feedback, Landed:
- Matches the host product id within the workspace, or joins a single normalized email
- Creates a workspace identity when the email is new
- Creates or continues a conversation and appends a customer-visible conversation message from the customer
Two host IDs stay separate people even when their emails match. A conflicting email on an existing host-ID match leaves that identity unchanged.
Security note
Because identification trusts the browser, a motivated user could impersonate another id/email via devtools. That is acceptable for many products today.