Academic Matchmaker
How I built a private, in-browser search that matches a CV against 181,568 researchers at the world's top 200 universities. Covers fitting the index into a static site, semantic matching with a small model, and why concept tags had to come next.

- Researchers indexed
- 181,568
- Universities (QS 2026)
- 200
- Per person, per vector
- 48 bytes
- Servers to run
- $0
Choosing a PhD or postdoc advisor is one of the biggest decisions in an academic career, and it is still done by hand. Students read faculty pages one university at a time, guess at fit from paper titles, and cold-email people whose research moved on years ago.
The Academic Matchmaker turns that into a search problem. You drop in a CV, a paper or a Google Scholar screenshot, and it ranks researchers across the top 200 universities by how closely their recent work matches yours. Two constraints shaped every decision:
- Nothing you upload leaves your device. Text extraction, the language model and the matching all run in the browser.
- No servers. The site is static files on GitHub Pages. The data is rebuilt by GitHub Actions and served from a Hugging Face dataset.
Those two constraints are what make this build interesting. Fitting 181,568 researchers into something a browser can search in a second or two took a series of storage and ranking decisions. They are worth writing down because the same moves apply to any retrieval system with a tight budget.
The three parts
Part 1 covers the problem and the architecture. Part 2 is the data pipeline and storage: how 200 universities of OpenAlex data are ingested under a free API budget and squeezed from about 280 MB of vectors down to under 9 MB. Part 3 is matching: the small model in the browser, coarse-to-fine vector search, why pure semantic matching was not enough, and the concept tags and laureate test set that fixed it.
3 parts
- Part 1A private research matchmaker that runs entirely in the browserOct 28, 2026 · 3 min
- Part 2Fitting 181,568 researchers into a static websiteOct 28, 2026 · 4 min
- Part 3Semantic matching in the browser, and why it needed concept tagsOct 28, 2026 · 5 min