1---
2layout: ../layouts/Marketing.astro
3title: "Privacy & Telemetry — Alchemy"
4description: What data the Alchemy CLI and Cloudflare State Store collect, where it goes, and how to opt out.
5---
6import "../styles/privacy.css";
7
8<div class="alc-privacy">
9
10# Privacy & Telemetry
11
12The Alchemy CLI and the Cloudflare State Store worker emit
13OpenTelemetry traces, metrics, and logs to a relay we operate at
14`otel.alchemy.run`, which forwards to our Axiom workspace. The data
15helps us prioritize providers, find bugs, and understand which
16features people actually use.
17
18This page documents exactly what is collected, what is not, where
19it goes, and how to opt out. Source of truth is the code:
20[`Telemetry/Attributes.ts`](https://github.com/alchemy-run/alchemy/blob/main/packages/alchemy/src/Telemetry/Attributes.ts)
21and [`Cloudflare/StateStore/Api.ts`](https://github.com/alchemy-run/alchemy/blob/main/packages/alchemy/src/Cloudflare/StateStore/Api.ts).
22
23## What we collect
24
25### From the CLI
26
27Resource attributes attached to every span/metric/log:
28
29| Attribute | Value |
30| --- | --- |
31| `alchemy.user.id` | Random UUID generated on first run, persisted at `~/.alchemy/id`. Not your shell user, email, or hostname. |
32| `alchemy.session.id` | Random UUID per CLI invocation. |
33| `alchemy.version` | The version of the `alchemy` package you're running. |
34| `alchemy.git.root_commit` | SHA of the first commit in your repo. Acts as a stable repo fingerprint. |
35| `alchemy.git.origin_hash` | SHA-256 of `git config remote.origin.url`. The raw URL is never sent. |
36| `alchemy.git.branch_hash` | SHA-256 of the current branch name. |
37| `alchemy.runtime.name` / `.version` | `bun` / `node` / `deno` and its version. |
38| `alchemy.ci` / `alchemy.ci.provider` | Whether this looks like a CI run, and which provider (GitHub Actions, GitLab, etc.). |
39| `host.arch`, `os.type`, `os.version`, `host.cpus`, `host.memory_mb` | Coarse machine info. |
40
41Per-operation span attributes:
42
43- `cli.<command>` spans carry the command name (`deploy`, `destroy`, `plan`, ...) and outcome (`success` / `error`).
44- `provider.<op>` spans carry the resource type (`AWS.S3.Bucket`, `Cloudflare.Workers.Worker`, ...), op (`create` / `update` / `delete` / `read`), and outcome.
45- `state_store.init` spans carry the state-store backend slug (`local`, `inmemory`, `http`, `cloudflare-http`, or any third-party slug).
46
47### From the Cloudflare State Store
48
49When you deploy the [Cloudflare State Store](/state-store/custom-state-store) it runs as a Worker on **your** Cloudflare account. The worker emits OTLP traces/metrics/logs to the same `otel.alchemy.run` relay.
50
51Resource attributes (set on every signal from the worker):
52
53| Attribute | Value |
54| --- | --- |
55| `service.name` | `alchemy-state-store` |
56| `service.version` | The deployed worker contract version (currently `2`). |
57| `alchemy.state_store.script_name` | `alchemy-state-store`. |
58
59Per-request span attributes (one per state-store API call):
60
61| Attribute | Value |
62| --- | --- |
63| `alchemy.state_store.op` | `getState` / `setState` / `deleteState` / `listStacks` / `listStages` / `listResources` / `getReplacedResources` / `deleteStack` / `getVersion` |
64| `alchemy.state_store.stack` | The stack name from your `alchemy.run.ts` (e.g. `MyApp`). |
65| `alchemy.state_store.stage` | The stage name (e.g. `prod`, `dev_alice`). |
66| `alchemy.state_store.fqn` | The fully-qualified resource name within the stack (e.g. `bucket/uploads`). |
67| `duration` | Op latency. |
68
69CLI-side spans that touch the Cloudflare State Store
70(`state_store.bootstrap`, `state_store.deploy`, `state_store.init`)
71also carry `alchemy.cloudflare.account_hash` — a SHA-256 of your
72Cloudflare account ID. The raw account ID is never sent. We use the
73hash to count distinct deployments without identifying anyone.
74
75## What we don't collect
76
77- Secrets, API tokens, environment variables, `.env` contents.
78- Resource property values, source code, file contents.
79- Raw filesystem paths, hostnames, or shell user names.
80- Raw git URLs, raw branch names, raw Cloudflare account IDs (only SHA-256 hashes of these).
81- IP addresses (the relay strips them before forwarding).
82- Any tracking cookies, advertising IDs, or third-party identifiers.
83
84## Where it goes
85
86`otel.alchemy.run` is a Cloudflare Worker we operate. It accepts
87standard OTLP/HTTP at `/v1/traces`, `/v1/logs`, and `/v1/metrics`,
88attaches an Axiom ingest token server-side, and forwards to our
89Axiom workspace. Source for the relay lives at
90[`stacks/otel/Ingester.ts`](https://github.com/alchemy-run/alchemy/blob/main/stacks/otel/Ingester.ts).
91
92We do not share or sell the data. Aggregated stats may appear in
93public talks, posts, or dashboards.
94
95## How to opt out
96
97### CLI — kill all telemetry
98
99Any one of these disables the OTLP exporter entirely. The CLI's
100default tracer becomes a no-op, so nothing leaves your machine:
101
102```sh
103DO_NOT_TRACK=1 alchemy deploy
104NO_TRACK=1 alchemy deploy
105ALCHEMY_TELEMETRY_DISABLED=1 alchemy deploy
106```
107
108To make the opt-out persistent without setting an env var on every
109run, create the marker file:
110
111```sh
112mkdir -p ~/.alchemy
113echo "true" > ~/.alchemy/telemetry-disabled
114```
115
116To re-enable, delete the file:
117
118```sh
119rm ~/.alchemy/telemetry-disabled
120```
121
122### Cloudflare State Store — opt out per-deployment
123
124The state-store worker exports its own OTLP signals — these go
125through the same relay but flow even if your CLI's telemetry is
126disabled (because the worker runs on your CF account, not your
127machine). Two mechanisms exist:
128
129**`noTrack` option.** Passes through to the CLI-side state-store
130spans, suppressing the `alchemy.cloudflare.account_hash` attribute:
131
132```ts
133import * as Cloudflare from "alchemy/Cloudflare";
134
135Cloudflare.state({ noTrack: true });
136```
137
138**`NO_TRACK` env var.** When `Cloudflare.state()` is called without
139an explicit `noTrack`, it falls back to `NO_TRACK` from the
140environment.
141
142```sh
143NO_TRACK=1 alchemy deploy
144```
145
146`noTrack` only suppresses the account-hash attribute on state-store
147spans. To stop the worker from emitting signals at all, you'd need
148to remove the OTLP layer in your own fork of `Api.ts`, or run a
149custom HTTP state store via [/state-store/custom-state-store](/state-store/custom-state-store).
150
151## Questions
152
153Email [sam@alchemy.run](mailto:sam@alchemy.run) or open an issue at
154[alchemy-run/alchemy](https://github.com/alchemy-run/alchemy/issues).
155
156</div>