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.
Register, verify by one-time code, login, refresh, logout and a current-user endpoint, layered routes to service to dao so the rules stay testable with no database and no running app. Codes are HMAC hashed with a server-side pepper before they reach Mongo, and the row keeps only a user id: an email copy and a stored expiry are both facts the users collection already owns, so expiry is derived from last sent, which is the same field the TTL index deletes on. Tokens carry a type claim that decoding checks, so a refresh token cannot be replayed as an access token, and they only ever travel in httpOnly cookies. Passwords are argon2id and deliberately never trimmed, since trimming one silently changes the credential someone typed.
SMTP delivery derives from the environment: console in development, where the whole message lands in the log so signup works with no mail server, and real delivery in production, which refuses to start on console mode, a local mail catcher host, missing TLS, absent credentials, or a missing code pepper. That last check is not cosmetic, without a shared pepper every worker hashes codes differently and verification fails at random. Rate limiting surfaced its own trap: with headers enabled a limited route must also accept the response object, or it raises on the first request rather than at import.
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.
Milo is in private beta. Leave your email and we’ll send one message when tracking links open up, no drip sequence, no newsletter.