Skip to main content

Guides

What Leaves Your Device When You Import an AI Export, and What Does Not

Your export is parsed in the browser before anything is uploaded. The exact path from file picker to database, including the limits.

By Novus Stream Solutions Editorial Team. Published 2026-07-31. Last reviewed 2026-07-31. 5 min read.

An AI export is one of the most sensitive files you own. A single chat archive can contain client names, credentials pasted into a prompt, unreleased plans, and the text of every document you ever attached.

So the interesting question about an AI analytics product is not which charts it draws. It is what actually travels over the network.

Here is the whole path, in order.

The file picker is the only entry point

There is no background scanning. A web app cannot watch a folder, and this one does not ask to. Every import begins with you selecting files or a directory.

You also choose the source explicitly. Shape detection exists, but it is assistance for the picker, never the decision — the adapter you select is authoritative, and a file that does not match it is rejected instead of being coerced.

Filenames are never authoritative either. A Cursor database is recognised by its first sixteen bytes, the literal SQLite format 3 header, not by its extension. Extensions are only an allow-filter: .json, .jsonl, .md, .markdown, .sqlite, .db, and .vscdb are considered, and everything else in a selected folder is skipped before it is read.

Parsing happens in a worker on your machine

The parser runs in a Web Worker inside your tab. ZIP archives are expanded in memory in the browser. Nested archives are rejected rather than walked, and an entry whose path has more than eight segments is rejected too.

The ceilings are fixed and checked before any parsing starts.

CeilingValue
Selected files1,000
Selected bytes512 MB
Any single file256 MB
Files after expanding archives10,000
Bytes after expanding archives1 GB
One JSONL line4 MB

These are not arbitrary. Parsing a large export inside a browser tab costs memory, and a limit that refuses is better than a tab that dies halfway through.

The narrowing step: everything to the left of this line stays on your machine.Generated motif, seeded from this article’s slug. It is decorative and encodes no measurements.

Normalization is a narrowing step, not a copy

Each conversation or session becomes one normalized record. That record holds the provider and product surface, start and end timestamps, duration fields, prompt and response and tool and agent counts, token categories, model names, a project hint, quality labels with their provenance, and warning codes.

It does not hold messages. Prompts, responses, code, attachments, and file contents are read to produce counts and timestamps, then discarded when parsing finishes.

Session titles are the one genuinely optional field. The default privacy mode is stats-only and sends no title at all; sending titles is a separate choice you make before the preview runs.

Local paths become hashes

A working directory is useful — it is how sessions group into projects — and it is also the field most likely to leak a client name or your own username.

So the path itself is never uploaded. It is reduced to a SHA-256 hash in the browser, plus a short display hint, and the project name you see is the one you confirm yourself.

Identity is derived, not taken from the file

Every record carries two hashes. A stable source identity uses the provider's own session ID when the export contains one; when it does not, it is a SHA-256 over exactly four values: start time, prompt count, response count, and the sorted model list. A second hash covers the whole normalized record.

Neither hash contains message text, and neither is the checksum of your ZIP. The container is not identity.

The upload is a batch of statistics

Normalized sessions are sent in batches of one hundred, each with a UUID idempotency key. Before storing anything the server re-derives both hashes from the payload and rejects the batch if either fails to match, so a client cannot claim an identity it did not compute.

The server also scans the payload for prohibited field names — anything matching prompt, response, content, attachment, transcript, raw, or a path field — and rejects the whole batch if one appears.

Be precise about what that check is: it reads key names, not values. It is a structural guard against an adapter regression shipping a new field, not an inspection of your data. The real protection is that the parser never puts message text into the record in the first place.

Re-importing the same export is safe

Exports overlap. You will import the same archive twice.

A record whose stable identity and normalized hash both already exist is skipped. A record whose identity exists with different content updates the existing session. Only genuinely new identities are inserted. Lifetime totals do not double because you exported again.

What this design does not give you

It does not prove what your browser did. Re-deriving hashes on the server proves a record is internally consistent; it does not prove your machine discarded anything. The verifiable claim is narrower and more useful: the payload has a fixed shape, and message text is not part of it.

It also does not always succeed. If no supported session is found, the import fails with an explicit reason and nothing is created — no partial statistics, no synthetic sessions.

And importing is still behind a server release flag, enabled source by source as fixture coverage lands. When it is off the workbench is visibly disabled rather than quietly broken. The provider import reference tracks what each adapter accepts today.

A tracker earns trust by being specific about the boundary. The boundary here is the worker in your tab: files go in, counts come out, and the counts are all that leave.

Was this page helpful?

Your answer stays in this browser. It is not sent anywhere, and no account or cookie is involved.