Privacy & data handling

A local build sends nothing. A cloud build obfuscates in memory and keeps nothing, except the Protection Map you asked it to store, which you can turn off. Telemetry is on by default, reports when a build reports an error-level diagnostic, never on a clean build, and turns off with one env var.

AfterPack's obfuscation product handles your code and account data as described below. This site's cookies and analytics are covered separately, in the Privacy Policy.

The short version

A local (Free) build never sends your source anywhere. A cloud (Pro) build obfuscates in memory and discards the source at the end of the request. One artifact is stored: the Protection Map for the dashboard. It is workspace-scoped, it expires, and you can turn it off per project. Telemetry is on by default, reports when a build reports an error-level diagnostic (a refused or partial build), never on a clean build, and turns off with AFTERPACK_telemetry_enabled=false. A DPA and the full sub-processor list are available on request.

A local build sends nothing

The Free engine is a native binary that runs on your machine. Nothing leaves your filesystem, so the cloud sections below don't apply to it. The only network call a local build ever makes is the telemetry report described below, which fires only when a build reports an error-level diagnostic (a refused or partial build), carries no source, and can be switched off.

A cloud build obfuscates in memory and keeps nothing

When a Pro build sends source to api.afterpack.dev to be obfuscated, it is processed in memory only, for the duration of that single request, then discarded:

  • The request runs inside a sandboxed Cloudflare Worker isolate that is destroyed at the request boundary. Nothing survives past the response.
  • Logging never carries source. Log lines carry a build id, file counts, byte totals, diagnostic codes, and the path of a file that failed. They never carry file contents, identifier names, or constant values.

This holds identically whether you call the API directly, through the CLI with AFTERPACK_key set, or through a framework plugin. They all speak the protocol described in the Cloud API reference.

One artifact is stored: the Protection Map, described below, written after the obfuscation is finished. The source you upload to be obfuscated is still gone at the end of the request.

What logs do and don't carry

RecordedNever recorded
Timestamps (request received, response closed)File contents
HTTP status codesIdentifier names
Build id, file counts, input/output byte totalsConstant values, including secrets that happened to appear in source
Diagnostic codes (DIAG_*)Diagnostic message text from telemetry
Client IP, for rate limitingSource map sources / sourcesContent
Workspace tier, for meteringAnything that could reveal your business logic

Aggregated metrics (per-day request counts, per-workspace metered bytes, build timings) are kept as counters and contain no code.

Telemetry is on by default, and only reports a build's error-level diagnostics

The client can report anonymous build diagnostics so engine bugs get found and fixed. It is on unless you turn it off. A clean build has nothing to report:

  • Only a build that emits an error or critical diagnostic sends anything. A clean build sends nothing at all: no periodic ping, no phase timings, no usage stats for a build that just worked.
  • Turn it off with AFTERPACK_telemetry_enabled=false, --telemetry.enabled=false on the CLI, or telemetry: { enabled: false } in your integration's config. Those are the whole surface.
  • It runs identically in CI. No TTY or CI check changes the default or skips reporting; the payload simply records ci: true, read from the same CI variable your pipeline already sets.
  • No prompt, ever. The first build after install prints a one-time notice (what is collected, what is not, how to turn it off) and moves on. It never blocks waiting for an answer. State (a random install id that rotates every 30 days, and whether the notice has printed) lives in ~/.afterpack/telemetry.json.
  • Test runs are exempt. NODE_ENV=test and Vitest's own VITEST marker disable telemetry.

What's collected, when a build reports an error-level diagnostic

  • The failing diagnostic's code, severity, and byte-offset span, plus a short list of typed fields chosen per diagnostic kind, never its free-text message
  • Engine, client, and Node versions, OS/arch, and the detected framework
  • Whether the build ran in CI
  • The complexity level: a named preset, or custom for a raw complexity
  • File count and build duration, bucketed (5-20, 1-5s) rather than exact; an exact number fingerprints a specific project
  • A random install id that rotates every 30 days, never derived from your machine or project

What's never collected, telemetry or otherwise

  • Source code or file contents
  • File names and file paths in telemetry. A cloud build's server-side log carries one path, the file that failed inside the batch, as described above
  • Diagnostic message text, ever; only its stable code
  • API keys or credentials
  • Constant values
  • String encoding choices
  • Any user-identifying information beyond what your account itself holds

Telemetry has a fixed shape.

Protection Maps for cloud builds are stored, and you can turn that off

A Protection Map is your original source, coloured by how hard each token is to reverse. On a cloud build, AfterPack generates it on the server that did the obfuscation and keeps it, so you can open any recent build's map from the dashboard.

This is the one place your source sits at rest

Storing Protection Maps is on by default, per project, and a stored map is readable by every member of the workspace that owns the project. If your source shouldn't be readable workspace-wide, a workspace admin turns the setting off in that project's settings.

  • What's stored: the map data for each build, your original source plus the per-token metrics behind the colours, compacted and gzipped into Cloudflare R2, encrypted at rest, plus a row of summary numbers for the dashboard. Your obfuscated output is not stored.
  • Scoped to one project, the one the build's key is bound to.
  • Readable only by members of that workspace. Not public, not indexed, no shareable link.
  • Retention: one year, and the last 500 builds per project, whichever runs out first. An hourly job deletes whatever is past either bound. For a project that builds often, the count is the bound that bites first. It caps how many copies of your source exist at any moment.
  • A map may be stored partial. When a build runs long, capture stops before obfuscation does. The stored record says which chunks were skipped and why.
  • Turning it off stops new builds from storing anything for that project. Maps already stored age out under the retention above rather than being deleted immediately. Local builds are unaffected: the Protection Map a local build writes into .afterpack/ never leaves your machine.
  • What's still recorded with it off: the build's numbers (coverage, inflation, complexity, timings), so the project's dashboard charts keep working. These are aggregates derived from a build. They contain no code, and nothing in them can be read back as code.

Sub-processors

A cloud build touches these processors. Source passes through Cloudflare in memory only while it is being obfuscated; Cloudflare is also the only one that ever holds source at rest, as the Protection Map described above:

Sub-processorRole
CloudflareWorkers / R2 / D1: edge compute, routing, Protection Map storage, and the account database
CreemBilling only, as merchant of record; never receives source
Email / auth providersMagic-link and transactional email for account and key-lifecycle events; never receive source
Anthropic (via Cloudflare AI Gateway)Powers the in-site assistant ("Ask AfterPack"); receives what you type into it and the documentation pages it reads to answer, never your source code

Data residency

The sections above answer whether source is stored. Residency is the separate question of where it is processed while a request is live, and where the stored map sits.

Neither is region-pinned. A cloud build is routed by Cloudflare to a nearby region, and under failover or load it can land elsewhere. There is no per-request region pin, and R2 storage is not region-locked. If you need a firm residency guarantee, use a local build. The Free engine runs entirely on your own infrastructure, so no residency question arises.

DPA and compliance

A Data Processing Agreement is available on request. The DPA you sign is the legal, executable contract, and it points back to the sub-processor list and residency behaviour described above.

Next