Google Jobs Scraper: Salary, Apply Links, ATS Detection avatar

Google Jobs Scraper: Salary, Apply Links, ATS Detection

Pricing

from $3.15 / 1,000 jobs

Go to Apify Store
Google Jobs Scraper: Salary, Apply Links, ATS Detection

Google Jobs Scraper: Salary, Apply Links, ATS Detection

Google Jobs listings (title, company, salary, job type, description, every apply link) by keyword and location; $8.10 per 1,000 jobs. $3.15 on Business plans, 60-150 jobs per search, the company's ATS board detected. SerpApi input names accepted, free error rows.

Pricing

from $3.15 / 1,000 jobs

Rating

0.0

(0)

Developer

Arcadium Data

Arcadium Data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 hours ago

Last modified

Categories

Share

Google Jobs Scraper: Salary, Apply Links, ATS Detection

Give it job searches ("software engineer", "registered nurse") and places ("Seattle, WA", "Berlin"), and it returns one JSON row per Google Jobs result: title, company, location, posted date, salary (as shown and parsed), job type, full description and every apply link Google lists. $8.10 per 1,000 jobs on the Free plan, $3.15 on Business plans and above; you pay only for rows you get.

Why this actor

  • The company's own ATS posting is picked as the best apply link, with the ATS and board detected.
  • Goes past Google's 10 jobs per page to 60-150 jobs per search, with Google's own filters.
  • SerpApi parameter names (q, date_posted, employment_type, gl, hl, num_pages) and these field names are also accepted: query, location, jobType, maxResults, maxPagesPerQuery, remote.
  • No login; recruiter names, emails and phones are never output. Empty searches are free rows.

Built by Arcadium Data: public data, dated and agent-ready, never personal data.

Use with AI agents

The actor takes plain JSON and returns one flat row per job, so an AI agent or MCP client (for example through mcp.apify.com) can call arcadium/google-jobs directly. Input example for "Data analyst jobs in Austin posted this week":

{ "queries": ["data analyst"], "locations": ["Austin, TX"], "datePosted": "week" }

"Remote part-time customer support jobs, up to 50, short descriptions for an LLM":

{ "queries": ["customer support"], "remoteOnly": true, "employmentTypes": ["PARTTIME"], "maxResultsPerQuery": 50, "maxDescriptionChars": 600 }

"Nursing jobs in three German cities, in German, with the company's applicant tracking system detected":

{ "queries": ["Pflegefachkraft"], "locations": ["Berlin", "Hamburg", "München"], "country": "DE", "language": "de", "jobsDbExport": true }

Read title, companyName, location, postedAt, salary, employmentTypes and applyUrl; description holds the job text. The same posting found by two searches comes once (jobId). 100 jobs cost $0.27. A search that finds nothing or cannot be read comes back as a free row with rowType: "error", a code (no_match, blocked, unavailable, invalid_input) and a message, never as a failed run, so an agent can tell "no jobs" from "try again later".

What you get

FieldWhat it holds
jobIdGoogle's id of the posting, stable across searches and runs (use it to dedupe).
title, companyName, locationJob title, hiring organisation and place as Google shows them.
viaSite Google read the posting from (LinkedIn, Indeed, the company's career site, ...).
postedAgo, postedAtAge as shown ("3 days ago") and the approximate date it gives (2026-10-19).
salaryText, salarySalary as shown and parsed: min, max, currency, period (hour, year, ...).
employmentType, employmentTypesJob type as shown and normalised (FULLTIME, PARTTIME, CONTRACTOR, INTERN, TEMPORARY).
qualification, workFromHomeGoogle's qualification chip ("No degree mentioned") and its work-from-home flag.
description, descriptionCompleteThe job description, and whether it is the full text or Google's preview.
applyUrl, applyOptionsBest apply link (the company's own ATS posting when listed) and every apply option with site, URL and detected ATS.
googleJobsUrlLink that opens the posting in Google Jobs.
searchText, query, searchLocation, positionThe exact text sent to Google, your query and location, and the rank.
jobsDbWith jobsDbExport: ATS, board, ATS posting id, clean apply URLs, fingerprint (see below).

Output example:

{
"rowType": "job",
"platform": "google-jobs",
"jobId": "d6Zuw_TVelot7iRuAAAAAA==",
"title": "Software Development Engineer, Network Monitoring and Remediation (NMR)",
"companyName": "Amazon Web Services, Inc.",
"location": "Seattle, WA",
"via": "Indeed",
"postedAgo": "5 days ago",
"postedAt": "2026-10-17",
"salaryText": "$144K–$194K a year",
"salary": { "min": 144000, "max": 194000, "currency": "USD", "period": "year", "source": "structured" },
"employmentType": "Full-time",
"employmentTypes": ["FULLTIME"],
"qualification": null,
"workFromHome": false,
"description": "DESCRIPTION\n\nAmazon's network carries traffic for hundreds of millions of customers ...",
"descriptionComplete": true,
"applyUrl": "https://www.indeed.com/viewjob?jk=917ad7a1f42a4176&utm_campaign=google_jobs_apply&utm_source=google_jobs_apply&utm_medium=organic",
"applyOptions": [
{ "source": "Indeed", "label": "Apply on Indeed", "url": "https://www.indeed.com/viewjob?jk=917ad7a1f42a4176&utm_campaign=google_jobs_apply&utm_source=google_jobs_apply&utm_medium=organic", "domain": "indeed.com", "ats": null },
{ "source": "LinkedIn", "label": "Apply on LinkedIn", "url": "https://www.linkedin.com/jobs/view/software-development-engineer-network-monitoring-and-remediation-nmr-at-amazon-web-services-aws-4480587462?utm_campaign=google_jobs_apply&utm_source=google_jobs_apply&utm_medium=organic", "domain": "linkedin.com", "ats": null }
],
"googleJobsUrl": "https://www.google.com/search?ibp=htl;jobs&q=software+engineer+jobs+in+seattle&htidocid=d6Zuw_TVelot7iRuAAAAAA%3D%3D",
"searchText": "software engineer in Seattle, WA",
"query": "software engineer",
"searchLocation": "Seattle, WA",
"position": 2,
"language": "en",
"country": "US",
"scrapedAt": "2026-10-22T08:00:00.000Z"
}

Input

{
"queries": ["software engineer", "product manager"],
"locations": ["Seattle, WA", "New York, NY"],
"datePosted": "week",
"employmentTypes": ["FULLTIME"],
"maxResultsPerQuery": 30
}
FieldWhat it does
queriesWhat to search, as typed into Google ("software engineer", "barista part time").
locationsPlaces; each query runs once per location ("software engineer in Seattle, WA"). Empty = the whole market.
datePostedany, today (since yesterday), 3days, week, month.
employmentTypesFULLTIME, PARTTIME, CONTRACTOR, INTERN; several = one search each, merged.
remoteOnlyGoogle's Remote filter.
maxResultsPerQueryJobs per query and location (default 10 = one Google page, up to 200).
maxItemsStop after this many jobs in total. A cost cap.
country, languageGoogle market and interface language, e.g. DE + de, IN + en, BR + pt-BR.
includeDescription, maxDescriptionCharsJob text on or off, and an optional length cap.
jobsDbExportAdds the jobsDb merge fields.
includeErrorRowsA free row for every search without jobs (on by default).

SerpApi parameter names and these input field names are also accepted as they are (query, q, location, date_posted, employment_type, jobType, gl, hl, maxResults, maxPagesPerQuery, num_pages, remote).

Google shows 10 jobs per search and loads the rest only inside its own page script. With maxResultsPerQuery above 10 the actor also runs the filter variants Google itself offers on the page (each job type, then narrower date windows, then both) and merges them without duplicates. A broad search ("software engineer in Seattle") reaches 60-150 jobs this way; a narrow one stops as soon as the variants stop adding new jobs. searchText on each row says which variant found it. You pay per job delivered, never per page.

Job-board merge fields (jobsDbExport)

Many Google Jobs postings link to the company's own applicant tracking system. With jobsDbExport: true each row gets a jobsDb object:

FieldWhat it holds
ats, boardToken, boardKeyATS (greenhouse, lever, ashby, workable, smartrecruiters, recruitee, personio, teamtailor, workday) and the company's board on it.
atsJobId<ats>___<posting id>, the same id our Career Site Jobs scraper gives that posting, for joins.
atsUrl, applyUrlsThe ATS posting URL and every apply URL, without tracking parameters.
fingerprintsha1 of company, title and location (lower case), to match the same job across aggregators.

Use it from code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("arcadium/google-jobs").call(run_input={
"queries": ["machine learning engineer"],
"locations": ["London"],
"country": "GB",
"datePosted": "3days",
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item["rowType"] == "job":
print(item["companyName"], "|", item["title"], "|", item["salaryText"], "|", item["applyUrl"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('arcadium/google-jobs').call({
queries: ['electrician'],
locations: ['Phoenix, AZ', 'Dallas, TX'],
maxResultsPerQuery: 40,
jobsDbExport: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.jobsDb?.ats).length, 'jobs link to a company ATS');

Pricing

You pay per job delivered, at the price of your Apify plan. Error rows and repeats (the same job found by another search) are free.

Apify planPer 1,000 jobs
Free$8.10
Starter (Bronze)$4.05
Scale (Silver)$3.60
Business (Gold)$3.15
Platinum$3.15
Diamond$3.15

Plus a one-off $0.001 per GB of memory when a run starts. Descriptions, apply links, salary parsing and the job-board fields are included.

Set a maximum cost per run in the Apify run options and the actor stops before it goes over.

Use cases

  • Job market and salary research: who is hiring for a role, where, at what pay, by job type.
  • Recruiting, sourcing and sales: companies hiring for X (a buying signal), with links to their career sites.
  • Job boards and aggregators: fresh postings with full text and every apply link, deduplicated by jobId.
  • Joining with ATS data: jobsDbExport gives the company's Greenhouse, Lever, Workday ... board and posting id.
  • AI agents: "open jobs for X in Y this week" as clean rows.

Limitations

  • Google shows 10 jobs per search. Past that, coverage comes from Google's own filter variants, so the total per search is what those variants list (typically 60-150 for a broad search), not every job Google has.
  • Results, ranking and the location area are Google's. A location is sent the way you would type it ("in Seattle, WA"); a very small place may return jobs from the surrounding area.
  • Some markets show only a preview of the description (about 400 characters, descriptionComplete: false); the full text is on the apply links.
  • Salaries are what Google shows; many postings have none.
  • Labels such as "3 days ago" follow language; postedAt, employmentTypes and salary.period are normalised for en, de, fr, es, it, pt and nl.

Privacy

Public data only: Google Jobs results as an anonymous visitor sees them. No login, no account, no cookies. Company names are organisations; recruiter names, emails and phone numbers are never output: emails and phone numbers in descriptions are replaced with [email] and [phone], and greetings that name a person are removed.

FAQ

Why do I get fewer jobs than maxResultsPerQuery? Google had no more for that search: its page and filter variants stopped adding new jobs. Broaden the query or the location, or add more locations.

Why is a search an error row with code no_match? Google Jobs listed nothing for it ("It looks like there aren't any Jobs matches"). Check the spelling or broaden it. It is free.

Can I search any country? Yes: set country (and language for local labels), e.g. "country": "IN" or "country": "DE", "language": "de".

Something looks wrong in the output. Who do I tell? Open an issue on the actor page with the run link. We read them all.