Privacy and Refunds
Short, plain-language beta policy. If something here is unclear, email [email protected].
What we process
We process the CV, job description, intake answers, and contact details you submit so we can provide the free fit scan, paid CV pack, and related delivery messages you request.
What we will not do
- We will not sell your personal data.
- We will not invent internships, employers, degrees, titles, certifications, or metrics. In the free scan that rule is written into the prompt itself. In a paid audit R5 labels every material claim; R6 cannot start unless R5 produced parseable labels, those labels are passed into its prompt, and the rewrite then faces a deterministic trace check.
- We will not guarantee interviews, offers, recruiter responses, visas, or employment outcomes.
- We will not autofill or submit any form on your behalf.
AI processing
For the free scan, PDF and TXT parsing happens in your browser first. The extracted CV text and the JD text are then sent to our Cloudflare Function, which makes exactly one request to the DeepSeek API (deepseek-v4-flash, api.deepseek.com), with a single prompt. The progress bar uses R0, R3, R5 and R7 as progress labels; they are not four separate model calls. R0 lights before any streamed model text is read, and the later labels light as the corresponding sections of the result stream back. The methodology page describes the full stage architecture used for a paid audit.
Paid deep-audit packs are built as 11 model stages (R0 to R9, plus R9b, the closing safety re-review). A blocking gate can stop the run early and hand what exists to a twelfth step, R10, which assembles the pack on our side and calls no model. The model stages use the DeepSeek API (deepseek-v4-flash, api.deepseek.com); the two writing stages, the CV rewrite and the cover letter, use Moonshot AI (kimi-k3, api.moonshot.ai). If a writing stage returns an empty completion or one of the HTTP status codes we treat as retryable on Moonshot, it is retried on DeepSeek; if a stage initially routed to DeepSeek returns an empty completion or one of the HTTP status codes we treat as retryable, it is retried once on Alibaba Cloud Model Studio (qwen), when a Qwen key is configured. A DeepSeek retry after Moonshot does not then cascade to Qwen. The customer and audit content sent to these three third-party model providers can include the CV text, JD text, earlier stage outputs and an internal audit order ID, together with the system and stage instructions needed for the call. Before submitting, redact phone numbers, national ID or passport numbers, home addresses, and anything else you do not want a model provider to process.
A paid audit keeps three things, all encrypted with AES-256-GCM: the CV, JD and intake answers you submitted, for up to 3 hours; the individual stage outputs, for up to 24 hours; and the finished pack, for up to 7 days. Expiry is not a flag. Each artifact is stored with its own expiry time. A cleanup alarm is scheduled for the next expiry, and when it fires every row then due is deleted outright. The database that tracks the audit does not store the raw CV, JD, intake answers, prompts or stage outputs. It stores SHA-256 fingerprints of the CV, JD, intake answers and stage outputs, plus encrypted-artifact references; prompts are identified by version rather than stored as text. It also stores operational metadata such as identifiers, timestamps, provider and model routes, token usage, latency, statuses, and hashed safety-gate handles. Those metadata records have no automatic expiry; we keep them for operations and accounting.
If you paste a JD URL instead of the JD text, our Cloudflare Function fetches that URL, follows redirects, extracts the visible text from the returned content, and uses that as the JD. We do not store the URL or the fetched content; only the extracted text is sent to the model along with the rest of the prompt. The request waits up to 10 seconds for the response to begin and reads at most 512 KB. It reads HTML, XHTML and plain text, and it reads a response that declares no content type at all; anything else is refused. JD pages that require login or depend on JavaScript may not yield usable text this way; paste the text instead.
The CV match panel on the jobs board parses files the same way: PDF and TXT are read in your browser, and only the extracted CV text is sent, in one request to our jobs API, together with any city, category and level filter you have set. The service builds an embedding query from up to 8,000 characters of that text. A Cloudflare Workers AI model (@cf/baai/bge-m3) embeds the query for comparison with a Cloudflare Vectorize index of live roles. We ask a second Workers AI model (@cf/baai/bge-reranker-base) to rerank them using the first 2,000 characters of the query plus a short context for each job; if that call fails, the service orders candidates by shared-term count, the original vector-recall order, then a stable job-key and title tie-break. Matching uses no other model provider, and the jobs service writes nothing at all: no database write, no storage write, and no log line carrying your text. If you carry a role from the board to the scan page, the fl.handoff record in your browser's session storage contains a version, source, timestamp, CV text, role title, employer, city and posting URL. The scan page reads it once and deletes it. When that record is loaded, the analytics event described next can include its source, whether CV text was carried and the employer name from our catalogue. The CV text, role title, city and posting URL do not go with that event; the CV text reaches scan processing only if you start a scan.
The public site uses Plausible Analytics to count visits and product interactions. For the handoff from the jobs board to the scan page, interaction events record the page language, where the handoff came from, whether CV text was carried, the employer name from our catalogue, and whether you chose Open posting or Paste the JD text here. They do not carry CV text, JD text, the role title, the posting URL or hostname, scan output, or your email address.
What gets sent to the model provider
For the free scan, we send the CV text you paste or the text extracted from your PDF/TXT, the JD text you paste, the language instruction for the result, and the product prompt that asks for the verdict, missing evidence, risky claims, one rewrite, and next step. We do not send the original file after browser parsing, and we do not send payment-card details.
What we store ourselves is narrower: no CV content, no JD content, no scan markdown, and no account record for the free scan. Here is the complete list of fields in a successful-scan record in our key-value store: an anonymous order ID and a timestamp; latency in milliseconds and an estimated cost in US dollars; the page language and the input mode; your level and target track if you set the two optional selects above the scan; the three rewrite controls and where they came from, plus, for older cached versions of this page that send slider coordinates, the two integer percentages derived from them; and the result, as a verdict word, a 0 to 100 fit score, which scoring path produced it, and the per-factor sub-scores. When the service writes a failure record for a provider, network or stream error after creating an order ID, that record contains only the order ID, a timestamp and an error-class value. If you answer the optional questions shown after the result, a second record under the same anonymous order ID stores your situation, how many applications you sent in the last 30 days, and what you find hardest. Every choice, control, score-source and error field named here is a value from a fixed list. When present, latency, the fit score, every factor score and the two legacy percentages are whole numbers; the remaining fields are a generated identifier, a timestamp and numeric cost metadata. None of these fields can hold CV text, JD text or other free text, and none is joined to your CV or JD.
To keep the free scan available there is a cap of 50 free-scan attempts per day, counted per connection and reset at midnight UTC. The counter increments after a request passes the input checks, before JD fetching or model processing, so an attempt that fails later still counts. The counter is keyed by the first 16 characters of a salted SHA-256 hash of your connection IP, stores only a number, and expires within 48 hours. Because that key is truncated, unrelated addresses can occasionally share one counter, and on shared university or office wi-fi the counter is shared with everyone behind the same address. Responses use HTTPS and cache-control: no-store.
Who else handles your data
Besides the model providers above, these companies receive data while providing the services listed here.
- Cloudflare hosts the site, the scan function, the jobs service and the paid-audit engine. Those First Landed services run on Cloudflare infrastructure.
- Stripe runs checkout. You enter your card details on Stripe's own page; we never see or store them. We send Stripe the amount, the currency, the product name, which pack and which audience you are buying, and, if you are already signed in, our internal account ID. For a guest checkout, Stripe sends back the email address you paid with, which becomes your sign-in email.
- Resend sends the sign-in email. It receives your email address, the sign-in link, and the delivery metadata needed to send it. No CV text, no JD text, no result.
- Cloudflare Turnstile checks that a human is requesting the sign-in link. The sign-in page loads its script, which receives normal web-request details. When you submit the form, your Turnstile token and your connection IP also go to Cloudflare's verification endpoint. Turnstile runs on the sign-in page only, not on the free scan.
- Fontshare and Google Fonts serve our typefaces and receive your IP address and browser details when a page that uses them loads. jsDelivr serves the PDF reader and receives the same network details when you open a PDF. None of them receives your CV, your JD, or your result.
- Plausible Analytics counts visits and product interactions, as described above.
Optional email capture
If you enter your email on the scan result, or on the CV Foundation waitlist in a JD-only breakdown, we store that email, a timestamp, the page language, and which of the two lists you joined in Cloudflare KV, so we can contact you when that thing launches. This is voluntary waitlist capture. We do not attach CV text, JD text, scan markdown, payment data, or model output to the subscriber record.
You can ask us to delete your subscriber records by emailing [email protected].
Browser-side portal prefill
When you start paid checkout from a completed free scan, your browser saves the CV text and JD text under fl_handoff_cv and fl_handoff_jd. It keeps a timestamped copy in localStorage so the portal can open from an emailed sign-in link in a new tab, plus a same-tab copy in sessionStorage. This storage handoff stays on your device and does not itself send the text to our server.
After payment and sign-in, the new-audit page reads the snapshot to prefill the paid audit form, then deletes the handoff keys. The portal accepts the localStorage snapshot for seven days and deletes an older snapshot the next time that page opens. The sessionStorage copy clears when the tab closes. Until the portal consumes it, you overwrite it with a new scan, or you clear this site's browser data, the local copy can survive a browser restart.
Your CV and JD are sent for paid-audit processing only when you submit the prefilled audit form.
Deletion requests
You can request deletion of your submitted materials by contacting [email protected]. We delete beta working files unless retention is required for payment, fraud-prevention, or legal records.
Refund policy
Checkout is automatic and self-serve. Signed-in buyers return directly to the portal, but the credit appears only after our Stripe webhook processes the payment confirmation, so the redirect can arrive first. For a guest purchase, we add the credit during that webhook and then send a sign-in link.
When an audit ends blocked for safety (blocked_safety), unable to parse safely (blocked_parse_failure) or incomplete because model stages failed (system_failed), the engine releases the reserved credit automatically so you can use it for another audit. A run that ends needing more evidence (needs_user_evidence) keeps the credit reserved; there is currently no self-serve way to release or reuse that credit. Releasing a credit is not a refund of money.
For money back, email [email protected] from the address you paid with, within 14 days of payment, and say what went wrong. If you have unused credits we refund them. If the pack you received is not what this site describes, or is clearly below the standard described here, we refund it whether or not the credit was used. Refunds are issued by hand through Stripe, to the original payment method, and we aim to reply within two business days. We do not offer rewrites or revisions; the product is the audit you ran.
Job-search outcomes are not guaranteed. Interviews and offers are between you and the employer.
Your responsibility
You are responsible for reviewing final wording before submission and confirming that every claim is accurate and defensible in interview. The engine is designed to keep claims truthful, but final ownership of submitted material is yours.
Questions, deletion requests, or refund requests: [email protected].