How to anonymize json for safe use in development environments
- Step 1Dump seed records from production — Export the records you want as a dev seed (enough for realistic volume) to a JSON file under the 2 MB free-tier limit, or use Pro for larger dumps.
- Step 2Load the dump — Drop the JSON file onto the dropzone. One file per run — there is no batch mode.
- Step 3List your PII keys — Edit the term list. Keep the defaults and append anything your data model adds, like
stripeCustomerId, deviceId. Remember the match is substring-based, soidwould catch every*id*key. - Step 4Pick hash for committed seeds — Choose
hashso the seed is reversible-proof yet join-stable, orremovefor fields a dev fixture should never include. Avoidfakeif your tests join on the scrubbed key. - Step 5Keep Deep enabled — Leave Deep on so nested relations in the dump (customer inside order inside cart) are scrubbed too.
- Step 6Download and wire into your seed step — Download the
.anon.jsonand reference it from your Prisma seed, Docker init script, or fixtures loader. Re-run this whenever you refresh the dump.
Strategy choice for dev seeds
Pick by what your local tooling needs.
| Goal | Strategy | Join-safe? | Notes |
|---|---|---|---|
| Committed seed, joins must work | hash | Yes | Same input → same 8-char token everywhere |
| Human-readable fixture rows | fake | No | Sequential userN@example.com, User N |
| Keep format for UI debugging | mask | Partially | Preserves length/format; not for public repos |
| Field should not exist locally | remove | n/a | Deletes the key; may break required-field code |
What Deep does to a nested seed record
Strategy: hash. Only matched keys change.
| Location | Deep on | Deep off |
|---|---|---|
| Top-level email | anonymized | anonymized |
| customer.email (nested object) | anonymized | left as-is |
| items[].buyerEmail (array of objects) | anonymized | left as-is |
| non-PII keys (sku, qty) | unchanged | unchanged |
Free vs Pro for dev dumps
Single-file processing on every tier.
| Tier | Max file | Batch | Use when |
|---|---|---|---|
| Free | 2 MB | 1 | small seed samples |
| Pro | 100 MB | 10 | full production dumps |
| Developer | 5 GB | unlimited | very large multi-table exports |
Cookbook
Patterns for turning a production dump into a safe, committable dev seed.
Hash a users seed so foreign keys still resolve
ExampleA dev seed where orders reference users by email. hash keeps the join intact after scrubbing.
Input:
{ "users": [ { "id": 1, "email": "ada@x.com" } ],
"orders": [ { "id": 9, "userEmail": "ada@x.com" } ] }
Strategy: hash · Deep: on
Output:
{ "users": [ { "id": 1, "email": "e91a77c2" } ],
"orders": [ { "id": 9, "userEmail": "e91a77c2" } ] }Remove secrets that have no place in a fixture
ExampleAdd password and apiToken to the term list and use remove so they never reach git.
PII terms: email, name, password, apiToken
Strategy: remove
Input:
{ "name": "Ada", "password": "hunter2", "apiToken": "sk_live_…", "role": "admin" }
Output:
{ "role": "admin" }Mask to keep realistic shapes during UI debugging
ExampleWhen you need a record that still LOOKS like a real user in the dev UI, mask keeps length and format.
Strategy: mask
Input:
{ "fullName": "Grace Hopper", "phone": "+1 212 555 0143" }
Output:
{ "fullName": "Gr*********er", "phone": "+1 212 555 *143" } (all but last 4 digits masked)Watch out: 'name' also catches username and filename
ExampleSubstring matching is broad. If your dump has username/filename keys you want to keep, use narrower terms.
PII terms: name
Strategy: hash
Input:
{ "name": "Ada", "username": "ada99", "filename": "avatar.png" }
Output (all three matched 'name'):
{ "name": "…", "username": "…", "filename": "…" }Reformat after anonymizing
ExampleOutput is 2-space pretty-printed. Minify it for a compact seed asset using a sibling tool.
Anonymizer output (pretty):
{
"users": [ { "email": "e91a77c2" } ]
}
→ run json-minifier →
{"users":[{"email":"e91a77c2"}]}Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
Dump larger than 2 MB on free tier
BlockedFree tier caps the file at 2 MB. A full production dump usually exceeds this — slice it to a sample or upgrade to Pro (100 MB) / Developer (5 GB).
ORM dump pasted with trailing commas
Parse errorSome hand-edited fixtures contain trailing commas or comments. JSON.parse rejects them and nothing runs. Clean it first with json-format-fixer.
fake used where the test joins on the key
Cautionfake increments a counter, so the same source email becomes user1@…, user2@… — the join breaks. For committed seeds with relations, use hash, not fake.
PII nested below a non-PII wrapper with Deep off
SurvivesWith Deep off, only top-level keys are evaluated; a profile.email two levels down is copied untouched. Keep Deep on for ORM dumps that nest relations.
remove deletes a required field
May break codeIf your dev code requires the key (NOT NULL column, required prop), remove will produce records that fail to load. Use hash or fake to keep the key present instead.
Free-text PII in a description key
Not detectedDetection never reads values, so an email inside a description string stays. Add description to the list and use remove/fake, or filter it with json-key-filter.
Stat shows fewer fields than expected after remove
ExpectedRemoved keys are not counted in 'fields anonymized'. The count reflects retained anonymized values only — a low number after a remove run is normal.
Numeric id hashed to a string
Type changeValues are stringified before hashing/masking, so a numeric userId becomes a string token. If your seed loader is strict about types, keep ids out of the PII list or cast on load.
Empty term list
DisabledAn empty PII list disables the Anonymize button. Provide at least one term.
Frequently asked questions
Is anonymized dev data safe to commit to git?
Generally yes if you use hash, fake, or remove and you review the result — confirm no real names/emails remain and that quasi-identifiers (rare values + location) can't re-identify a person. Avoid mask for public repos because it preserves length and format.
How do I keep foreign keys working after anonymizing?
Use the hash strategy. It is deterministic, so the same source value (an email or id) becomes the same token in every table, preserving joins. fake does not do this.
Can I anonymize a whole multi-table dump at once?
Yes, if it is a single JSON file under your tier's size limit. The tool walks the entire structure in one run with Deep on. It does not accept multiple files in one batch.
Does the dump get uploaded?
No. Reading and anonymization happen in your browser. The production dump is never sent to JAD Apps.
What happens to keys not in my PII list?
They are copied unchanged (recursively, with Deep on). Only keys whose names contain a PII term are altered.
Why did a non-PII key like filename get scrubbed?
Matching is substring-based: the term name is contained in filename, username, and displayName. Use the most specific terms that still cover your real PII keys.
Can I set the output indentation?
No UI control exists; output is 2-space pretty JSON. Run it through json-minifier if you want a compact seed asset.
What is the file size limit for dev dumps?
2 MB on Free, 100 MB on Pro, 5 GB on Developer. There is no row gate for this tool.
How do I strip secrets like passwords and tokens?
Add those key names (password, apiToken, secret) to the term list and choose remove, which deletes the keys entirely from the seed.
Should I use this or generate fresh mock data?
Use this when you want REAL structure/volume with PII scrubbed. Use json-mock-generator when you want fully synthetic seed records with a fixed shape.
Will remove leave the key with a null value?
No. remove deletes the key from the object entirely. To blank rather than delete, use mask or fake.
Can it scrub PII inside arrays of objects?
Yes, with Deep on. The tool maps over arrays and recurses into each object, anonymizing matched keys at every level.
Privacy first
Conversion runs locally in your browser. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.