> For the complete documentation index, see [llms.txt](https://andrewkimjoseph.gitbook.io/celina-sdk/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://andrewkimjoseph.gitbook.io/celina-sdk/guides/telemetry.md).

# Telemetry

On **Node.js**, the SDK reports usage counts for **read** operations to [Amplitude](https://amplitude.com)'s HTTP API. [celina-stats-api](https://api.stats.usecelina.xyz) copies those events into its stats store on the daily export cron. Each event uses the same name as the corresponding Celina MCP tool (for example `get_stablecoin_balances`, `verify_self_agent`). The Amplitude write key ships in the SDK. The export secret stays on the stats Worker.

## What is sent

* Event name (MCP tool name)
* A `device_id` identifying the **npm package** that called `createCelinaClient()` (auto-detected from its `package.json` `name`, sanitized: strip leading `@`, replace `/` and `-` with `_`, e.g. `celeste_ai`, `andrewkimjoseph_celina_mcp`). Falls back to `celina_sdk` when detection fails. **Prefer setting `analyticsDeviceId` explicitly** — auto-detection walks the call stack to the nearest `package.json` and can misattribute events in bundled/serverless deployments (Next.js, Vercel, single-file bundles).
* A `user_id` set to the lowercase wallet `0x…` address when the read is wallet-scoped (no other args — wallet is only on `user_id`)
* No tool arguments or private keys

### Canonical device ids across the Celina ecosystem

The Celina ecosystem is the `celina-*` packages plus [celeste-ai](https://github.com/andrewkimjoseph/celeste-ai). Other apps that embed the SDK are consumers, not ecosystem members.

| Project                  | `device_id`                                     | How it's set                                                                       |
| ------------------------ | ----------------------------------------------- | ---------------------------------------------------------------------------------- |
| celina-sdk (no override) | `celina_sdk`                                    | Default fallback                                                                   |
| celina-mcp               | `andrewkimjoseph_celina_mcp[_<install-suffix>]` | `getMcpAnalyticsDeviceId()` (per-install anonymous suffix)                         |
| celina-api               | `celina_api` (default), or caller-supplied      | `X-Celina-Client` request header, sanitized                                        |
| celina-bot               | `celina_bot`                                    | Sends `X-Celina-Client: celina_bot` to celina-api (doesn't embed the SDK directly) |
| celeste-ai               | `celeste_ai`                                    | Explicit `analyticsDeviceId`                                                       |

Consumers should follow this pattern: pass `analyticsDeviceId` explicitly in `createCelinaClient()` (or forward a caller id via a header, like celina-api/celina-bot do) rather than relying on auto-detection.

Wallet resolution order:

1. Wallet address extracted from the read call args (catalog-driven)
2. `runWithAnalyticsWallet(address, fn)` request scope (singleton SDK clients)
3. `analyticsWalletAddress` on `createCelinaClient()` (e.g. MCP session signer)

Writes and `prepare*` flows are not tracked (on-chain Celina attribution covers those — see [On-chain attribution](/celina-sdk/guides/on-chain-attribution.md)). Successful mined writes are also reported (hash only) to [celina-stats-api](https://api.stats.usecelina.xyz) via `reportCelinaOnchainTxn` — see that same guide.

Custom `attributionTags` from client config appear in the calldata suffix on-chain, not in telemetry events.

## Default behavior

Telemetry is **on** for server-side use (MCP, your app's API routes, scripts) unless you opt out.

Browser bundles that import the SDK do not send events.

On **serverless** hosts (Vercel, AWS Lambda, Cloudflare Workers), do **not** await the report on the request path — that adds request round-trip time (or a hung timeout) to every read. Tracking is fire-and-forget; keep the isolate alive with `waitUntil(drainCelinaAnalytics())` (Workers) or `waitUntil` / `after(() => drainCelinaAnalytics())` (Vercel / Next).

### Singleton clients (e.g. Next.js API routes)

When one shared `createCelinaClient()` serves many users, wrap the handler:

```ts
import { runWithAnalyticsWallet, drainCelinaAnalytics } from "@andrewkimjoseph/celina-sdk";
import { after } from "next/server";

export async function POST(req: Request) {
  after(() => drainCelinaAnalytics());
  const { address } = await req.json();
  return runWithAnalyticsWallet(address, () => {
    // SDK reads inside this scope attach address as user_id
  });
}
```

## Opt out

```ts
const celina = createCelinaClient({
  analyticsEnabled: false,
});
```

## Overrides

| Option                                                                   | Purpose                                                                                                                                                |
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `analyticsDeviceId` in `createCelinaClient()`                            | Override auto-detected `device_id` (recommended for every non-SDK integration)                                                                         |
| `analyticsWalletAddress` in `createCelinaClient()`                       | Default wallet for `user_id` when reads omit an address                                                                                                |
| `statsApiBaseUrl` in `createCelinaClient()` / `CELINA_STATS_API_URL` env | Override the celina-stats-api base URL for on-chain hash reporting only (default `https://api.stats.usecelina.xyz`). Read telemetry goes to Amplitude. |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://andrewkimjoseph.gitbook.io/celina-sdk/guides/telemetry.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
