Contact Cleaner
September 20, 2026 · View on GitHub
Clean your Google “Other contacts” in a few minutes.
Google quietly saves everyone who ever emailed you: newsletters, robots, shared inboxes, student IDs, spam, and a few real people. Contact Cleaner reads the list Google exports, asks TypeSafe’s Jev model a fixed set of questions about every address, and sorts them into three piles:
| Pile | What lands here | What you do with it |
|---|---|---|
| Keep | Real people | Download as a Google CSV and import it into Contacts |
| Review | The AI was not sure | Skim and drag rows to Keep or Remove |
| Remove | Newsletters, robots, shared inboxes, student IDs, spam | Download the list and delete them in Google |
No account, no database. Your contacts live in your browser tab only. For each contact, just the name and email address travel to the server, which asks the AI and forgets them.
1. Export your contacts from Google
- Open contacts.google.com and click Other contacts in the left menu.
- Tick the checkbox at the top of the list, then choose Select all.
- Click the three dots → Export → choose Google CSV → Export.
Google downloads a file called contacts.csv. That is the file you upload.
2. Use the app
Open the app, drop contacts.csv on the page, and press Start cleaning. You will see:
- how many rows and duplicates were found,
- a progress bar with elapsed time and the AI cost so far (a 4,700-contact file costs well under a dollar),
- a live count of Keep / Review / Remove.
When it finishes you get a table you can filter, sort by confidence, group by domain (to remove an entire university or spam domain in one click), and drag rows between piles. Then download:
- Keep as Google CSV — same columns as Google’s export, so it re-imports cleanly. Rows get the label
Cleaned by Contact Cleanerand land in your main Contacts list. - Remove list — a plain list of emails to find and delete in Google.
- Full results — everything, including every probability, for your records.
What does “confidence” mean? How sure the AI is about the kind of sender. 100% means all its weight was on one answer; a low number means it was torn between several, so the row goes to Review.
Optional: before you start, type your own yes/no question in the box (for example “Is this person likely based in Israel?”). The answer shows up as a probability in its own column.
3. Deploy your own copy (one click)
You need two things: a free Vercel account and a TypeSafe key.
- Get a key at console.typesafe.ai/settings/keys. Copy it.
- Click the button below. Vercel will copy this project and ask for one value.
- Paste your key into the field named
TYPESAFE_API_KEYand press Deploy. Two minutes later you have your own URL.
Adding or changing the key later
In Vercel: open your project → Settings → Environment Variables → add Name TYPESAFE_API_KEY, Value = your key, tick all environments → Save. Then open Deployments → ⋯ on the latest one → Redeploy.
If you leak the key, regenerate it in the TypeSafe dashboard and paste the new one in the same place.
Using Vercel AI Gateway instead
If you would rather bill through Vercel, leave TYPESAFE_API_KEY empty and set AI_GATEWAY_API_KEY. The app then calls Jev through the Vercel AI SDK’s experimental_evaluate with the model typesafe-ai/jev.
For the curious: how it decides
- Deterministic first. Code computes facts Jev is bad at: digit counts, name-in-email checks, how many contacts share a domain, free-mail and disposable lists, role-word patterns. Only those facts, plus the name and email, are sent.
- One call per contact. Every question is asked in that single call: what kind of sender is this, does the name look like a real person, what kind of domain is it, does it look like a professional contact, plus your optional question.
- Buckets are code, not the model.
lib/jev-questions.tsis the only file with question text and thresholds. Change a threshold there and nothing else needs to move.
Run locally
npm install
cp .env.example .env.local # paste your key inside
npm run dev
Check accuracy on labeled rows
eval/labeled.csv holds real rows with the bucket a human expects. Run:
npx tsx scripts/eval.ts
It prints accuracy per bucket, a confusion table, every row where confidence and correctness disagree, and what accuracy would be at other confidence floors. Pass --floor 0.6 to try another floor or --source path/to/contacts.csv to compute domain counts from a full export.
Privacy
Contacts never leave your browser except the name and email fields going to the server route, which forwards them to TypeSafe and discards them. Nothing is stored and nothing is logged.