Google Jobs API
Query Google's postings through one API with ?source=google — plus why the board hides in an AF_initDataCallback blob and every field is addressed by number.
Google is not a platform. Every multi-tenant source here is software that hosts
many employers' boards — one Greenhouse adapter reaches every
company on Greenhouse. This one reaches Google, and only Google. company is
ignored, because there is exactly one.
It's here because Google is large enough for its jobs to matter on their own, and because it runs a bespoke careers site rather than buying an ATS — so no platform adapter will ever discover it. If you want Google's postings, you write an adapter for Google and you own it forever.
We wrote it: query it with ?source=google.
/v1/meta is the authoritative live vocabulary, with
the current count per source.
How Google Careers actually works#
No browser, no auth, and — pleasantly — no per-job N+1. The results page
server-renders each page of jobs into the HTML as a JavaScript callback, and
?page=N walks it twenty jobs at a time:
curl "https://www.google.com/about/careers/applications/jobs/results/?page=1"Buried in that HTML is a blob:
AF_initDataCallback({ key: 'ds:1', data: [[…jobs…], …, 3202], sideChannel: {} });data[0] is the page of jobs, data[2] is the whole-board total. Page 1 carries
the total and the rest of the pages fan out in parallel. Each record already holds
the full description — overview, responsibilities and qualifications inline — so
there is nothing to fetch twice.
The old search API is gone
Google's /api/v3/search — the clean JSON endpoint most write-ups still point
at — is dead (404). And it wouldn't help if it weren't: that per-keyword
search capped out around 2,000 results. The no-query listing paginates the
entire board with no such cutoff (measured: ~3,200 unique jobs to page 166).
Every field is addressed by number#
The ds:1 record is a positional array, not an object. There are no keys — you
read a job by index, and the indices are Google's, not yours:
[0] id [1] title [3] responsibilities [4] qualifications
[9] locations [10] overview [14] published (unix seconds) [20] levelSlot [20] is Google's target_level, decoded against the site's own
?target_level= facet: 1 early, 2 mid, 3 advanced, 5 intern. It's the one
field that gives you seniority, and a few short records don't carry it at all.
What bites you#
A shifted index mismaps silently, and nothing throws
Because the record is positional, there is no field name to disagree with. The
day Google inserts one element and the description slides from slot [10] to
[11], your titles are fine, your ids are fine, and every body is quietly wrong.
A named JSON field that vanishes reads null or throws; a reshuffled array keeps
returning strings — just the wrong ones.
A throttled page looks like a shrunken board
Google is a complete-return source: the live set — and therefore what expires — is derived from what the scrape returns. So a run that loses pages to throttling looks exactly like a board that shrank, and would expire every job it failed to fetch. The guard is to throw (and retry) when the run comes back with less than 70% of Google's own reported total, rather than bank a decimated board. Fetch the whole thing or fetch none of it.
The data lives in page markup, not an API. It's extracted with a regex over the
AF_initDataCallback(...) blob. That's robust enough today and brittle by nature:
markup is not a contract.
No structured salary. Nothing in ds:1 carries comp; whatever pay exists is
prose inside the qualifications HTML.
Or use ours#
Pagination off a total buried in a JS callback, a positional array read by index,
seniority decoded from a facet, and a completeness guard that refuses to expire a
throttled board — with Google's rows in the same Job shape
as every other source, dedup against the same role on
LinkedIn, and the adapter's upkeep being ours instead of yours.
Same deal as Amazon, Apple, Uber,
TikTok, Microsoft and IBM.
Every source above normalises onto the same schema, with the hiring company already joined onto each posting.
Get an API key