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

# SDKs overview

> Traceten's SDKs send AI-traffic pageviews and revenue events from the browser or your backend. One browser SDK, three server SDKs (Node, Python, Go), one shared contract.

## What this lets you do

Send the same pageviews and revenue conversions from wherever your code runs: the browser snippet's `window.traceten` global for client-side tracking, or a server SDK for delivery that ad-blockers and privacy browsers cannot strip.

## Pick your SDK

The browser SDK is the right default for most sites. Reach for a server SDK when the snippet cannot run, or when you need delivery that survives ad-blockers.

<CardGroup cols={2}>
  <Card title="Browser (JavaScript)" icon="js" href="/sdks/browser">
    The `window.traceten` global the snippet installs. Pageviews, custom events with revenue,
    `identify`, and consent.
  </Card>

  <Card title="Node.js" icon="node-js" href="/sdks/node">
    `@traceten/sdk-node`. Node 18 or newer.
  </Card>

  <Card title="Python" icon="python" href="/sdks/python">
    `traceten` on PyPI. Python 3.9 or newer.
  </Card>

  <Card title="Go" icon="golang" href="/sdks/go">
    `github.com/traceten/traceten-go`. Go 1.21 or newer.
  </Card>
</CardGroup>

## Browser vs server

|                                                | Browser SDK                                      | Server SDKs                                                                           |
| ---------------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------- |
| Where it runs                                  | The visitor's browser, via the installed snippet | Your backend                                                                          |
| Reaches ad-blocked and privacy-browser traffic | No (client scripts get stripped)                 | Yes                                                                                   |
| Supplies `visitor_id` / `session_id`           | Automatically, from first-party cookies          | You supply them from your request context                                             |
| Best for                                       | Most sites, most events                          | Server-rendered flows, background jobs, webhook handlers, ad-block-resistant delivery |

Many sites run both: the browser SDK for standard client-side tracking, and a server SDK for the conversions that must not be lost.

## The server SDKs share one contract

All three server SDKs (Node, Python, Go) implement the same contract: the same methods, the same defaults, the same batching and retry behavior. Only the naming follows each language's idioms.

Every server SDK exposes three methods that map to the three ingestion endpoints:

| Method      | Endpoint                            | Carries                                      |
| ----------- | ----------------------------------- | -------------------------------------------- |
| `page()`    | `POST {host}/v1/server/events`      | Pageviews and traffic events                 |
| `track()`   | `POST {host}/v1/server/conversions` | Custom and revenue events (the money events) |
| `payment()` | `POST {host}/v1/server/payments`    | Payments from any payment processor          |

`page()` and `track()` buffer the event and return immediately. A background worker batches, retries, and flushes without blocking your request path. You call `flush()` to send everything queued now, and `close()` to flush and stop the background worker on shutdown.

`payment()` is different, and deliberately so. It sends immediately, waits for the answer, and returns it. The [Payment API](/api/payments) is idempotent on the transaction id, and that answer, whether the payment was recorded or was one we already had, is the point of the call. A queue could not hand it back to you. It is also the only method that reports a delivery failure to the caller: a dropped pageview is a dropped pageview, but a dropped payment is missing revenue.

### You supply the visitor id

Because a server SDK runs on your server, there is no Traceten cookie and no DOM. The two identifiers the browser snippet derives client-side, `visitor_id` and `session_id`, do not exist server-side. You supply them from your own request context. The SDK never fabricates a visitor id.

A `visitorId` is either a canonical UUID or the identify-hash form `h:<64-hex>`. It is optional on `page()` and on `payment()`, and required on `track()`, because a conversion cannot be attributed without it. On `payment()` you can supply the customer's email instead, and if you supply neither the payment is recorded as unattributed revenue. The robust way to get these values is `window.traceten.getVisitorId()`/`getSessionId()`, called client-side and forwarded to your backend. They always resolve the current cookie, so they survive you turning cross-subdomain cookies on or off later. If you read the cookies by name instead, the name depends on the site's cookie scope: cross-subdomain cookies are **off by default**, giving plain `_traceten_vid`/`_traceten_sid`; once you confirm a value under **Sites → Settings → Cookies**, it becomes `_traceten_vid_`/`_traceten_sid_` followed by eight characters of your site key. Your install page and Settings show the exact current name. Read that name exactly rather than by prefix: two Traceten sites under one registered domain each set their own cookie, and a prefix match picks whichever the browser lists first.

## Authentication

<Warning>
  **Keys issued before the current release have been revoked and must be replaced.** An SDK still
  configured with an older key will fail to send events. See [re-minting your
  keys](/api/authentication#you-must-re-mint-every-existing-key).
</Warning>

Every server SDK requires an API key. Set it on the constructor (`apiKey` in Node, `api_key` in Python, `WithAPIKey` in Go) and the SDK sends it as `Authorization: Bearer <key>` on every request.

The key is a secret. Keep it on your server: never in client-side code, a mobile app, or a public repository. It is not the same value as `siteId`, which is public and already embedded in every page that runs the snippet.

The server SDKs post to `/v1/server/events`, `/v1/server/conversions` and `/v1/server/payments`, which return `401` without a valid key. `/v1/events` and `/v1/conversions` remain open, because the browser snippet shares them and cannot hold a secret.

Two things the key buys you:

1. Access. The authenticated endpoints reject unauthenticated requests.
2. Your own ingestion quota. Traffic that arrives with a valid key is rate-limited on a bucket tied to that key, separate from the shared per-site bucket. Because `siteId` is public, anyone who can read your page source can send events under it; with a key, that traffic cannot exhaust your allowance and 429 the conversion calls that carry your revenue data.

Create keys in the dashboard under Settings, API keys. Each SDK validates the key's shape when you construct the client and fails immediately if it is missing or malformed, rather than letting a broken integration buffer and drop events silently.

The key must carry the **Send events** permission (`ingest:write`). New keys are created read-only by default, so tick that box when you create one, or the API will reject your calls. The key created automatically with a new site already has it. See [permissions](/api/authentication#permissions).

To rotate a key: create the new one, deploy it, then revoke the old one. Revocation normally takes effect at the edge within about a minute. If our
database is unreachable at that moment, an edge location that was already using
the key may keep honouring it for up to about fifteen minutes more, so that a
database blip cannot silently drop your events.

The same [API keys](/api/authentication) also authenticate the account-level data deletion and access endpoints.

## Privacy

Traceten is privacy-first, and server-side sending puts that in your hands. Two rules carry across every server SDK:

* **Keep `visitorId` opaque.** Use a random first-party id or a salted hash you control. Never pass a bare `sha256(email)` or any hash of an email or phone number, which is re-identifiable PII. The SDK enforces the shape (UUID or `h:<64-hex>`) but cannot see what you hashed.
* **Keep `properties` opaque.** Use ids and enums such as `{ "plan": "pro" }`. Do not put emails, names, or phone numbers in `properties`.

The browser SDK enforces the same rules and redacts PII patterns from event properties automatically. See the [browser SDK reference](/sdks/browser#property-rules).

## Next

* [Browser SDK reference](/sdks/browser)
* [Node.js SDK](/sdks/node)
* [Python SDK](/sdks/python)
* [Go SDK](/sdks/go)
* [Verify installation](/install/verify)
* [Stripe revenue attribution](/integrations/stripe)
