This page answers one procurement question directly: where do the measurements live, and on what basis do they cross a border? Every technical claim was checked against the running code (
src/), the schema (schema.sql) and the deployment config (wrangler.toml). It is the residency companion to DATA-PROCESSING.md and PRIVACY.md, which hold the full detail; this page does not repeat it, it points at it. It has not been reviewed by an external lawyer — if your process needs a counter-signed statement, write to hello@batchwatch.dev and we handle it as a contract, not as a web page.
We know exactly what we hold, where it is processed, and what never reaches us — because the data model is deliberately narrow and we built it that way. This page states it plainly so a regulated buyer can answer their own compliance team without having to reverse-engineer our infrastructure.
1. The short answer
- What is stored: queue-time metadata — model name, token counts, timestamps, durations, a two-letter country code, and salted hashes for abuse control. Never prompts, completions, system prompts, tool definitions or provider API keys. The full field list, checked against the schema, is in PRIVACY.md §2.
- Where it is processed and stored: on Cloudflare — Cloudflare Workers for compute and Cloudflare D1 for the database. Cloudflare is the only sub-processor in the request path of the measurement service.
- Who else touches it: nobody, on the measurement path. Payment data goes to Stripe for paying customers only, and consent-gated analytics to Google on the marketing pages only — neither is on the
/v1/…measurement routes. See DATA-PROCESSING.md §5. - Transfer basis: Cloudflare is US-headquartered and runs a global network, so processing may occur outside the EEA. The mechanism is Cloudflare's Data Processing Addendum and its Standard Contractual Clauses. This is the honest state and §4 says exactly where it stands.
2. Where the data physically lives
batchwatch is a single Cloudflare Worker backed by a single Cloudflare D1 database. There is no other datastore, no second cloud, and no on-premise component. That is the whole system, and it is small on purpose — a narrow surface is easier to reason about than a broad one.
Compute — Cloudflare Workers. Requests are served at Cloudflare's edge, close to the caller, wherever the caller is. The Worker code is src/; it is what gets deployed, with no hidden backend behind it.
Database — Cloudflare D1. Every measurement, key hash and counter lives in one D1 database, declared in wrangler.toml:
[[d1_databases]]
binding = "DB"
database_name = "batchwatch"
database_id = "cfc78264-b810-4ac9-af83-489ab11a43df"
D1 has one primary region that holds the authoritative copy; reads may be served from replicas nearer the caller.
The country code, and how it is derived. The one location-shaped field we store is call.region — a two-letter country code read from Cloudflare's cf-ipcountry edge header (src/index.js), which Cloudflare derives from the caller's IP at its edge. We store the country code, never the IP address. It is the contributor's own country, an attribute of the measurement row — it is not where the database lives.
3. The D1 primary region — stated as it is
The D1 primary region is not pinned in our configuration. wrangler.toml declares the database binding and id but sets no location_hint, so Cloudflare chose the primary region when the database was created. Because we do not assert a region we have not verified, this page does not claim an EU primary — see DATA-PROCESSING.md §5 and PRIVACY.md §9, which say the same thing.
This is a solvable, well-understood knob, not a limitation of the platform:
- Recording it is a one-time lookup in the Cloudflare dashboard, after which the exact region is written here and in the two documents above.
- Pinning an EU primary is supported: D1 accepts a
location_hintat database creation. Moving an existing database to a specific primary means recreating it and re-importing, which is an operator action.
If an EU-primary guarantee is a hard requirement for your process, say so at hello@batchwatch.dev — it is a configuration we can commit to for a named customer, and §5 records it as an open decision so it is not lost.
4. The transfer basis
Cloudflare is a US-headquartered company operating a global network, so personal data may be processed outside the EEA. The lawful transfer mechanism is Cloudflare's Data Processing Addendum and its Standard Contractual Clauses, which govern transfers to the US and to Cloudflare's wider network.
Two things are true at once, and both are stated rather than one hidden behind the other:
- The mechanism exists and is the right one. Cloudflare publishes a DPA and the SCCs; that is the standard basis for a service built on their platform, and it is the basis batchwatch relies on.
- The counter-execution and the transfer impact assessment are open items. Cloudflare's DPA and SCCs have not yet been counter-executed on our side, and a transfer impact assessment has not yet been done. Both are named in DATA-PROCESSING.md §5–6 and tracked as decisions in §5 below.
For a buyer who needs the executed paperwork before onboarding, that is exactly the conversation hello@batchwatch.dev exists for — we would rather resolve it as a contract with a real customer than assert it is done when it is not.
5. Open decisions — for the operator, not the reader to guess
The residency and transfer story is truthful today. Three items still need a product or legal decision before this page can drop its qualifiers, and they are recorded here so they are decided on purpose rather than defaulted:
- D1 primary region — record, and decide whether to pin. Look up the current primary in the Cloudflare dashboard and write it into this page, DATA-PROCESSING.md §5 and PRIVACY.md §9. Then decide whether to pin an EU primary via
location_hint(a recreate-and-reimport), or to keep the Cloudflare-chosen primary. Owner: operator. - Counter-execute Cloudflare's DPA and SCCs, and do the transfer impact assessment. This is the paperwork that turns "the mechanism is the SCCs" into "the SCCs are in force". Owner: operator / legal.
- Retention periods. No automatic deletion is implemented in the code today — verified: there is no TTL, no scheduled purge and no
DELETEstatement insrc/. Rolling query windows (30 days, 7 days, 1 hour) mean older rows stop influencing answers, but the rows are retained. Setting a retention bound for thetrialandusageabuse-control records — and deciding the deliberately-unbounded term of the aggregate contribution — is a policy call, tracked in PRIVACY.md §6 and reflected in the licence term in TERMS.md §7. Owner: operator / legal.
Until each is settled, this page states the real position and does not overclaim. That is the point of writing it down: a buyer gets the truth, and the operator gets a short, closable list rather than an open-ended worry.
6. What a self-host or VPC deployment would answer — and why it is parked
A regulated buyer sometimes asks the stronger question: can the measurements never leave our infrastructure at all? — i.e. a self-host or VPC deployment of the prober. That option is parked: it is a platform build, and the decision (2026-08-29) is to answer the residency question with a page rather than shape the architecture around a customer we do not yet have. It reopens the moment a named customer needs it. For almost every buyer, the question underneath it — where does the data live and on what basis does it transfer? — is answered above, today, without one.
7. Contact
hello@batchwatch.dev · Stenager Consulting ApS, CVR 44456923, Stenagervaenget 45, 7100 Vejle, Denmark.