01 · Today
Your resume already lives somewhere.
On your site, in Drive, on GitHub. Milo does not move it, copy it, or store it. It stays exactly where you put it.
Share your resume through Milo and see when it’s viewed, downloaded, and where the traffic came from.
Your resume stays where it already lives. Milo provides the analytics layer.
See how it works01 · Today
On your site, in Drive, on GitHub. Milo does not move it, copy it, or store it. It stays exactly where you put it.
How it works
Milo is an analytics layer over a file you already host. Setup is one form, and there is nothing to install.
Your site, GitHub, Drive, Dropbox, anywhere public. Milo stores the link and some metadata. It never uploads or keeps a copy of your PDF.
https://yoursite.com/resume.pdf
One short link per resume. Put a different one in each application, or add UTM tags to tell LinkedIn from a referral.
milo.app/r/abc123
Views, unique viewers, downloads, which pages held attention and for how long. Aggregate patterns, never identities.
12 views · 8 viewers · 3 downloads
Share the Milo link and every open, page turn and download is measurable. Attach the raw PDF to an email or upload it to a job portal and Milo sees nothing: a file that leaves your hands stops reporting back. Embedding a tracker inside the PDF would change that, and it is exactly the invisible tracking Milo refuses to do. So use the link in LinkedIn messages, cold emails, referrals, your portfolio and your signature.
The dashboard
Performance, sources, and per-page attention. No IP, no city, no company name, no identity, because Milo never collects them.
Example data
Resume views
12
Unique viewers
8
Downloads
3
Download rate
38%
Average reading time1m 42s
No name, no company, no location. By design.
Features
No CRM, no lead scoring, no pitch-deck analytics. Milo does one thing for people applying to roles.
Milo stores the URL and the analytics, never the document. Move or replace the PDF and the tracking link keeps working.
Separate a recruiter opening your resume four times from four different people opening it once.
Which page held someone the longest, and where they stopped reading. Deduplicated, so scrolling back does not inflate the count.
Downloads are recorded before the file is handed over, and repeat clicks within a short window count once.
UTM tags first, referrer domain second, Direct when neither is available. Honest about what it cannot know.
Sessions are anonymous and scoped to one resume. There is no identity field in the schema to fill in later.
Privacy
A recruiter opening your resume did not sign up for anything. The only honest way to build this is to collect the minimum that answers your question and nothing beyond it.
Written in plain language, without legal claims we cannot back up.
Path
Milo is early and being built in the open. Every technical and product decision lands here as it gets made, dated the day it shipped, including the quiet weeks.
Marketing shell for the app, with a story section where one beat index drives the copy feed, the figure pose and a WebGL backdrop of 54 cards rendered as a single InstancedMesh. Tokens and shared components moved into their own packages so both apps render from one source; Tailwind v4 needs explicit source globs to scan a linked package, verified against the built CSS rather than assumed.
npm workspaces for TypeScript, Poetry for the FastAPI service, and a Makefile so one command lints both languages. CI splits into parallel JavaScript and Python jobs. Prettier is fenced out of the Python package, proven by dropping an identical malformed file into each and checking only one was flagged.
Elastic License 2.0, diffed byte for byte against two official Elastic repositories rather than reproduced from memory. Third-party notices built from each dependency own license file, which surfaced that lucide-react carries ISC terms plus a separate MIT notice for Feather-derived code.
Zod validation at the boundary, rate limiting, and a honeypot that returns success so bots learn nothing. Duplicates are rejected by a unique index rather than a read-then-write check that would race. One cached client per serverless instance, and a rejected connect promise clears itself, since a memoised rejection makes a warm instance fail forever after the cluster is fixed.
Milo is in private beta. Leave your email and we’ll send one message when tracking links open up, no drip sequence, no newsletter.