Privacy & data

The claim worth making is about custody, not about runtime: your resume PDF and the text extracted from it stay in your browser. Some other things do go over the network, and this page lists them.

The short version

There is no account, no login, and no upload step. The PDF is read by JavaScript in the tab you dropped it into; parsing, scoring, editing and PDF export all happen there. No request this app makes carries the PDF bytes or the extracted resume text.

What does go out: the page and its assets, a job-search keyword string when you press search, a public company name when you check a company’s own board, a job posting URL when you ask the app to fetch one for you, a GitHub star count, optional AI model weights, and — on this hosted site — anonymous product analytics.

What never leaves

One helper — src/lib/job-search/providers/keywords.ts — is the single place in the codebase where anything derived from your resume is turned into outbound data, and it is deliberately kept to one file so it can be audited in one place. Its output is described below.

Every request, itemised

1. Loading the site

Serving you the page means our host sees your IP address and user agent, the same as any website. The app is static files; there is no application server to send anything to.

2. Job search feeds

The Find jobs tab can query free, keyless, public job feeds. These requests fire only when you click “Search jobs” — not when you drop a resume, not when you open the tab, not while you edit the query. What is sent is the short keyword string built from the query’s title and skills fields, which are shown to you and editable before you search. The feeds shipped today are Remotive, Arbeitnow and Jobicy. Each is contacted directly from your browser, so each sees your IP address.

Within Find jobs, where you ask about a specific company’s own job board (Greenhouse, Lever, Ashby), the request carries that company’s public board name and nothing else. Fetching one specific posting by its URL is a different request, described next.

3. Fetching a job posting from its URL

Where the app offers to fetch a posting for you rather than have you paste it — the URL field on JD fit today — pressing Fetch calls that applicant tracking system’s own public API directly from your browser. Five are supported: Greenhouse, Lever, Workable, Recruitee and Ashby. The request fires only on that click, and nothing derived from your resume is part of it.

What it carries is the company’s public board name — which for Recruitee is the hostname itself — and, for Greenhouse and Lever, the identifier of the one posting you asked for. The other three return the whole board and the match happens in your browser. Because the call comes from your browser, that ATS sees your IP address, and for Greenhouse and Lever it also sees which specific posting you are reading. That is a sharper disclosure than anything else on this page, which is why it is worth pasting the description instead if you would rather the ATS not see you.

4. GitHub star count

The footer shows the repository’s star count via an unauthenticated call to the GitHub API, cached for about an hour. It carries no data about you beyond the request itself, and it fails silently. Because it originates in your browser, GitHub sees your IP address.

5. On-device AI model weights

The optional AI features run a language model inside your browser via WebGPU. Running it locally still means downloading it first: the weights are fetched from the public CDN that the @mlc-ai/web-llm library points at, on the first use of an AI feature, and cached by your browser afterwards. Your resume is not part of that download, and once the model is loaded the prompts built from your resume are evaluated locally.

6. Analytics on this hosted site

This site is built with a PostHog key set, so it emits anonymous product analytics — events like a file being accepted, a parse completing, or a parse failing. The payloads carry file size, page count, parse duration, the score breakdown, layout triggers and error names. They do not carry PDF bytes, extracted text, names or URLs. Session recording and autocapture are off, and the identifier is held in memory and reset when the tab closes.

This is a property of this deployment, not of the software. A build made without that key removes the analytics code entirely — the dependency is dynamically imported and is eliminated from the bundle. If you would rather not be counted, you can run your own build, or block the request.

7. Feedback, if you send it

The optional feedback panel sends a 1–5 rating, plus a category, free text and an email address only where you choose to fill them in. The email field is blank by default. It is attached as a property on that one event and is never turned into a stored profile.

What is stored in your browser

The app writes to your browser’s own storage so that state survives a reload. This is first-party and local; none of it is transmitted, and it introduces no network requests of its own. HTTP cookies are not used at all.

Browsers can clear this. Safari in particular clears script-writable storage after seven days without a visit, and any browser may evict under disk pressure. The app asks for persistent storage on first write, but that grant is best-effort, so there is a JSON export in the resume library for taking your own backup. Clearing site data removes everything above.

How to verify any of this

Do not take the claim on the strength of the sentence. Open your browser’s developer tools, switch to the Network tab, and use the app — drop a resume, edit it, export it. The requests you see are the requests there are. The source is public, and the README’s telemetry section documents the same ground in more detail than this page does.

If you find an egress path this page does not name, that is a bug in the page or the code, and it is worth filing an issue.

Open the resume parser