Landed
Custom UI SDK

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 conversation

Headless 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

FieldRequiredNotes
idYesUnique user id from your system
emailYesUsed to attribute the submission
nameNoFull display name
firstName / lastNameNoAlternative to name
avatarNoProfile image URL
organizationNoExplicit organization with externalId and name. Never inferred from email.
paymentNoDisplay-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:

  1. Matches the host product id within the workspace, or joins a single normalized email
  2. Creates a workspace identity when the email is new
  3. 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.

Next step