Google Jobs Scraper — Descriptions, Salaries, Apply Links avatar

Google Jobs Scraper — Descriptions, Salaries, Apply Links

Pricing

$3.50 / 1,000 delivered jobs

Go to Apify Store
Google Jobs Scraper — Descriptions, Salaries, Apply Links

Google Jobs Scraper — Descriptions, Salaries, Apply Links

Google Jobs scraper for US job searches: title, company, location, salary, posting age, employment type, full description, job highlights and every apply link. Query expansion runs 7 searches per query and keeps unique jobs only; watch mode delivers only new jobs. Pay per result, no login.

Pricing

$3.50 / 1,000 delivered jobs

Rating

0.0

(0)

Developer

architek.earth

architek.earth

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Recorded run: 100 jobs from 10 searches in 91 seconds (2026-10-24, build 0.1.1, run IUbu3u7h1OveEIjrf; 10 US role-and-city searches, 100 job charges, 0 blocked). A bounded canary sample, not a full-catalogue benchmark. At $3.50 per 1,000 jobs this costs less than half of the most-used Google Jobs actor in the Store (about $9 per 1,000 jobs at $0.09 per page of about 10 jobs on its free tier), and every one of the 9 validation runs on 2026-10-24 succeeded and charged exactly the jobs it delivered.

architek.earth — an independent data studio. Pay-per-result scrapers with recorded runs, published canaries and stable schemas, built for people and AI agents.

What's new

  • 2026-10-25 — Five input recipes, a head-to-head table, n8n and Make imports and MCP setup for Claude and Cursor added to this page; output and prices unchanged.
  • 2026-10-24 — First version: Google Jobs search in the US with full descriptions, job highlights and direct apply links; expandQueries for up to 7 searches per query with jobs deduplicated by jobId; hiring watch mode; resumable runs.

Google Jobs search results as JSON: give it job searches such as "nurse jobs near Chicago, IL" and get every job Google shows, each with title, company, location, source, posting age, employment type, salary when published, the full description, Google's job highlights and every apply link.

SourceMarketFromStandout fields
Google Jobs (the Jobs tab of google.com search)United States$3.50 / 1,000 jobsdescription, applyOptions[].url, salaryText, highlights

✅ Why choose this scraper

  • The full posting in every row, no second request. description (line breaks kept), highlights.qualifications / benefits / responsibilities and applyOptions come from the same search page as the title, so one $0.0035 row is the complete job. In run IUbu3u7h1OveEIjrf 100 of 100 jobs had a description over 200 characters and at least one direct apply link (5.5 per job on average, up to 8).
  • Direct apply links. applyOptions[].url is the job board's or employer's own posting URL (LinkedIn, Indeed, Workday, company career sites), not a Google redirect, with the button label in title and the site in domain.
  • More than Google's 10 jobs per search, without paying twice. expandQueries runs 7 searches per query (the query plus 6 refinements) and delivers each job once, deduplicated by jobId across searches and queries. Run AliOdsNDVWAqyR3hk: "registered nurse jobs near Houston, TX" expanded to 7 searches gave 53 unique jobs; the 13 repeats were free.
  • Charges equal delivered rows, measured. 9 validation runs on build 0.1.1 delivered 280 jobs and recorded 280 job charges; 0 runs failed. Status rows, searches with no jobs, repeated jobs and unchanged watch rows were free.
  • Hiring watch that charges only for new jobs. With incrementalMode and a stateKey, later runs deliver only jobs not delivered before for that key. The watch rerun b28aKFY0ZSIj4I11o charged the 5 jobs Google had added and skipped the 15 it had already delivered, for free.

Tested head-to-head (2026-10-25)

This actorThe field (16 job actors in the store search)
Runs that did not succeed0 of 6 recorded canary runs (2026-10-24 to 2026-10-25)median 5.5%, range 0–100%; 10 of 16 had failed runs (30-day store stats)
Rows per run12.2 jobs per canary run (2 searches daily; a watch run delivers only new jobs)not published
Price$3.50 / 1,000 jobsmedian $5.50 / 1,000, range $0.80–$200.00

⚠️ Worth knowing up front

  • Google shows about 10 jobs per search to this route, and there is no page 2. Google loads more jobs in the browser through a session-bound request that a server route cannot make; start= and num= return nothing new (tested 2026-10-24). For more coverage use expandQueries, more specific searches (a neighbouring town, a seniority, a company name), or both.
  • expandQueries adds exactly these 6 searches per query: <query> in the last 3 days, <query> remote, senior <query>, entry level <query>, <query> full time, <query> contract. Some refinements return few or no jobs for some queries; each search with no jobs is a free NO_RESULTS row. Recorded unique jobs per expanded query: 57 (software engineer, Austin, Phase 0) and 53 (registered nurse, Houston, run AliOdsNDVWAqyR3hk).
  • postedText is Google's relative text ("3 days ago"); Google shows no posting date. salaryText appears only when the employer published a salary (44 of 100 jobs in run IUbu3u7h1OveEIjrf). postedText was missing on 26 of those 100 jobs and employmentType on 1.
  • Apply links are the ones Google lists for the job. Google groups near-identical postings, so a button can lead to the same role posted on another site or for another office.
  • US jobs only in this version: searches run on google.com with gl=us and hl=en through a US proxy. A page in another language or with mostly non-US jobs is fetched again (3 attempts), then becomes a free SOURCE_ERROR row, so a search for jobs outside the US returns nothing.
  • Pacing: Google pages take about 2 to 60 seconds through the SERP proxy (median about 8 seconds in Phase 0), two searches at a time, so plan about 5 to 10 searches per minute. Measured on 2026-10-24: 10 searches in 91 seconds, one query expanded to 7 searches in 141 seconds. Each page is fetched with a 90-second timeout and retried once.
  • A run stops cleanly 3 minutes before its deadline (PARTIAL, stopReason ACTOR_DEADLINE), at your spending limit (BUDGET_LIMIT), and after two blocked searches in a row (PARTIAL). The deadline is the run timeout, capped at 6 hours. Rerun with the same stateKey to continue.
  • Invalid input (INVALID_INPUT), a stateKey still held by another run (STATE_BUSY), a search with no jobs (NO_RESULTS), a blocked, failed or other-market page (BLOCKED, SOURCE_ERROR, SOURCE_CHANGED), the deadline (ACTOR_DEADLINE) and the spending limit (BUDGET_LIMIT) each write a free status row ("recordType": "status"). An unconfirmed delivery (RECONCILIATION_REQUIRED) or a storage fault fails the run and replays nothing.

⚡ Try the example

This actor has no free preview of its own; the example below costs about $0.035 (one search, up to 10 jobs).

Open the actor's input page, switch to JSON, paste this and start the run:

{
"queries": ["software engineer jobs near Austin, TX"]
}

Add more searches to queries (up to 50), and set "expandQueries": true for up to 7 searches per query.

⚙️ Input

ParameterTypeDefaultDescription
queriesarray— (prefill ["software engineer jobs near Austin, TX"])1–50 Google Jobs searches, as typed into Google: a role and a place ("nurse jobs near Chicago, IL"), a remote search ("remote data analyst jobs") or a company ("Tesla jobs near Austin, TX"). Duplicates are removed.
expandQueriesbooleanfalseAlso run the 6 refinements listed above for each query. Jobs found by several searches are delivered and charged once.
incrementalModebooleanfalseNeeds stateKey. Deliver and charge only jobs (by jobId) not delivered before for this key.
stateKeystring—Any name up to 100 characters. Keeps the watch baseline and lets an interrupted run resume. One key per set of inputs.
feedbackstring—Optional note for the maintainers. It is logged and read by a human, and it never changes output.

The run's spending limit (maxTotalChargeUsd, set in the run options) caps how many jobs are delivered.

Input recipes

Linked recipes open a public example task with exactly this input; run it as is or copy it. Paste the others into the JSON tab of the input page.

  • One search, about 10 jobs: {"queries": ["software engineer jobs near Austin, TX"]}
  • One query expanded to 7 searches, unique jobs only: {"queries": ["nurse jobs near Chicago, IL"], "expandQueries": true}
  • Hiring watch: only new jobs for 3 searches: {"queries": ["data analyst jobs near New York, NY", "electrician jobs near Phoenix, AZ", "remote product manager jobs"], "incrementalMode": true, "stateKey": "us-hiring-watch"}
  • Remote roles across the US: {"queries": ["remote data engineer jobs"], "expandQueries": true}
  • Several cities for one role in one run: {"queries": ["registered nurse jobs near Houston, TX", "registered nurse jobs near Phoenix, AZ", "registered nurse jobs near Atlanta, GA"]}

🧱 Stable fields

These top-level fields keep the same name and the same kind of value in every release. Fields are only ever added, never renamed or removed, so an n8n, Make, Zapier or spreadsheet pipeline can bind to them.

FieldTypeMeaning
querystringYour query as given (whitespace collapsed).
searchQuerystringThe text sent to Google: the same as query, or one of its expandQueries refinements.
countrystringus.
positionnumberRank of the job on its Google search page (1 = first).
jobIdstringGoogle's job id. The same job found by two searches has the same jobId; it is the dedupe and watch key.
titlestringJob title.
companystring, nullableEmployer name.
locationstring, nullableGoogle's location text, for example Austin, TX, Anywhere or Austin, TX (+2 others).
viastring, nullableThe source Google names, for example LinkedIn, Indeed or Schwab Jobs.
postedTextstring, nullableGoogle's relative posting age, for example 2 days ago.
employmentTypestring, nullableFor example Full-time, Contractor, Full-time, Part-time, and Contractor.
salaryTextstring, nullableThe salary as shown, for example $164K–$205K a year or $50 an hour; null when the employer published none.
workFromHomebooleantrue when Google tags the job "Work from home".
chipsarrayEvery label on the job card, for example Posted 2 days ago, Employment Type Full-time, Qualification No degree mentioned.
descriptionstring, nullableThe full job description, with line breaks.
highlightsobjectGoogle's "Job highlights": qualifications, benefits and responsibilities, each a list of strings (empty when Google shows none).
applyOptionsarrayOne object per apply button: title (for example Apply on LinkedIn), url (the posting on that site) and domain.
shareUrlstring, nullableGoogle's share link for the job.
scrapedAtstringCollection time, UTC ISO 8601.
recordTypestring"status" on free status rows; "job" on data rows.

Data rows also carry deliveryId (unique per delivered row). Status rows carry recordType, inputRef (the search text), status and message. Other fields are extras, not part of the contract. To have one pinned, say so in feedback.

📦 Output example

Abridged real row from run IUbu3u7h1OveEIjrf on 2026-10-24 (description cut, one item per highlight list, 2 of 8 apply options, shareUrl shortened); values are a historical snapshot.

{
"recordType": "job",
"query": "software engineer jobs near Austin, TX",
"searchQuery": "software engineer jobs near Austin, TX",
"country": "us",
"position": 3,
"jobId": "ZrBruAaEW4Eb97eJAAAAAA==",
"title": "Sr Software Engineer",
"company": "Charles Schwab",
"location": "Austin, TX (+2 others)",
"via": "Schwab Jobs",
"postedText": "12 days ago",
"employmentType": "Full-time",
"salaryText": "$164K–$205K a year",
"workFromHome": false,
"chips": [
"Posted 12 days ago",
"Salary $164K–$205K a year",
"Employment Type Full-time",
"Qualification No degree mentioned"
],
"description": "Your opportunity\n\nAt Schwab, you’re empowered to make an impact on your career. Here, innovative thought meets creative problem solving, ...",
"highlights": {
"qualifications": [
"8+ years of software engineering experience"
],
"benefits": [
"In addition to the salary range, this role is also eligible for bonus or incentive opportunities"
],
"responsibilities": [
"The engineer will work closely with architects, product teams, infrastructure partners, and business stakeholders to transform ideas into working prototypes and production-ready solutions"
]
},
"applyOptions": [
{
"title": "Apply on Schwab Jobs",
"url": "https://www.schwabjobs.com/job/austin/sr-software-engineer/33727/101909398560?utm_campaign=google_jobs_apply&utm_source=google_jobs_apply&utm_medium=organic",
"domain": "schwabjobs.com"
},
{
"title": "Apply on CareerBuilder",
"url": "https://www.careerbuilder.com/job-details/sr-software-engineer-blockchain-ann-arbor-mi--34192420-ab6d-446d-b589-b215d70fe39c?utm_campaign=google_jobs_apply&utm_source=google_jobs_apply&utm_medium=organic",
"domain": "careerbuilder.com"
}
],
"shareUrl": "https://www.google.com/search?ibp=htl;jobs&q=software+engineer+jobs+near+Austin,+TX&htidocid=ZrBruAaEW4Eb97eJAAAAAA%3D%3D&hl=en-US...",
"scrapedAt": "2026-10-24T21:33:21.717697+00:00",
"deliveryId": "2768132ebb1bd912996312d73ff94090-2"
}

A free status row looks like this (run F4p8zrCPSt9ND01DA, a nonsense search):

{"recordType": "status", "inputRef": "zqxjvbwkpfh qwmzrtvxl jobs", "status": "NO_RESULTS", "message": "Google Jobs shows no jobs for this search; nothing was charged"}

The run's status message reads Done: N rows, 0 details, K status rows (STATUS), and the RUN_SUMMARY record of its key-value store holds the outcome (abridged, the expanded run AliOdsNDVWAqyR3hk):

{"status": "COMPLETE", "delivered": 53, "charged": {"job": 53}, "chargeUsd": "0.1855", "statusRows": 0, "duplicates": 13, "queriesFetched": 7, "serpRequests": 7, "checkpointComplete": true}

🧠 Advanced usage

Daily hiring watch. Schedule a run with your searches, "incrementalMode": true and "stateKey": "us-hiring-watch". The first run delivers every job; later runs deliver (and charge) only jobs whose jobId was not delivered before under that key, so the dataset of each run is the list of new postings. Google reorders and refreshes its 10 jobs per search between days, which is where new jobs appear.

Wider coverage for one role. Use "expandQueries": true and add neighbouring places as separate queries ("nurse jobs near Evanston, IL", "nurse jobs near Oak Park, IL"). Every job is delivered once across all of them; searchQuery tells you which search found it.

Route by apply site. applyOptions[].domain names each site that carries the posting (for example linkedin.com, myworkdayjobs.com, the employer's career site). Filter on it to keep employer-direct postings or to send each job to the board you use.

Resume an interrupted collection. With a stateKey, a run that stops at the deadline, the spending limit or a forced stop keeps its progress; start the same input again with the same key. Jobs already delivered are not delivered or charged again. After a forced stop, the key is free again once the stopped run's timeout plus 60 seconds has passed (STATE_BUSY before that).

🔌 Integrations

Results land in a dataset you can export as JSON, CSV or Excel. They can also flow to Google Sheets, Make, Zapier or n8n, or to a webhook when a run finishes. The Apify Scheduler runs it on a timetable. A daily run with incrementalMode turns a list of searches into a feed of new job postings. Copy-paste code in Python, Node, curl and n8n: architek-earth/examples/google-jobs-scraper.

n8n and Make

💸 Pricing

Pay per result. Platform and proxy usage are included. Status rows and failed requests are free. Each job is charged once, after it is written to the dataset; a job found again by another search in the same run, or (in watch mode) by an earlier run with the same stateKey, is not delivered or charged again, and a resumed run continues after the last confirmed batch without re-charging it (a batch whose charge was left unconfirmed by a crash is counted in RUN_SUMMARY.recoveredUncertainCharges and not charged again).

EventPriceWhat it covers
job$3.50 / 1,000 jobsOne delivered job row with its description, highlights and apply links.

1,000 jobs cost $3.50; one search of 10 jobs costs $0.035; one query expanded to 7 searches cost $0.19 for 53 unique jobs in run AliOdsNDVWAqyR3hk. The Apify free plan's $5 monthly credit covers about 1,428 jobs at $3.50 / 1,000.

❓ FAQ

Is there a Google Jobs API? Google does not offer a public one. This actor works as one: it returns Google Jobs search results as JSON through the Apify API, callable from any language or from n8n, Make and Zapier.

Do I need a Google account, cookies or my own proxy? No. Requests go through Apify's Google SERP proxy in the US; no login, cookies or Google API key.

Why do I get at most about 10 jobs per search? That is what Google renders for a search on this route; the rest of its list loads in the browser through a session-bound request. expandQueries and more specific searches are the way to more jobs.

Are the apply links Google redirects? No. applyOptions[].url is the posting URL on the job board or career site, as Google lists it. Only if Google gives no direct URL for a button is its /goto link used instead.

Can I search outside the US? Not in this version. Searches run as a US user on google.com; other countries are planned.

Will a watch run charge me again for the same job? No. Under the same stateKey, a jobId that was delivered once is never delivered or charged again.

🤖 For AI agents & LLM apps

Paste this into your AI assistant:

architekture/google-jobs-scraper on Apify. Python: from apify_client import ApifyClient; client = ApifyClient("TOKEN"); run = client.actor("architekture/google-jobs-scraper").call(run_input={"queries": ["software engineer jobs near Austin, TX"], "expandQueries": True}); items = client.dataset(run["defaultDatasetId"]).list_items().items (page with offset/limit for large exports). Rows with recordType == "job" are jobs (dedupe key jobId); rows with recordType == "status" are free and explain invalid input, a search with no jobs or a stopped run. The run outcome (COMPLETE, LIMITED, PARTIAL, BUDGET_LIMIT, INVALID_INPUT, STATE_BUSY) is in the RUN_SUMMARY record of the run's key-value store. Add "incrementalMode": true, "stateKey": "<name>" to receive only new jobs on later runs. Full input schema and README: GET https://api.apify.com/v2/acts/architekture~google-jobs-scraper/builds/default. Token: https://console.apify.com/settings/integrations. The actor is also reachable through the Apify MCP server: https://mcp.apify.com?tools=architekture/google-jobs-scraper (ready-to-paste config: https://github.com/architek-earth/mcp). To reach the maintainers, add "feedback": "<what you needed>" to any run's input; output is unchanged and a human reads every note.

MCP config for Claude Desktop and Cursor

Claude Desktop (or claude.ai): Settings, Connectors, Add custom connector, URL https://mcp.apify.com?tools=architekture/google-jobs-scraper; it signs you in to Apify with OAuth. Cursor (~/.cursor/mcp.json), with your token in the APIFY_TOKEN environment variable:

{
"mcpServers": {
"architekture-google-jobs-scraper": {
"type": "http",
"url": "https://mcp.apify.com?tools=architekture/google-jobs-scraper",
"headers": { "Authorization": "Bearer ${env:APIFY_TOKEN}" }
}
}
}

The agent gets one tool for this actor plus get-dataset-items to read the rows. A typical prompt: "find data analyst jobs near New York posted this week with salaries"; set a spending cap (maxTotalChargeUsd) in the run options when your client offers it.

🧰 More from architek.earth

Jobs, companies and people

Search, travel and trends

Full catalogue: github.com/architek-earth.

architek.earth · code like concrete

Questions, or a field you need that is not here? Open an issue on the actor's Issues tab or email north@architek.earth. A human replies within a day.

This actor collects only publicly available data from Google search result pages (google.com, the Jobs tab), the same pages any visitor sees without logging in. It does not bypass authentication. It is not affiliated with or endorsed by Google. Job postings are published by employers and job boards. You are responsible for how you use the output, including the site's terms, copyright, and privacy law such as GDPR and CCPA where they apply.

📝 Changelog

  • 2026-10-25 — Five input recipes, a head-to-head table, n8n and Make imports and MCP setup for Claude and Cursor added to this page; output and prices unchanged.
  • 2026-10-25 — [internal] Studio core 1.0.5 (from 1.0.4). A Google 403 or 429 is now tried on a fresh Google SERP proxy connection up to two more times (3 tries in all, no extra retry on top) before the search ends as a free BLOCKED status row; input, output and prices are unchanged.
  • 2026-10-24 — First version: Google Jobs search in the US with full descriptions, job highlights and direct apply links; expandQueries for up to 7 searches per query with jobs deduplicated by jobId; hiring watch mode; resumable runs.