A customer sends a delivery address, shares a phone number or gives a CPF to find an order. An ordinary support conversation now contains personal data that a business needs to handle carefully.
We built w-privacy-filter to mask personal data in Brazilian Portuguese customer-service conversations. With an 8 MB model and a TypeScript runtime, it runs on CPU and is designed to process every message without a GPU.
What gets masked
The filter masks customer information while preserving staff introductions. A customer’s name is still masked when an attendant repeats it.
Agent: Sou Carlos, da equipe de atendimento.
User: Meu nome é Mariana Lopes. Email: mariana@example.com.
Agent: Sou Carlos, da equipe de atendimento.
User: Meu nome é [NAME]. Email: [EMAIL].The policy covers contact details, Brazilian identifiers, addresses, payment data and order references. Company names and generic business contacts stay visible.
How it works
Format rules recognize structured values such as CPF and phone numbers. Learned models use the surrounding words and who is speaking to find names and other personal values. A small classifier combines their evidence and decides what to mask[1].
The same model reads text without speakers, such as a document. There it masks every phone number and e-mail, since it cannot tell whose they are.
Results
The table shows seven of the 19 baselines we tested, scoring names, e-mails, phones, CPFs and street addresses.
Scroll horizontally to compare all 8 systems →
| Evaluation set | Wiv | GLiNER2 | PII-Tracer | OpenAI Privacy Filter | Microsoft Presidio BR | Google DLP | GLiNER pt-BR | Legal-BERT LGPD |
|---|---|---|---|---|---|---|---|---|
| BR-Agentic[2]Synthetic Brazilian Portuguese banking chats. | 93.5%23.5% leaked4.8 false /1k | 90.3%12.7% leaked3.2 false /1k | 91.7%0.3% leaked25.4 false /1k | 89.1%15.5% leaked17.3 false /1k | 86.4%12.4% leaked7.3 false /1k | 93.9%17.0% leaked3.3 false /1k | 56.5%67.5% leaked0.2 false /1k | 89.9%35.6% leaked5.4 false /1k |
| LGPD-Carolina[3]Legal documents with substituted personal data. | 80.4%26.1% leaked14.5 false /1k | 74.1%26.4% leaked20.3 false /1k | 68.1%7.6% leaked44.0 false /1k | 68.6%36.8% leaked19.9 false /1k | 48.5%53.1% leaked18.1 false /1k | 73.2%42.0% leaked11.7 false /1k | 55.4%65.0% leaked8.4 false /1k | 81.0%38.2% leaked9.2 false /1k |
| LeNER-Br[4]Court-decision fragments; only person names are annotated. Intervals resample constructed chunks, not original court decisions. | 92.7%5.1% leaked2.8 false /1k | 86.2%3.4% leaked6.0 false /1k | 73.7%23.6% leaked6.1 false /1k | 61.0%45.5% leaked8.0 false /1k | 63.3%26.6% leaked12.7 false /1k | 92.0%14.6% leaked1.7 false /1k | 60.5%58.8% leaked5.1 false /1k | 92.5%5.1% leaked2.8 false /1k |
| PTBR-PII-Val[5]2,000 synthetic Portuguese texts reserved for evaluation. | 85.9%26.5% leaked9.1 false /1k | 90.8%11.0% leaked10.1 false /1k | 84.3%5.2% leaked35.7 false /1k | 80.7%33.0% leaked11.6 false /1k | 77.0%32.5% leaked11.9 false /1k | 86.4%21.9% leaked12.4 false /1k | 97.4%2.9% leaked2.2 false /1k | 89.4%15.8% leaked12.2 false /1k |
Higher F1 is better; bold marks the highest F1 in each row, not necessarily a statistically significant difference. Hover over an F1 to see its 95% bootstrap interval. Leakage is the percentage of personal values left partly visible. False /1k counts ordinary characters masked per 1,000 scored characters. Lower is better for both. These measures use different scales.
BR-Agentic is the closest of these tests to customer-service chats. On it, Google DLP[6] scores slightly higher F1 than Wiv, but the confidence intervals overlap, so we read it as a tie. Both DLP and GLiNER2[7] leave fewer personal values exposed and mask less ordinary text.1
On written text, Wiv is ahead of DLP on the synthetic LGPD corpus (80.4 against 73.2) and level with DLP and Legal-BERT on LeNER-Br’s court decisions. On the PTBR holdout DLP is slightly ahead (86.4 against 85.9), and Wiv leaves a quarter of values partly visible, mostly names and addresses.2
The OpenAI result[8] uses our CPU adaptation.3
Select a model to highlight it. Throughput uses the same 20 public texts; F1 uses the 41 public BR-Agentic chats. Network time is not included. Google DLP is omitted here because its server-side CPU throughput is not measured. Measurement notes ↗
On the same 20 public texts, using one CPU thread, Wiv processed about 258,000 characters/s versus 58,000 for Microsoft Presidio[9] with Brazilian recognizers.4
Related work
Combining rules and learned detectors is established practice, including in Brazilian police-report anonymization[10]. OpenAI Privacy Filter[8] and Perplexity’s PII-Tracer[11] also run locally. Our contribution is a smaller implementation for this customer-service policy.
Try it
Use synthetic text only. Clicking Run filter sends your text to Wiv on Cloudflare for processing at threshold 0.5. The demo does not save or log conversation text.
Ready to run. The recorded examples are already available.
Wiv privacy filter
Live · Wiv serverReady to run on the server.
Click Run filter to send this text.
Redacted text
No result yet.
OpenAI Privacy Filter
Recorded example · offline CPURecorded offline for this exact example. Not live inference.
User: Meu CPF é 123.456.789-09. O pedido 448231 foi cobrado em R$ 150,00. Agent: Vou consultar o pedido.
Redacted text
User: Meu CPF é [account_number]. O pedido 448231 foi cobrado em R$ 150,00. Agent: Vou consultar o pedido.
This example only: character F1 100.0% · recall 100.0% · 0 false-masked characters.
Microsoft Presidio + spaCy pt
Recorded example · offline PythonRecorded offline for this exact example. Not live inference.
User: Meu CPF é 123.456.789-09. O pedido 448231 foi cobrado em R$ 150,00. Agent: Vou consultar o pedido.
Redacted text
User: Meu CPF é 123.456.789-09. O pedido 448231 foi cobrado em R$ 150,00. Agent: Vou consultar o pedido.
This example only: character F1 0.0% · recall 0.0% · 0 false-masked characters.
Reference labels
Hand-labeled synthetic examples, scored on names, e-mails, phones, CPFs and addresses, as in the benchmark; order numbers and amounts are not scored. Character F1 measures overlap, not general model accuracy. Editing the text removes example scores and recordings.
The Wiv model and inference code are not downloaded to your browser.
Wiv runs on our server at threshold 0.5 when you click Run filter. OpenAI and Microsoft Presidio show recorded outputs for the four examples; editing the text hides them.
Conclusion
This is the first version of w-privacy-filter. We built it because we needed to mask personal data in Portuguese conversations between customers and businesses, and the models we tried were either too slow and expensive to run on every message or not accurate enough on this kind of text. The current model is a few megabytes, runs on a single CPU core and was the fastest locally timed system in our comparison. Google DLP is a cloud API: every message has to be sent to Google before it is masked. w-privacy-filter matches it on our one conversational benchmark and is close or ahead on the others, inside our own process, so the conversation never leaves our infrastructure to be masked.
In the next version, we will focus on lowering the error rate further without losing accuracy or speed, or using more resources. If you have questions or work on similar problems, write to us at product@wiv.com.br.
Notes
- Character F1 gives partial credit when only part of a value is masked. BR-Agentic has only 41 synthetic chats, and the F1 confidence intervals overlap. Asked only for the ten categories DLP was asked for, Wiv scores 94.9 on BR-Agentic, 83.1 on LGPD-Carolina, 96.3 on LeNER-Br and 85.9 on the PTBR holdout, mainly because it no longer masks categories outside that list. ↩
- Some models were trained or validated on the legal and synthetic distributions. None of the public sets were used to train Wiv, but all four, the PTBR holdout included, were scored while we developed this model, and two of those runs informed design decisions. We chose the final recipe on a separate private panel. ↩
- Checks against the official OpenAI runtime are in the technical report. The chart uses our CPU adaptation, not that runtime. ↩
- Throughput uses the same 20 public texts and one CPU thread. First-pass rates were about 168,000 and 50,000 characters/s for Wiv and Microsoft Presidio; repeated-input caches explain part of the advantage. Wiv was timed while the machine was in use, which can only lower its rate. These are CPU throughput figures, not production latency measurements. ↩
References
- Wolpert (1992). Stacked generalization. Neural Networks 5(2). ↗
- BR-Agentic PII Benchmark ↗
- Synthetic LGPD corpus ↗
- Luz de Araujo et al. (2018). LeNER-Br: a Dataset for Named Entity Recognition in Brazilian Legal Text. PROPOR. ↗
- Portuguese PII benchmark and models by arthrod ↗
- Google Cloud Sensitive Data Protection infoType reference ↗
- Zaratiana, Lewis and Hurn-Maloney (2026). GLiNER2-PII: A Multilingual Model for Personally Identifiable Information Extraction. arXiv:2605.09973. ↗
- de Bourcy et al. (2026). Model Card for OpenAI Privacy Filter. arXiv:2608.18274. ↗
- Microsoft Presidio supported entities ↗
- de Almeida, Botega and Lima (2026). Local Anonymization of Free-Text Robbery Police Reports in Brazilian Portuguese. KDMiLe. ↗
- Zhang et al. (2026). PII-TRACE: A Benchmark for Context-Aware PII Detection in Multi-Turn LLM Conversations. arXiv:2609.22200. ↗