All articles
A paper document with raised charcoal bars masking two lines, a lime accent, and a small charcoal tile.

What Your AI Writing Tool Actually Sends to the Cloud

You paste an email into a chat window to make it sound better. The email contains your home address, a client's phone number, and the last four digits of a card. A second later the rewrite comes back and you move on.

That text is now on someone else's servers. Not because anyone did anything wrong. That is simply what "send it to the model" means. The question nobody asks at that moment is which company received it, how long they keep it, and who inside that company can read it.

This guide covers what actually leaves your machine when you use an AI writing tool, how to find out for a specific product, and how to strip personal information out before it goes, including the open-source way to do it.

"Encrypted" is not the answer to this question

Every credible tool uses TLS. Nobody is reading your text off the wire. That is table stakes, and it answers a question you were not asking.

The real questions are about the receiving end:

  • Who receives it? Most AI writing tools are not running their own models. They are a thin layer over an API from OpenAI, Anthropic, Google, or a hosting provider. Your text goes to that company too.
  • How long is it kept? Provider defaults differ, and "we don't train on it" is a different promise from "we don't keep it". Several major APIs retain request data for a period for abuse monitoring by default, with zero-retention available on request or on specific tiers.
  • Who can read it? Retained data can be reachable by staff under defined processes, by a legal request, and by anyone who gets into the account.
  • Which jurisdiction? Where the servers are decides whose courts can compel disclosure.

A breach does not have to be dramatic to matter. If a tool held ninety days of requests and those requests contained your address and your clients' contact details, the size of the incident is not measured in your account. It is measured in everything you ever pasted.

Four checks before you paste anything sensitive

Do these once per tool. They take about ten minutes and the answers are rarely on the marketing page.

1. Find the sub-processor list. This is the one that matters, and it is usually a separate page linked from the privacy policy or the DPA, often titled "Sub-processors" or "Third parties". It names every company that receives your data. If OpenAI, Anthropic, Google, Azure, or AWS Bedrock is on it, your text reaches them. A tool with no such list either has nothing to disclose or is not disclosing it, and the privacy policy usually makes clear which.

2. Separate training from retention. Look for two distinct statements: whether your content is used to train or improve models, and how long it is stored. "We never train on your data" is common and says nothing about storage. Ask for a number of days.

3. Check which tier you are on. Consumer and business tiers of the same product frequently have opposite defaults. Free and personal plans often allow training unless you opt out; team, enterprise, and API tiers often forbid it by contract. If your employer's DPA is doing the work, it only covers the account it applies to, not the personal one you use at home.

4. Work out what the tool reads, not just what you paste. A system-wide assistant that reads the field you are typing in has a wider surface than a chat window you paste into deliberately. Neither is worse by definition; they are different amounts of text, and you should know which one you have.

Mask before you send

The general fix is older than AI writing tools: do not send the sensitive values in the first place. Detect personal information on the device, replace it with a placeholder, send the placeholder, and put the real value back into the answer locally.

For an email like this one:

Hi Ana, the invoice should go to 42 Elm Street, Bristol. My mobile is 07700 900461 if the courier needs it.

what leaves the machine is:

Hi Ana, the invoice should go to [ADDRESS_1]. My mobile is [PHONE_NUMBER_1] if the courier needs it.

The model rewrites that text without ever seeing the address or the number. The placeholders come back in its answer and get swapped for the originals on your machine, so you read the finished version with the real details in place.

Two design choices make this work rather than merely sound good.

The placeholders are reversible, not redactions. [ADDRESS_1], not *****. This matters more than it looks. A redaction marker leaves a hole the model has to write around, and a false positive turns into a row of asterisks in text a person reads. A labelled placeholder tells the model what kind of thing sits there, so it can construct a correct sentence around it. A false positive costs a placeholder you silently restore, nothing more.

The asymmetry sets the threshold. A missed detection sends real data to a third party permanently. A false detection produces slightly noisier input to the model and is undone on the way back. The two errors are nowhere near equal, so the detection threshold is set low on purpose, accepting false positives to reduce misses.

Doing it on-device, without Python or a GPU

The detector has to run locally, or it is just another network hop with the same problem. That rules out a hosted PII API and it rules out anything that needs a Python runtime shipped inside a desktop app.

What works: a small named-entity model exported to ONNX and quantised to INT8, run through ONNX Runtime. No Python, no GPU, no network call.

BlinkWrite's implementation is open source under MIT, at github.com/BlinkWrite/pii-masker, in two versions: Swift for macOS, and .NET for Windows and Linux. Both run the same model with the same settings, and the weights are on Hugging Face at blinkwrite-ai/gliner-small-pii-onnx-int8. The specifics, since general claims are the easy part:

  • Detection is GLiNER, a zero-shot entity model that takes its label set at inference time rather than being trained on fixed classes. The weights are a modified vicgalle/gliner-small-pii, itself fine-tuned from gliner-community/gliner_small-v2.5. Both are Apache-2.0. The modification is the ONNX and INT8 conversion; no retraining.
  • The model is about 137 MB on disk and its version is pinned in source, along with the SHA-256 of the archive and the SHA-256 of the unpacked weights. Both are checked, the second after unpacking. A hosted manifest would move that trust to whoever serves the manifest; a constant compiled into the library has no host to trust.
  • Seventeen categories ship by default: phone number, email address, credit card number, address, social security number, date of birth, bank account number, password, PIN code, IP address, dollar amount, passport number, driver licence number, tax ID, API key, access token, and secret key. Because the model is zero-shot, the list is configuration. Add "employee id" and it detects employee IDs.
  • The label also names the placeholder. "email address" produces [EMAIL_ADDRESS_1], so renaming a label changes the token the remote model sees.
  • If masking cannot run, because the model is missing or the text is too long or inference times out, the correct response is to send nothing. Fail closed. A masking layer that quietly passes text through on failure is worse than no masking layer, because you stop checking.

Both versions ship the same command-line tool, so you can watch it work before writing any code:

# Swift, on macOS
echo "Card 4111 1111 1111 1111, SSN 123-45-6789, I live at 42 Elm Street." | swift run pii-mask --model ./model --show-map
# .NET, on Windows or Linux
echo "Card 4111 1111 1111 1111, SSN 123-45-6789, I live at 42 Elm Street." | dotnet run --project dotnet/src/pii-mask -- --model ./model --show-map
Card [CREDIT_CARD_NUMBER_1], SSN [SOCIAL_SECURITY_NUMBER_1], I live at [ADDRESS_1].

What masking does not fix

Anyone selling this as a guarantee is overselling it. The honest limits, all of them documented in the library:

  • Recall is not 100%. It is a best-effort entity model, not a rule engine. Some personal information gets through, and no compliance claim should be built on it.
  • Long context detects worse than short context. Measured on the shipped weights: eight of eight planted entities caught in a bare sentence, six of eight once 300 words of surrounding prose are added. If you mask long context, lower the threshold.
  • Languages without spaces are unsupported. The model's spans are whitespace-delimited, so Chinese, Japanese, and Thai arrive as one enormous word. The pass fails, which means nothing leaks. It also means those users get no masking, so a caller that gates on it holds their requests entirely.
  • It is tuned for English chat and email prose. Other registers and languages are not characterised.
  • Restored text is exactly as sensitive as the input. The protection is over the wire and only over the wire.
  • Name masking covers one person reliably: the signed-in user, replaced by regex before the model runs. Everyone else is masked only when the model happens to detect them.

Those limits are the argument for a second layer rather than against the first one: mask what leaves, and separately choose who receives it.

What BlinkWrite does with your text

BlinkWrite is a Mac writing assistant that reads the field you are typing in, so the question applies to it directly. The specific answer:

Personal information is detected and masked on your Mac, by the library above, before anything is sent. Your raw text, the masking step, and language detection all stay local. The Windows version of BlinkWrite, which is in the making, masks the same way on your PC.

What is sent is the masked draft, the masked surrounding context when there is any, the type of help requested, the rephrase mode, and the detected language. That goes over an encrypted connection to BlinkWrite's own self-hosted models, not to OpenAI, Anthropic, Google, or any third-party AI API. There is no sub-processor receiving your text, which is why there is no sub-processor list to check.

Your text is not saved, logged, or retained, and it is never used to train or fine-tune anything. Each suggestion is generated and discarded. Privacy & security sets out the full list of what is sent and what stays on the device, and Uninstall BlinkWrite removes the app, the local model, your settings, and its permissions together.

If you are deciding whether to grant the system permission that makes any of this possible, macOS Accessibility permission covers what it does and does not grant. Every generation is also watermarked, so text from BlinkWrite can be identified as machine-written after the fact. AI text watermarking and detection covers how that works and what it does not reveal.

Common questions

Does ChatGPT train on what I paste?

It depends on the tier and your settings, and the defaults differ between the consumer app and the API. Check the data controls in your account rather than a general answer, and check them again for a work account, which may be governed by a separate agreement.

Is "we don't train on your data" enough?

No. It is a statement about training, not about storage, access, or disclosure. Ask for the retention period in days and for the sub-processor list. Those two answers tell you more than the entire privacy page.

Is masking the same as redaction?

No, and the difference is the point. Redaction destroys the value. Masking replaces it with a labelled placeholder that the remote model can reason about and your device swaps back afterwards, so the finished text is complete.

Does masking make the suggestions worse?

Slightly, in one direction: the model cannot use the exact value it never saw. Since it is being asked to fix the wording rather than the address, this rarely shows. A labelled placeholder also tells it far more than a row of asterisks would.

Can I use this in my own product?

Yes. It is MIT and comes in two versions: Swift for macOS 14 and later, and .NET 8 and later for Windows and Linux, on NuGet as PIIMasker. Each ships a CLI so you can see what it catches before integrating, and a health probe you are expected to run after installing a model, because a bad model does not crash; it quietly detects less.

Diana Dobra

Article written by

Diana Dobra