> ## Documentation Index
> Fetch the complete documentation index at: https://platform.atlan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Add Visitor identity to your agent stack

> Identify who each agent run was for, and see it on every session in Agent Registry — works with any framework, new or already in prod.

# Add Visitor identity to your agent stack

A **Visitor** is the stable identity for whoever an agent run was for — a chat
user, a ticket requester, a calling agent. Identify them once per request and
the same `visitor_id` shows up on every session your agent reports afterward,
regardless of which framework ran it.

<Note>
  **Internal release.** `@atlanai/sdk` and `atlan-ai` are distributed
  org-internal today (GitHub Packages / release artifacts, not npm or PyPI).
  Confirm access with your Atlan contact before wiring this into a
  customer-facing deployment.
</Note>

## 1. Install the tracing SDK

<CodeGroup>
  ```bash Python theme={null}
  # Internal distribution — install the wheel from the atlanai-sdk-python repo
  pip install releases/0.1.0/atlan_ai-0.1.0-py3-none-any.whl
  ```

  ```bash TypeScript theme={null}
  # .npmrc: @atlanai:registry=https://npm.pkg.github.com
  npm install @atlanai/sdk
  ```
</CodeGroup>

## 2. Initialize the client once at startup

<CodeGroup>
  ```python Python theme={null}
  import atlan_ai

  client = atlan_ai.init(
      service_name="support-rover",   # your agent's name
      api_key="...",                  # or env ATLAN_API_KEY
      workspace_id="...",             # or env ATLAN_WORKSPACE_ID
  )
  ```

  ```typescript TypeScript theme={null}
  import * as atlan from "@atlanai/sdk";

  const client = atlan.init({
    serviceName: "support-rover",
    apiKey: process.env.ATLAN_API_KEY,
    workspaceId: process.env.ATLAN_WORKSPACE_ID,
  });
  ```
</CodeGroup>

## Fresh integration: identify on every new run

For an agent that doesn't call `identify` yet — new or already live, it's the
same one-time code change either way.

**3. Identify the visitor at the start of each request.** Use a stable id
from wherever the request came from — a Slack user id, a ticket requester's
id, a calling agent's handle — not just an email.

<CodeGroup>
  ```python Python theme={null}
  visitor = client.identify(
      identity_source="slack",
      external_id="U0123ABC",
      traits={"name": "Jordan Lee", "email": "jordan@example.com"},
  )
  ```

  ```typescript TypeScript theme={null}
  const visitor = await client.identify({
    identitySource: "slack",
    externalId: "U0123ABC",
    traits: { name: "Jordan Lee", email: "jordan@example.com" },
  });
  ```
</CodeGroup>

`identify` is idempotent on `(identity_source, external_id)` — call it again
on every request and it refreshes the existing profile instead of creating a
duplicate.

**4. Carry the visitor through the run, whatever framework runs it.** Wrap
the call into your agent — LangGraph, CrewAI, the OpenAI Agents SDK, Google
ADK, the Claude Agent SDK, or a plain loop — in the SDK's attribute
propagation. This stamps the visitor id on every span emitted inside,
including third-party instrumentation, without changing how the framework
itself runs:

<CodeGroup>
  ```python Python theme={null}
  from atlan_ai import propagate_attributes

  with propagate_attributes(visitor_id=visitor.id if visitor else None):
      result = my_agent.invoke({"input": user_message})  # LangGraph .invoke,
      # CrewAI .kickoff(), an OpenAI Agents SDK Runner.run(), or your own loop
  ```

  ```typescript TypeScript theme={null}
  await atlan.propagateAttributes({ visitorId: visitor?.id }, async () => {
    const result = await myAgent.invoke({ input: userMessage }); // same idea —
    // whatever your framework's run/invoke/kickoff call is
  });
  ```
</CodeGroup>

**5. Verify it in Agent Registry.** Open the agent's profile, select
**Sessions**, find the session the run above just reported, and confirm its
visitor fields — id, name, email, link status — match what you sent in step 3.

## Backfill: an agent already running in prod

Your agent already has sessions and traces in Agent Registry from before you
added `identify`. "Backfill" here means two different things — they are not
the same operation.

**Pre-seed the Visitor directory from your own user list.** If you already
have an export of known users (Zendesk requesters, Slack members, CRM
contacts), identify them all up front instead of waiting for each one's next
request — the same `identify` call as above, looped over your existing list:

<CodeGroup>
  ```python Python theme={null}
  known_users = [
      {"external_id": "zendesk_1001", "name": "Priya Shah", "email": "priya@example.com"},
      {"external_id": "zendesk_1002", "name": "Alex Kim", "email": "alex@example.com"},
      # ... however you exported these from Zendesk, Salesforce, or your CRM
  ]

  for user in known_users:
      client.identify(
          identity_source="zendesk",
          external_id=user["external_id"],
          traits={"name": user["name"], "email": user["email"]},
      )
  ```

  ```typescript TypeScript theme={null}
  const knownUsers = [
    { externalId: "zendesk_1001", name: "Priya Shah", email: "priya@example.com" },
    { externalId: "zendesk_1002", name: "Alex Kim", email: "alex@example.com" },
    // ... however you exported these from Zendesk, Salesforce, or your CRM
  ];

  for (const user of knownUsers) {
    await client.identify({
      identitySource: "zendesk",
      externalId: user.externalId,
      traits: { name: user.name, email: user.email },
    });
  }
  ```
</CodeGroup>

Then add the two-line change from steps 3–4 above to the agent's request
handler so every run **from now on** carries the link. Pre-seeding just means
the directory match (`link_status`) is already resolved the first time a
known user's id comes through, instead of resolving cold on their next visit.

<Warning>
  **This does not relink sessions or traces you already reported.** Sessions
  are create-only in Agent Registry — a session created before you called
  `identify` keeps whatever visitor snapshot it was created with (typically
  none), permanently. Identifying a visitor today does not retroactively
  attach them to yesterday's sessions or traces; the link only applies to
  runs reported **after** this point. There is no supported bulk-relink
  operation for historical sessions today — if that matters for your
  rollout, confirm the current state with your Atlan contact before assuming
  it's covered.
</Warning>

<Card title="Agent API reference" icon="code" href="/developers/api-reference">
  Browse the session and visitor operations.
</Card>
