---
title: "Send events from your server for the right person"
description: "Forward the browser's anonymous and session ids to your server, so server events join the same person and visit."
canonical: "https://www.togohq.ai/docs/guides/server-events"
applies_to: "@togohq/sdk-browser 1.x, @togohq/sdk-node 1.x"
updated: "2026-11-03T00:00:00Z"
---

# Send events from your server for the right person

Forward the browser's anonymous and session ids to your server, so server events join the same person and visit.

## Signed-in users: send the same `userId`

When the person is signed in, the server SDK only needs your user id — the one the browser passes
to `identify()`:

```ts
analytics.track('invoice_paid', { amount_bucket: '100-500' }, { userId: user.id });
```

Different ids on the two sides make one user into two people.

## Visitors who have not signed in: forward `anonymousId`

Before sign-in there is no user id. Send the browser's anonymous id with the request, and pass it
on:

```ts
// browser
await fetch('/api/quote', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'x-togo-anonymous-id': analytics.getAnonymousId() ?? '',
    'x-togo-session-id': analytics.getSessionId() ?? '',
  },
  body: JSON.stringify(form),
});
```

```ts
// server
const anonymousId = request.headers.get('x-togo-anonymous-id') || undefined;
const sessionId = request.headers.get('x-togo-session-id') || undefined;

if (anonymousId) {
  analytics.track('quote_requested', { seats_bucket: '10-50' }, { anonymousId, sessionId });
}
```

The header names are yours to choose; Togo never reads them. The getters return `undefined` until
the browser's first event, and while consent is pending or denied, so handle the empty case.

## Never make an id up

An event with neither `userId` nor `anonymousId` is dropped with an error, because nobody could be
credited with it. Do not fill the gap with a random id, a request id or a constant: each would
create a person who does not exist. If the server cannot tell who it is about, skip the event or
send it from the browser instead.

## Join the visit with `sessionId`

`sessionId` is optional. Forwarded from `getSessionId()`, it puts the server event in the same
session as the browser events around it. Without it, the event is still the right person's, but
outside any session.

## Before you return

In a serverless function, `await analytics.flush()` before returning the response, or the events
may never leave ([Node.js and serverless](/docs/node)).
