Inspiration

Type almost anyone's name and city into a free people-search site and you'll get their home address, phone number and relatives. People already pay services to remove those listings, but those services start by asking for your name, address and birthdate, and then you have to trust what they do with it. And when the spam and scam calls start, nobody can tell you which company your data came from.

We wanted a tool that finds where your data is exposed, points to the likely source with evidence, and gets it taken down. We also didn't want you to have to trust it: every request it makes on your behalf is shown in full.

What it does

Dossier shows you where your personal data is exposed online and which company is the likely source, then helps you get it taken down. Every request it sends to an outside service goes into an outbound log you can open, including exactly what Google's AI reads.

The browser extension (Chrome and Edge) checks the privacy of each site you visit:

  • A toolbar badge flags risky sites. There's no green "safe" light, because finding nothing isn't proof.
  • The popup shows what the site's privacy policy says it collects, sells and shares, with the exact sentence for each.
  • It lists the trackers the page loaded and the kinds of personal data its forms ask for.
  • It warns you when a policy says "we don't sell" but the page loads ad trackers.
  • It links to the site's "Do Not Sell" opt-out and offers a private email alias just for that site.

The extension never reads what you type. It sends only hostnames and fixed words like "email" or "card". The automatic check on each visit contacts no website, and only opening the popup fetches that one site's policy. Results stay in memory, because the sites you visit are your browsing history.

The website lets you scan yourself with only your name and city:

  • Exa and Tavily find your listings on people-search sites.
  • The Wayback Machine dates each listing. Every date shows its source, and a missing date says "unknown".
  • Each likely source is ranked Proven, Likely or Possible.
  • Dossier drafts the opt-out requests and re-scans to check they worked.
  • For companies you have accounts with, it shows breach timelines and policy flags.
  • One email alias per signup catches anyone who passes your address along.
  • A footprint tracker follows each removal request.

On a laptop, a threat monitor also checks your email addresses against breach data. On the public site, each account sees only its own data, and searches have a daily limit.

How we built it

  • Backend: Python 3.13 and FastAPI with async httpx and pydantic v2. PostgreSQL 16 through plain SQL holds accounts, saved scans, aliases and the footprint.
  • One door out: every request to an outside service goes through one module, outbound.py. It writes the outbound log and refuses any search query that contains a phone number, email, SSN or birthdate. We call the Exa, Tavily and Gemini REST APIs directly instead of through their SDKs, so the log captures exactly what was sent.
  • A seven-stage pipeline:
    1. Find exposures with Exa and Tavily, falling back to search snippets when a site blocks extraction.
    2. Date them with the Wayback Machine.
    3. Build breach timelines from news, date-filtered Exa searches and state attorney general notices.
    4. Check privacy policies.
    5. Rank likely sources.
    6. Find opt-out pages and privacy contacts, then re-scan.
    7. Match aliases against the inbox.
  • The AI: Google's Gemini API, with JSON output, is the only service that reads page text, policy text or breach evidence. We kept it on a short leash. It picks numbered sentences instead of writing quotes, so every quote is verbatim, and a date is kept only if the cited source contains it. Ranking uses fixed rules, not the model.
  • Threat monitor: Have I Been Pwned gets only the first 6 characters of a verified address's SHA-1 hash, never the address itself.
  • Frontend: Next.js (App Router, TypeScript). The browser talks only to our backend, through Next's /api proxy.
  • Extension: Manifest V3 in plain JavaScript, with no build step. Fixed rules check the policy, and a list of known trackers checks the page.
  • Public site: Vercel for the frontend, Render for the backend, and Neon for Postgres over TLS.
  • Tests: 301 offline pytest tests. They include checks that page text never reaches Exa, Tavily or the Wayback Machine, and that two accounts can't see each other's scans or logs.

The four of us split the pipeline by stage and kept changes to shared files additive, so we could merge often over one weekend.

Challenges we ran into

  • A local model was too slow and too loose. We started with a local LLM so page text would never leave the laptop. Each page took 30 to 90 seconds on a CPU laptop. The 8B model also reported the searched city as a street address, even with a prompt rule against it. We added code checks (an address needs a house number), skipped social sites and capped pages per site, then moved to Gemini. That traded "never leaves your laptop" for "you can see exactly what Google was sent", so the outbound log had to show it in full. The public site uses a paid key, because on the free tier Google may use what it's sent.
  • One person, many pages. A broker often has a name page, a city page and a profile page for the same person, and each one became its own card. We merged them into one card per site. The opt-out letter lists every page, and a listing counts as removed only when all of them are gone.
  • Vercel's 2-minute limit. Vercel waits at most 120 seconds for the backend. When it hung up, the scan was cancelled partway through: it had already used its searches and saved nothing. Each scan now runs as its own task that survives a dropped request, and asking again joins the running scan instead of starting a new one.
  • Antivirus broke TLS. Antivirus HTTPS scanning re-signed every connection with its own root certificate, so every Exa and Tavily call failed. We switched to the operating system's trust store and kept certificate verification on.
  • Reading policies honestly. Privacy policies are full of denials ("we do not sell..."), definitions and boilerplate that look like selling to a keyword match. The code throws those out before anything is flagged.

Accomplishments that we're proud of

  • The outbound log. It isn't a privacy promise, it's a receipt: every request Dossier made, with its exact contents, including what the AI read. The minimal-query rule is enforced in code.
  • Evidence instead of accusations. Dossier says "likely source", never "leaked by", and each tier comes with its reasons. Proven means mail sent to the alias you gave one company came from another company. Likely means the timing and the breach's scope line up. Possible means the policy allows selling or sharing.
  • An extension that respects your browsing history. The check on each visit contacts no site, calls no AI and never reads what you type.
  • "Promises that don't add up." Dossier shows a "we don't sell your data" sentence next to the ad trackers the same page loaded. California law calls passing data on for targeted ads "sharing", and a promise not to sell doesn't cover it.
  • A working public site with separate accounts, a log for each account and daily search limits.

What we learned

  • One choke point makes a privacy claim checkable. Every request goes through outbound.py, so the log can't miss one, and a test can prove that page text never reaches the search APIs.
  • Constrain the model instead of arguing with it. The model ignored prompt rules. Having it pick sentence numbers and then checking its picks in code worked.
  • Wording is part of the product. We say "likely source" instead of "leaked by" and "unknown" instead of a guessed date, and there's no green "safe" badge, because finding nothing isn't proof.
  • Local and hosted AI is a real tradeoff between speed, quality and where your data goes. If data has to leave the machine, you should be able to see exactly what left.

What's next for Dossier

  • Real alias inboxes. The demo's inbox is mocked. Next, aliases receive real mail, so Proven matches come from your own inbox.
  • Automated removal plans. Dossier would send the opt-outs for you and re-scan on a schedule to catch listings that come back.
  • More people-search sites with built-in opt-out steps.
  • The threat monitor on the public site. Today it runs only on a laptop.
  • The extension in the Chrome Web Store, so people don't have to install it with "Load unpacked".
Share this project:

Updates

Submission history