How it stays private

The data path, in full — nothing hidden.

Content-blind does not mean invisible. This page is the honest, checkable account of exactly what happens to your spreadsheet. The network claims here you can check in your own browser's Network panel.

1 · Parsing and cloaking run on your device

When you drop a file or paste rows, the CSV/TSV/xlsx is parsed in the tab — no upload. Cells in the first 500 rows are run through the published CloakAPI browser engine (a WebAssembly tokeniser, an on-device name dictionary, a ~25 000-name gazetteer, and the same on-device multilingual NER model the rest of the suite uses — a multilingual BERT model, ~181 MB, for Level 2, plus a Level 3 model, fetched same-origin). Cells it detects — emails, phone numbers, dates of birth, cards, IBANs, passports, national/health/company IDs, IP addresses, postcodes, places, organisations, and person names, including uncommon and non-Latin-script names the model finds — are replaced with realistic, locale-matched surrogates. If the name model cannot load, we hold the send and offer you the choice at once to send with the layers that are ready — taking it sends with the engine, dictionary and gazetteer only, and leaving it sends nothing. If it is merely still loading, we hold the send — and after about ten seconds we offer you the choice to send anyway with the layers that are ready. Take that choice and the send proceeds with the engine, dictionary and gazetteer only — the model's contextual catches are not in it. Cells it still does not detect are left as they are: a residual the receipt measures. Secrets-class values (cards, national IDs) become opaque, locked markers. A marker is derived from the value itself with no secret key: it cannot be turned back into the number, but anyone who already holds a candidate number can check whether it matches. The link from marker to real value exists only on this device, and an answer that repeats the marker is shown with the real value. During this step the app requests its engine, dictionaries and models from this origin. The live monitor counts requests it observes to other origins; check it alongside your browser's Network panel.

2 · The analysis request is relayed

When you ask a question, the browser prepares a JSON request containing the question, instructions, column names, up to 8 rows in cloaked form (every row if the sheet has 8 or fewer) and request metadata. Be precise about what that means: every cell the engine detected is a surrogate in that sample, and a cell it detected nothing in is included exactly as it is — a department, a salary figure, or a residual the on-device name model also missed. The request body receipt reports the UTF-8 byte size of the exact JSON body this browser posts to the same-origin relay. It includes instructions, the question, schema, cloaked sample and request metadata; it excludes HTTP headers and transport bytes and does not measure bytes received by the gateway. The server builds a separate gateway request from those messages and obtains a pretokenisation proof for that body; it does not run PII detection or tokenisation. The model receives these messages and writes analysis code — the full table stays in the tab, and the analysis runs on your device.

3 · The analysis runs on your device

The model's Python is executed in a sandboxed Web Worker on your machine, using a pinned, same-origin Pyodide runtime. The worker is served with a connect-src 'self' Content-Security-Policy and installs a no-network guard as its first statement. That guard blocks WebSocket, EventSource and sendBeacon outright, and rejects fetch, XMLHttpRequest and importScripts to any other origin, so the code that touches your real rows cannot open a connection to anywhere else. Same-origin requests are still allowed — that is how the pinned runtime loads — and the CSP above is what holds that origin to this app. pandas, numpy and matplotlib run over your real numbers; the answer and any charts are written to an in-memory folder and rendered locally.

4 · A request body receipt, not a promise

After a successful analysis, the request body receipt shows how many cells were cloaked, by category; text byte counts for detected and undetected values in sample cells; and the UTF-8 byte size of the exact JSON request body this browser posted to the same-origin relay. The sample text counts are not serialized JSON lengths, and the request-body size is not a gateway-received byte count. The re-identification map that restores your originals stays in the browser.

What we can and can't claim

  • We can say: rows outside the sample stay in the tab; if the sheet has 8 or fewer rows, every row is included in the cloaked sample — the question, instructions, column names, up to 8 sample rows and request metadata are sent in the JSON body to the same-origin relay; every detected sample value is a surrogate; the request body receipt reports that body's UTF-8 byte size and sample text counts; the analysis code runs locally in a sandbox that cannot open a connection to any other origin; the re-identification map stays in the tab.
  • We won't say: that no real cell value reaches the gateway. A cell in the sample rows in which the engine detected nothing may be relayed as written; the receipt's sample text counts describe cell text and are separate from its serialized JSON body byte count.
  • We also won't say that the receipt tells you which name layers ran. If you took the ten-second choice and sent before the model finished, the receipt looks the same as one from a full pass — it measures request-body length and sample text counts either way, but it does not record that you accepted partial coverage. The panel that offered you the choice is the only place that says so.
  • And we won't say that detection is complete. Structured PII (emails, phones, dates of birth, cards, IBANs, passports, national/health/company IDs, IPs, postcodes) is deterministic and high-coverage. Person names, organisations and places are checked by the on-device NER model (Layer B) on top of the dictionary and gazetteer — uncommon and non-Latin-script names are in scope. The model is not perfect: some organisations still slip through both layers, and street addresses are still matched in US number-first order only, so a European “Storgata 14” is not detected as an address. If the name model does not run, the sheet is not sent. Reveal originals and scan the grid before you rely on a column being fully cloaked.

The platform's full legal terms — Terms of Service, Privacy Policy, Data Processing Addendum and data-subject requests — live at cloakapi.io/legal ↗.