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

# Identify a visitor

> Link an anonymous visitor to a known user when they sign in.

Call this when a visitor signs in. Send the anonymous ID their events used before signing in, and your user ID for them.

```json theme={null}
{
  "anonymous_id": "aid_7f3c2b91e0",
  "user_id": "user-123"
}
```

Events still recorded under the anonymous ID move onto the user, and the user's profile is rebuilt with them. What someone browsed before signing in then shapes their recommendations, on that device and on every other device where they sign in. After the call, send `user_id` for that person on later events and recommendation requests.

The JavaScript SDK calls this for you from `identify(userId)`. See [Identity](https://docs.neuronsearchlab.com/integrate/identity.md) for the full sign-in and sign-out flow.

## What moves

* Only events still recorded under the anonymous ID move. An event moves once.
* Events older than the workspace's retention period stay where they are, as do events beyond the newest 5,000.
* The anonymous ID stays on each event, so **Data → Users** can show which device it came from.

## When nothing moves

A refused link still returns `200`, with `linked: false` and a `reason`:

| `reason` | Meaning |
| - | - |
| `linked_to_other_user` | The anonymous ID is already linked to someone else, for example on a shared device. Call `reset()` in the SDK, or start a new anonymous ID, when a user signs out. |
| `erased` | One of the two IDs was erased at a user's request. |
| `same_id` | The anonymous ID and the user ID are the same value. |

Calling it again for the same pair is safe. It returns `already_linked` and moves anything sent anonymously since the last call.


## OpenAPI

````yaml api-reference/openapi.json POST /v1/identify
openapi: 3.0.3
info:
  title: NeuronSearchLab Core API
  version: 1.0.0
  description: >-
    Versioned data-plane API for OAuth token exchange, catalog item ingestion,
    user event ingestion, and recommendation serving.
  license:
    name: Proprietary
    url: https://neuronsearchlab.com
servers:
  - url: https://api.neuronsearchlab.com
    description: Core API
security:
  - oauth2: []
tags:
  - name: Authentication
    description: OAuth 2.0 client credentials token exchange.
  - name: Items
    description: Catalog item ingestion, lookup, update, deletion, and pagination.
  - name: Events
    description: User interaction event ingestion, lookup, and pagination.
  - name: Identity
    description: Link anonymous visitors to known users.
  - name: Recommendations
    description: >-
      Personalized recommendation serving, request-scoped filtering, and
      auto-section generation.
  - name: Search
    description: Query-driven catalogue search and complementary recommendations.
paths:
  /v1/identify:
    post:
      tags:
        - Identity
      summary: Identify a visitor
      description: >-
        Link an anonymous visitor to a known user when they sign in. Events
        still recorded under the anonymous ID move onto the user, so what they
        did before signing in shapes their recommendations on every device they
        use. Call it each time a visitor signs in on a device; repeated calls
        are safe.
      operationId: identify
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IdentifyPayload'
            examples:
              login:
                summary: A visitor signs in
                value:
                  anonymous_id: aid_7f3c2b91e0
                  user_id: user-123
                  source: login
      responses:
        '200':
          description: >-
            Link result. A refused link is still a 200 with `linked: false` and
            a `reason`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IdentifyResult'
              examples:
                linked:
                  value:
                    object: identify
                    anonymous_id: aid_7f3c2b91e0
                    user_id: user-123
                    linked: true
                    events_moved: 12
                    reason: linked
                    embedding_refresh:
                      enqueued: true
                sharedDevice:
                  value:
                    object: identify
                    anonymous_id: aid_7f3c2b91e0
                    user_id: user-456
                    linked: false
                    events_moved: 0
                    reason: linked_to_other_user
                    embedding_refresh:
                      enqueued: false
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '403':
          $ref: '#/components/responses/Error403'
        '500':
          $ref: '#/components/responses/Error500'
      security:
        - oauth2:
            - neuronsearchlab-api/write
components:
  schemas:
    IdentifyPayload:
      type: object
      required:
        - anonymous_id
        - user_id
      description: >-
        Links an anonymous visitor to a known user. `anonymousId` and `userId`
        are accepted as aliases.
      properties:
        anonymous_id:
          type: string
          maxLength: 255
          description: >-
            The anonymous ID the visitor's events were sent with before they
            signed in.
          example: aid_7f3c2b91e0
        user_id:
          oneOf:
            - type: string
              maxLength: 255
            - type: integer
          description: >-
            Your stable user ID for the person who signed in. Use the same value
            for later events and recommendations.
          example: user-123
        source:
          type: string
          maxLength: 64
          description: >-
            Optional label for what made the link, shown in the console. The
            JavaScript SDK sends `js-sdk`.
          example: checkout-login
    IdentifyResult:
      type: object
      properties:
        object:
          type: string
          enum:
            - identify
        anonymous_id:
          type: string
        user_id:
          type: string
        linked:
          type: boolean
          description: True when the anonymous ID is now linked to this user.
        events_moved:
          type: integer
          description: >-
            Earlier events moved from the anonymous ID onto the user by this
            call.
        reason:
          type: string
          enum:
            - linked
            - already_linked
            - linked_to_other_user
            - same_id
            - erased
          description: >-
            `linked`: first link. `already_linked`: linked to this user before;
            any events sent anonymously since were moved.
            `linked_to_other_user`: the anonymous ID belongs to someone else
            (for example a shared device), nothing moved. `same_id`: the two IDs
            are equal. `erased`: one of the IDs was erased, nothing moved.
        embedding_refresh:
          type: object
          properties:
            enqueued:
              type: boolean
          description: Whether the user's profile is being rebuilt with the moved events.
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - type
            - code
            - message
          properties:
            type:
              type: string
              enum:
                - invalid_request_error
                - authentication_error
                - permission_error
                - not_found_error
                - conflict_error
                - rate_limit_error
                - api_error
            code:
              type: string
            message:
              type: string
            details: {}
            request_id:
              type: string
              format: uuid
          additionalProperties: true
  responses:
    Error400:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            validation:
              $ref: '#/components/examples/ErrorValidation'
    Error401:
      description: Unauthenticated
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            unauthorized:
              $ref: '#/components/examples/ErrorUnauthorized'
    Error403:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Error500:
      description: Server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  examples:
    ErrorValidation:
      summary: Validation error
      value:
        error:
          type: invalid_request_error
          code: validation_error
          message: Validation error
          details:
            fieldErrors:
              name:
                - Required
    ErrorUnauthorized:
      summary: Unauthorized
      value:
        error:
          type: authentication_error
          code: unauthorized_no_client_id_in_jwt
          message: 'Unauthorized: No client ID in JWT'
  securitySchemes:
    oauth2:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://auth.neuronsearchlab.com/oauth2/token
          scopes:
            neuronsearchlab-api/read: Read recommendations, items, and events.
            neuronsearchlab-api/write: Create, update, and delete items; submit events.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.