What this does not achieve
Nothing is kept, all ten Australian recognisers are on, and the confidence floor is 0.20 β the strictest setting this tool supports. What that still leaves: non-Latin-script names recall ~13.7% and names have no checksum, so no deterministic rule can close it; the checksum rules over-redact (~1 in 10 random ten-digit numbers pass the Medicare check); no indirect or inferential identifier is handled, so a rare condition plus a suburb can re-identify someone even when both are redacted; and detecting an IHI is not the same as being permitted to process it, which is a Healthcare Identifiers Act 2010 question rather than a Privacy Act one. Under the Privacy Act, de-identification is a judgement about re-identification risk in context, which a token classifier cannot make. Health information is sensitive information: treat this as a first pass with human review, and do not represent its output as de-identified data.
Documented limits, worth knowing before you trust it
Non-Latin-script names recall ~13.7% (Cyrillic 2.4%, Arabic 4.8%, Han 8.8%). Government-style identifiers have no checksum backstop and the model catches ~67.6% of them. Zero-width-split digits and PII-embedded prompt injection are known misses. The model does not treat dates or ages as PII: the Dates recogniser in the Australian layer covers the common date formats, ages are not covered. Headline private-term recall is 98.42% across seven Latin-script languages β i.e. roughly 1 term in 64 slips through. Treat output as harm reduction, not a compliance guarantee, and review anything before it leaves your control.
Which settings should I use?
For most people, the defaults. Here is when to change them.
- Checking some text you are about to paste somewhere
- Single text + WASM. Leave the policy alone.
- A file, or a folder of files
- Batch files + WASM. Keep field context on. To preserve a CSV column, untick the column β do not rely on the keep-set, which is unreliable on bare cells.
- One long document, interactively
- WebGPU is ~2Γ faster on documents of a few thousand characters (293 ms vs 566 ms here), but the first run pays a one-off shader compile of tens of seconds. Not worth it for short text or batch, where WASM is actually faster.
- You only want the checksum-verified identifiers, instantly
- Deterministic layer only. No model, no wait β Medicare, IHI, TFN, ABN, card, SSN, email, URL, IP.
- You want to see what the vendor's pipeline does
- Vendor default: keeps city / state / postcode, floor 0.40, AU recognisers off. Useful for comparison; not the posture to de-identify with.
- Your data has an identifier this tool does not know
- A medical record number, a UR number, an internal code: add a custom pattern. Ask an AI assistant to write the regex for you with the prompt provided.
- You are de-identifying data for real
- Stay on Strict, and read what this does not achieve.
The settings, one by one
Labels to keep
Default-deny: every detected span is redacted unless its label is kept. This app keeps nothing by default. The upstream model ships a keep-set of city / state / postcode for eligibility checks, but OAIC de-identification guidance treats geography as a quasi-identifier β suburb plus postcode narrows a population sharply, and postcode with a date of birth is the textbook re-identification vector β so the stricter posture is the default here.
In the label grid, a dot marks the classes the deterministic layer owns. Those are matched by regex and a check algorithm and premasked before inference, so a model guess cannot overrule them. The rest come from the model and are subject to the confidence floor.
Australian recognisers
The upstream validator layer is US-shaped β SSN structural rules, Luhn for cards β so these fill the AU gaps: Medicare, IHI / HPI, TFN, ABN / ACN, provider, DVA, passport, BSB, phone and date coverage. All are regex rules emitted at score 1.0 and premasked before the model exactly like the built-in classes; the checksum tier also runs a published check algorithm.
Tiers are labelled because they are not equally trustworthy. Checksum-verified means a published check algorithm must pass; structural means no checksum exists but the shape is unambiguous in AU text; keyword-anchored means a nearby keyword carries the precision. A checksum bounds false positives only to roughly 1 in 10 for a random number of exactly the right length (Medicare, ACN), 1 in 11 (TFN) or 1 in 89 (ABN), so expect occasional over-redaction of reference and account numbers. That is the intended trade.
Confidence floor
Model spans scoring below the floor are dropped. The upstream default is 0.40; the default here is 0.20, since lowering it can only add redactions. Measured caveat: this slider is close to inert. Span-level aggregation only emits confident spans β over a 104-span document at floor 0, the lowest score was 0.768, and nothing scored under 0.40 β so dropping the floor adds nothing. The real gaps are unmodelled classes, not thresholds. Do not treat it as a safety dial.
Premask structured IDs
On by default, and the shipped behaviour. Identifiers that a regex and a check algorithm can verify are replaced with sentinels before the text reaches the model, which is how the model was trained β so it never sees raw card or SSN digits. The Model input tab shows exactly what it receives.
Deterministic layer only
Skips the model entirely. Results are instant and cover only what regex and checksums catch: Medicare, IHI, TFN, ABN, card, SSN, email, URL, IP. Names, street lines and free-text identifiers are missed, so this is a comparison tool rather than a safe mode.
Backend: WASM or WebGPU
Measured in this app on an Apple Metal-3 adapter, not taken from the model card. WASM is the better default. WebGPU wins on long text β roughly 1.9Γ on a 3.4k-character document β but it has a floor of about 30 ms per call regardless of input size, so WASM wins on short text and across a batch of short cells. WebGPU's first run is brutal: ONNX Runtime Web compiles shader programs per input shape, and the first detection after initialising cost ~36.7 s on the long document versus well under a second on WASM. WebGPU init also failed on one of three attempts here and fell back to WASM automatically.
Interview transcripts
A research interview exported from Loom, Teams or Zoom is a run of lines shaped
00:41 Speaker label: what they said. Switch on Interview transcript under the text box
(it switches itself on when you paste one) and the tool handles the three things that leak most in
interviews, with nothing to set up per interview.
What it does
Speaker labels become roles, and it never guesses. A label that matches someone on your team list
gets their role. A meeting-room device label (one with VC, Room or an office
code in it) becomes Magentus team: everyone in the room shares one microphone, so the transcript
cannot tell them apart. The transcriber's Unknown user becomes Unknown speaker. Once the
team side is known, everyone else is Participant (a second one, Participant 2, is flagged
for you to confirm). If the team side is not known, the rest stay neutral as Speaker 1,
Speaker 2 until you pick their roles in the Check tab. A wrong role would put a quote in the wrong
mouth in every summary written from the transcript, so the tool leaves the decision to you.
Names in a label are removed everywhere. A participant's display name ("Dr Surname/Practice Accounts") is mined for names before it is replaced, and every mention of those names in the body is removed too: any case, possessives, and near-miss spellings of longer names. An all-capitals token in the label is treated as a practice abbreviation. Your team list's names are removed from the body the same way.
A name found once is removed every time. When the model finds a name on one line, every other capitalised mention of that word is removed too, and a detection that stops half-way through a word is widened to the whole word.
Product names are kept and corrected. Speech-to-text spellings such as Gen 2, Gentoo, ConsentTick
or Co-View become Gentu, Consentic and CoView, and those names are never redacted. The list lives in
src/interview.js.
The Check tab
Lists the lines to read again, by timestamp: a word the model thought might be a name but scored below the confidence floor, a social-media or close-family mention, and anything said by an unknown speaker. It shows the redacted line, never the original. It is a reading list, not a guarantee: a name the model never suspected and that is not in a speaker label can still get through, so read the whole result before you share it.
The team list
Under Adjust, Interview team: one person per line as name = role, for example
Alex Smith = Researcher. It fills itself: picking a team role in the Check tab adds that person.
It is saved in this browser only, and a participant is never added to it.
Custom patterns
The built-in layers know nothing about identifiers that are specific to your organisation: a medical
record number, a UR number, an appointment or claim reference, an internal project name. A custom pattern
closes that gap. You give it a label and a regular expression, and every match is removed at score 1.0,
premasked before the model exactly like the checksum rules, and replaced with a reversible placeholder
such as [MRN_1]. Custom patterns apply to single text and batch files alike, and their counts
appear in the audit report under your label.
Getting an assistant to write the regex
Most people should not hand-write a regular expression. Open Adjust, find Custom patterns, and press Copy a prompt for Copilot or Claude. Paste the prompt into Copilot, Claude, ChatGPT or whichever assistant you use, replace the placeholders with a description of the identifier and two or three invented examples, and paste the pattern it returns into the Pattern field. The prompt already states the constraints this tool needs: JavaScript syntax, no surrounding slashes, the whole match is removed, never an empty match.
Describe the shape, do not paste real records. "Eight digits after the letters UR, sometimes with a space" is enough. A real patient's identifier does not belong in a chat with an assistant, whichever assistant it is. Then check the live preview under the form against your own text before you add the rule, and look at the Detected tab afterwards: a pattern that is too broad over-redacts, and a pattern that is too narrow silently misses.
Rules and limits
Labels are upper-case letters and underscores, because that is the shape the placeholder reverser looks
for. Anything else is normalised (ur number becomes UR_NUMBER), and a built-in
label cannot be reused. Case-insensitive matching is a switch; the global flag is always on. A pattern
that can match an empty string is rejected, and a pattern that matches more than 5,000 times in one
document stops there, so a runaway regex degrades to partial redaction rather than a hang. Patterns are
stored in this browser's local storage so they survive a reload. Nothing leaves the device, but if a
pattern contains a real value, remove the rule when you finish on a shared machine.
Batch files
CSV / TSV are redacted cell by cell in the columns you select; TXT, Markdown and logs are redacted as a whole document; JSON and JSONL have their string values rewritten. Anything with an unrecognised extension is treated as plain text. Files are read with the File API and redacted in this tab β nothing is uploaded.
Field context, and why it matters for CSVs
The model was trained on chat-style sentences, and a bare cell has none. Without context 3053
labels as a phone number rather than a postcode, and VIC labels as a given name. Prefixing
the column name or JSON key for inference β then mapping spans back onto the value β restores accurate
labels, and lets keyword-anchored rules fire ("bsb": "083-004" is a BSB because of its key).
It does not fix everything. Bare state and suburb values stay unreliable, which has one practical consequence: keep-sets are unreliable on CSV cells. To preserve a column, untick the column rather than relying on a label being kept.
Consistent placeholders across the batch
On, one value maps to one token everywhere, so records for the same person stay linkable across files β useful for analysis, but linkability is itself a re-identification consideration. Off, each file gets its own numbering and cross-file linkage is broken.
Exports and the audit report
Exports are written as name.deid.ext with structure preserved: a CSV stays loadable, JSON
stays valid, Markdown keeps its formatting. Multiple files come back as a zip. The audit report lists
counts by label per file and deliberately contains no redacted values, so it can be kept as
evidence without undoing the de-identification.
Two format caveats. In JSON, only string values are rewritten: object keys are schema, and a number cannot become a placeholder without changing its type β so an identifier stored as a JSON number is not redacted. In CSV, unselected columns are copied through verbatim.
Placeholders and reversal
Redaction uses stable, reversible placeholders rather than a blanket [REDACTED]: the same
value always maps to the same [GIVEN_NAME_1] token for the life of the session, so a
downstream assistant can still reason about it across turns. The mapping never leaves this tab.
The Placeholders tab shows the mapping and reverses it: paste a reply containing placeholders and the real values go back in. Changing the keep-set starts a new session, because the keep-set is baked into the placeholder table when it is created.
How it works
A local front end for the Rampart client-side redaction system: a deterministic recogniser layer (regex + Luhn / SSN structural validation) unioned with a 14.7 MB q4 MiniLM-L6 ONNX token classifier, a default-deny keep-set policy, and reversible placeholders β plus the supplementary Australian recognisers and strict defaults added here. The model and the ONNX runtime download with the page from this site, and remote model loading is switched off in the runtime, so no text and no telemetry leave your device. Inference runs in a Web Worker, so a long paste does not block the interface.
Australian identifiers get their backstop from this app, not from Rampart. Switch the AU
recognisers off with Vendor default to see the difference: the Medicare number falls back to a
model guess labelled TAX_ID, the IHI is caught only because a real IHI is Luhn-valid and the
generic card rule matches it β labelling a patient identifier CREDIT_CARD β and the provider
number and date of birth are missed outright.
Benchmark Γ20 runs the full pipeline twenty times over the current input and reports
p50 / p95 for the whole path β premask, inference, projection and merge β not just inference.
Attribution
The model (nationaldesignstudio/rampart) and its runtime (@nationaldesignstudio/rampart 0.1.3) are CC BY 4.0, by National
Design Studio. All detection, span merging, policy and placeholder logic is theirs. This app adds the
browser interface, the batch pipeline, the supplementary Australian recognisers and the strict defaults.
The interface is built on the Vitality design system.