# Join backend events to a visit (https://www.getfounderhq.com/docs/analytics/recipes/session-stitching)

Your server never sees the browser, so an event it sends has no visit
attached. In a person's activity it sits on its own, away from the pages
that led to it. Pass the session id along with the request and the two
join up. About 10 minutes.

<Callout type="info" title="Before you start">
You need the web SDK running on your site and the Node SDK on your server.
See [Getting started](/analytics/getting-started).
</Callout>

## What this fixes

A checkout is one story told by two systems. The browser records the pages
and the click; your server records the charge. Without the session id, the
charge is filed as unrelated activity and the visit looks abandoned.

## 1. Send the header from the browser

Turn on `tracingHeaders`. The SDK then adds `x-founderhq-session-id` to
your own API calls:

```ts
founderhq.init("fhq_pk_...", { tracingHeaders: true });
```

That covers requests to the page's own origin. If your API is on another
host, list it, and allow the header in that host's CORS policy:

```ts
founderhq.init("fhq_pk_...", {
  tracingHeaders: ["https://api.example.com"],
});
```

Prefer to do it by hand? Read the value and set the header yourself:

```ts
const sessionId = founderhq.getSessionId();
await fetch("/api/checkout", {
  method: "POST",
  headers: sessionId ? { "x-founderhq-session-id": sessionId } : {},
});
```

## 2. Read it on the server

```ts
events.capture({
  contact: { externalId: user.id },
  event: "subscription.upgraded",
  properties: { plan: "growth" },
  sessionId: request.headers.get("x-founderhq-session-id"),
});
```

A missing or malformed value is dropped, and the event still lands. Session
stitching is a nicety; it never costs you the fact itself.

## When to leave it out

Omit `sessionId` for work no visit caused: a nightly job, a queue worker, a
webhook from your payment provider. Those events belong outside a visit,
and forcing them into one would misreport it.

A late arrival is safe. A job that finishes an hour after the person left
joins their visit without stretching how long the visit lasted, because a
visit's shape is read from what the browser saw.

## Two rules worth keeping

Send the session id only. Never send a user id in a header and trust it:
anyone can forge a header, and your server already knows who the caller is.

Treat the session id as a grouping key, not a secret. It says which visit
an event belongs to, and nothing more.

## Next

- [Node SDK](/analytics/sdks/node)
- [Web SDK](/analytics/sdks/web)
