back

InternOutsider

i built this because InternInsider was charging too much for what is, underneath, a list of public endpoints. every ATS a company hires through already serves its own postings over an unauthenticated API. nobody needs to pay a subscription to read them. so i wrote the thing that reads them.

it pulls from 13+ sources. the community-maintained github lists (Simplify, Pitt CSC/Vansh, and a big-tech tracker), Y Combinator's per-company job pages, a16z's portfolio jobs API, and then the applicant tracking systems directly: Greenhouse, Lever, Workday, Ashby, SmartRecruiters, Oracle Cloud HCM, and Workable. Amazon and Apple hire through their own stack rather than an ATS, so those get their own adapters. Google, Microsoft, Tesla and Meta got adapters too, and then got deleted after probing them from the deployment showed every endpoint either 404s, 403s from a datacenter IP, or only loads postings over GraphQL after render.

the interesting part is board discovery. the curated company lists capped coverage at whatever ~60 companies i had added by hand. but every posting the community feeds carry links straight at the company's ATS, and the board identifier is sitting right there in the URL, so the scraper harvests those tokens across seven platforms and then pulls each discovered board in full. a typical run finds ~510 Greenhouse boards, ~1,160 Workday tenant/site pairs, ~270 Ashby, ~170 Lever. a token found this way is verified by construction: it came off a posting a maintained feed is currently serving, so the board exists.

that doesn't fit in Vercel's 60 second function limit, so boards past the per-run cap aren't dropped, they're deferred. each run records where it stopped and the next one resumes there, wrapping around, and jobs found earlier are carried forward until three days after they were last actually seen. Workday's ~1,160 boards take about 14 runs, roughly 3.5 hours at the 15 minute refresh. phase two also runs under a hard wall-clock budget, so a slow ATS degrades to partial coverage that the next run heals, instead of Vercel killing the function and losing the whole snapshot.

there's no cron either. Vercel Hobby only allows daily crons, so instead /api/jobs checks the cached snapshot's age on every request: older than 15 minutes and that one request pays the ~15-20s re-scrape, everyone after it gets the fresh cache instantly. scraping only happens when someone's actually using the site.

each ATS stores whatever its customer typed, so normalizing is its own problem. RTX's Workday board hands over locations like `CA-ON-OAKVILLE-1400 ~ 1400 S Service Rd W`, which is unreadable and also breaks country detection, so Workday's country-region-city blocks get unpacked and street addresses dropped. the category facet had ~200 entries because every department string went through verbatim (`806-G&A ES Corp`, `Botnet`, `ZURU Toys`), so titles are now classified into 17 buckets with the more specific one winning ties. 2 of 1,607 jobs end up in "Other".

and then the part i actually enjoyed building: the site's front page isn't the job board. it's Rabbit Simulator, a carrot-clicking game. the board lives at /board and a glance at the tab, or at the screen over your shoulder at work, shows a game. click the rabbit by the burrow ten times and it unlocks; Shift+Escape anywhere on the board re-locks it and drops you back into the game. shift is required so it can't fire while you're closing a dialog with plain escape. the routing carries it too, `public/index.html` is the game and `public/board.html` is the board, so the game is just the directory index with no rewrite involved.

worth being honest about: that's a privacy screen, not access control. it keeps the board off the screen of anyone who glances at it. it does nothing against anyone who opens devtools or hits /api/jobs directly.

Node.jsExpressSupabaseVercelPlaywrightREST APIs