Google Jobs Scraper - Salary, Apply Links & Dates, No Login avatar

Google Jobs Scraper - Salary, Apply Links & Dates, No Login

Pricing

from $0.85 / 1,000 job listings

Go to Apify Store
Google Jobs Scraper - Salary, Apply Links & Dates, No Login

Google Jobs Scraper - Salary, Apply Links & Dates, No Login

Scrape Google Jobs listings for your job searches: title, company, location, salary, job type, posting date, full description and direct apply links. Pick the city and country; deep mode finds more jobs per search. No login.

Pricing

from $0.85 / 1,000 job listings

Rating

0.0

(0)

Developer

Cliqto Media

Cliqto Media

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Google Jobs Scraper searches Google Jobs for your job titles and a location and returns one row per job: title, company, location, salary, job type, posting age, full description and the apply links to LinkedIn, Indeed or the employer site. It reads the public Google Jobs results page, so you need no Google login and no API key. The default input (python developer in Berlin, 10 jobs) usually takes 10–60 seconds and costs $0.033.

Use it for job market research, recruiting lead lists, salary checks and job feeds. The smallest run is one job title in the Job searches field.

Google Jobs Scraper: a job search with location, date and job type gives job listings with company, salary and apply links on LinkedIn, Indeed or the employer site. 8 countries, up to 1,000 jobs per run, no login, no API key.

Table of contents

What it does

  1. You add one or more job searches, for example python developer or registered nurse, and a location.
  2. The Actor opens the Google Jobs results page for each search in the right Google country.
  3. It reads every job card: title, company, location, the site Google found the job on (via), posting age, salary and job type.
  4. It reads the job panel too: the full description, Google's highlights and all apply links, without tracking parameters.
  5. It removes duplicate jobs (same Google job id) and saves one Dataset row per job.
  6. Fast mode reads one Google page per search, about 10 jobs. Deep mode repeats each search with Google's date and job-type filters and removes duplicates, so you get several times more jobs.

Good fit

  • Job market research: who hires for a role in a city, and on which job boards.
  • Lead lists for recruiters and staffing agencies: companies with open roles, with the link to each job.
  • Salary checks: Google's salary text where the job has one.
  • A daily job feed for a niche job board, a Slack channel or a spreadsheet.

Not a fit / limits

  • 8 countries only: United States, United Kingdom, Canada, India, Germany, France, Spain and Brazil (countryCode). Google shows the texts in the language of that country, for example vor 1 Tag and Vollzeit in Germany.
  • Google shows about 10 jobs per search page. Fast mode gives about 10 jobs per search; deep mode about 20–70 (our tests). For more jobs, add more searches (up to 50) or more specific titles.
  • salary is often null: Google shows a salary only for some jobs (0–40 % in our tests).
  • highlights is often null in fast mode: Google does not send this block on many pages. The full description is still there.
  • No recruiter names, emails or phone numbers. The Actor saves only the public job post.
  • Google decides which jobs it shows. Two runs a few minutes apart can return a slightly different set or order.
  • Google's terms do not allow automated access to Google Search. You are responsible for how you use the data.

Quick start

  1. Open the Input tab.
  2. In Job searches (queries), keep python developer or add your own job title.
  3. Keep Location Berlin and Max jobs 10, or change them. Country auto picks the country from the location.
  4. Click Start.
  5. Open the Output tab. The Jobs table shows title, company, location, salary and the apply links.

Expected result: about 10 Python developer jobs in Berlin in Google's order, each with company, posting age and at least one apply link.

Use cases

Buyer jobInput pathOutput entityKey fieldsNext integration
Job market researchqueries + location, mode: "deep"Jobtitle, company, via, postedAtCSV or Excel export
Recruiting lead listqueries like "sales manager" + datePosted: "week"Jobcompany, title, location, applyLinksGoogle Sheets or CRM through Apify integrations
Salary checkqueries + locationJobsalary, employmentType, titleSpreadsheet
Daily job feedqueries + datePosted: "today" on a scheduleJobjobId, title, googleJobsUrlSlack, email or a website through webhooks

Input

Input fields

FieldPlain nameTypeRequiredDefault / prefillAllowed valuesEffectExampleRecommendation
queriesJob searchesarray of stringsyesprefill ["python developer"]1–50 searchesOne Google Jobs search per item["data analyst", "nurse"]Use job titles people really write in job posts
locationLocationstringnoprefill BerlinCity, region or remoteAdded to every search"Austin, TX"Leave empty to search the whole country
countryCodeCountrystringnoautoauto, us, gb, ca, in, de, fr, es, brGoogle country and language"gb"Keep auto when the location is a known city
datePostedDate postedstringnoanyany, today, 3days, week, monthOnly jobs posted in this period"week"Use today for a daily feed
employmentTypeJob typestringnoanyany, fulltime, parttime, contractor, internshipOnly jobs of this type"fulltime"
modeSearch depthstringnofastfast, deepdeep repeats each search with Google's filters"deep"Use deep when 10 jobs per search are not enough
maxJobsMax jobsintegernodefault 50, prefill 101–1,000Stops the run at this many jobs in total200Keep the default 900-second timeout for more than 300 jobs
includeDescriptionInclude descriptionbooleannotruetrue / falsefalse leaves out description and highlightsfalseTurn off for smaller rows; the price is the same

Duplicate searches (same text, any case) run only once. A job that two searches find is saved once. If queries is empty, the run fails at once with INVALID_INPUT and makes no requests. A country outside the list above is rejected by the input form.

Interacting settings

WhenInput AInput BEffective behaviorExampleCost/result effect
Empty locationlocation: ""countryCodeThe country name is added to the search, because Google Jobs needs a place"nurse" → nurse USAnone
Country autocountryCode: "auto"locationCountry from the location; unknown places use the United States"Lyon" → Francenone
Date or type filterdatePosted, employmentTypeGoogle's resultsGoogle's own filter, then jobs whose shown date or type does not match are dropped (filteredOut in RUN_SUMMARY). Jobs without a shown date or type are keptdatePosted: "week"Dropped jobs are free; the page is still charged
Deep modemode: "deep"datePosted, employmentTypeUp to 9 Google pages per search: the base search, plus one per date filter if datePosted is any, plus one per job type if employmentType is any. With both filters set, deep mode is the same as fastmode: "deep"Up to 9 charged pages per search, several times more jobs
Job limitmaxJobsqueriesSearches run in order and stop at maxJobs; later searches may not runmaxJobs: 10 with 3 searchesRUN_SUMMARY.stopReason: "MAX_JOBS"

Input examples

Python jobs in Berlin (prefill)

{
"queries": ["python developer"],
"location": "Berlin",
"maxJobs": 10
}

Expected behavior: one Google Jobs page in Germany (countryCode auto → de). Expected output: 10 job rows with title, company, via, postedAt and applyLinks. Limit or cost note: $0.033 on the Free plan; about 10 seconds in our last test.

More jobs per search: deep mode in Houston

{
"queries": ["registered nurse", "pharmacist"],
"location": "Houston, TX",
"mode": "deep",
"maxJobs": 100
}

Expected behavior: up to 9 Google pages per search (base, 4 date filters, 4 job types); duplicates removed. In our test these two searches found 60 and 59 jobs. Expected output: 100 jobs with searchVariant showing which search found each job. Limit or cost note: at most $0.34 on the Free plan (1 start, up to 18 pages, 100 jobs); usually a few minutes.

Output

The Actor saves one row per job in the default Dataset. A search with no jobs gets one free not_found row, and a search that failed gets one free error row, so you always see what happened to each search. A run overview is saved as RUN_SUMMARY in the default Key-value store.

Output fields

FieldMeaningTypeCan be empty?Example / enumSource / notes
statusRow resultstringnocomplete, partial, not_found, errorpartial = deep search where some Google pages did not answer
titleJob titlestringyesPython Team Lead, Integration teamAs the employer wrote it
companyEmployerstringyesFliff Inc
locationJob location as Google shows itstringyesBerlin, Beliebiger Ort (anywhere)In the language of the country
viaSite Google found the job onstringyesLinkedIn, Indeed
postedAtPosting age as Google shows itstringyesvor 1 Tag, 2 days agonull when Google shows no date
postedAtApproxApproximate posting datestring (YYYY-MM-DD)yes2026-10-14fetchedAt minus postedAt
salarySalary as Google shows itstringyes65.000 € bis 85.000 € pro Jahrnull = Google shows no salary (not zero)
employmentTypeJob type as Google shows itstringyesFull-time, Vollzeit
workFromHomeRemote job tagbooleanyestruenull when Google does not say
descriptionFull job description, plain textstringyesWe're looking for a Python Team Lead…null when includeDescription is off
highlightsQualifications, Responsibilities, Benefitsarrayyes[{"title": "Qualifications", "items": ["…"]}]Often null in fast mode
applyLinksWhere to applyarrayyes[{"title": "LinkedIn", "url": "https://…"}]Tracking parameters removed
jobIdGoogle's job idstringyeseAHxzL0ATotpbjXSAAAAAA==Same job, same id across runs
googleJobsUrlGoogle page that opens this jobstringyeshttps://www.google.de/search?ibp=htl;jobs&…
positionOrder in this search after removing duplicatesintegeryes2null on not_found and error rows
query, searchLocation, countryCodeYour search, your location, the Google countrystringsearchLocation yespython developer, Berlin, de
searchVariantWhich deep search found the jobstringyesdatePosted:weeknull in fast mode
source, sourceUrlSource name and the Google URL that was readstringnogoogle_jobs
fetchedAtWhen the page was read, UTCstring (ISO 8601)no2026-10-15T06:20:55.335Z
statusReason, errorCodeWhy a row is not completestringyesSOURCE_TIMEOUTnull on complete rows

null means "Google shows no value"; it never means zero.

Output entities and surfaces

SituationDataset/API/KVS/live viewResult shapeUser action
Normal itemDataset, view Jobsstatus: "complete" job rowUse title, company, applyLinks
No jobs for a searchDatasetone free not_found row with statusReasonTry a wider location or another title
Partial resultDatasetstatus: "partial" rows of a deep searchRun again later for the missing pages
Technical failureDataset + RUN_SUMMARYfree error row with errorCode; run status PARTIAL or ERRORRun again later; see Troubleshooting
Run overviewKey-value store record RUN_SUMMARYstatus, stop reason, counts per search, charged pages and jobsCheck status, stopReason and counts

Output example

{
"status": "complete",
"title": "Python Team Lead, Integration team",
"company": "Fliff Inc",
"location": "Beliebiger Ort",
"via": "LinkedIn",
"postedAt": "vor 1 Tag",
"postedAtApprox": "2026-10-14",
"salary": null,
"employmentType": "Vollzeit",
"workFromHome": true,
"description": "We’re looking for a Python Team Lead to join our Integration team, which owns a broad set of critical integrations across the product…",
"highlights": null,
"applyLinks": [
{ "title": "LinkedIn", "url": "https://de.linkedin.com/jobs/view/python-team-lead-integration-team-at-fliff-inc-4479228357" },
{ "title": "Startup Jobs", "url": "https://startup.jobs/python-team-lead-integration-team-fliff-inc-10437417" }
],
"jobId": "eAHxzL0ATotpbjXSAAAAAA==",
"googleJobsUrl": "https://www.google.de/search?ibp=htl;jobs&q=python+developer+Berlin&htidocid=eAHxzL0ATotpbjXSAAAAAA%3D%3D&hl=de-DE#…",
"position": 2,
"query": "python developer",
"searchLocation": "Berlin",
"countryCode": "de",
"searchVariant": null,
"source": "google_jobs",
"sourceUrl": "https://www.google.de/search?q=python+developer+Berlin&udm=8&hl=de&gl=de",
"fetchedAt": "2026-10-15T06:20:55.335Z",
"statusReason": null,
"errorCode": null
}

This is one row from the prefill run. The description, one apply link and the end of googleJobsUrl are shortened here. This job has no salary on Google, so salary is null.

Moving from another Google Jobs Actor

Field names are different from other Google Jobs Actors, so this Actor is not a drop-in replacement. Common changes: company_name → company, share_link → googleJobsUrl, job_highlights → highlights, apply_options → applyLinks (with url instead of link), job_id → jobId (Google's own id), search_timestamp → fetchedAt. Google's tag list (extensions) is split into salary, employmentType, postedAt and workFromHome.

Pricing and limits

Pricing unit

This Actor uses pay-per-event pricing. You pay for:

EventWhen it is chargedPrice
Actor start (apify-actor-start)Once per run (runs up to 1 GB memory)$0.01
Search page (search-page)Each Google Jobs page that Google answered (up to 10 jobs), also a page with no jobs$0.013
Job (job)Each unique job saved to the Dataset$0.001 (Free plan), $0.00095 (Bronze), $0.0009 (Silver), $0.00085 (Gold and higher)

Duplicates, jobs dropped by your date or type filter, not_found rows and error rows are free. Pages that failed are not charged, and a page that answers after maxJobs is reached is not charged. A search with no jobs costs one search page ($0.013). Apify platform usage (compute, proxy, storage) is included; you do not pay it separately.

If you set a maximum charge for the run, the Actor stops before it goes over it: RUN_SUMMARY.status: "CAPPED", stopReason: "CHARGE_LIMIT".

Cost examples

Prices on the Free plan, from our test runs.

ScenarioInput scopePagesJobsTotal
Prefill1 search, fast, 10 jobs110$0.033
100 jobs10 searches, fast10100$0.24
1,000 jobs22 searches, deep1961,000$3.56
Nothing found1 search, no jobs10$0.023

Measured run times: 10 jobs in about 10–60 seconds (up to about 3 minutes when Google answers slowly), 100 jobs in about 2 minutes, 500 jobs in about 8 minutes, 1,000 jobs in about 8–9 minutes. Google answers each page in 4–20 seconds; more memory does not make it faster.

The default run timeout is 900 seconds. If a run reaches its timeout, the Actor stops by itself and keeps what it saved (status: "CAPPED", stopReason: "DEADLINE"). For more than 300 jobs, keep the timeout at 600 seconds or more, or split the searches into several runs.

API, export and integrations

  • API: start the Actor with the Apify API and read rows from the default Dataset (view jobs).
  • Export: download the Dataset as JSON, CSV, Excel, XML or HTML from the Output tab.
  • Scheduling: create a schedule with datePosted: "today" for a daily job feed. Use jobId to skip jobs you already have.
  • Webhooks / no-code: send new rows to Slack, Google Sheets, Make, Zapier or n8n through Apify integrations.

Use with AI agents (MCP)

  • MCP server with only this Actor: https://mcp.apify.com?tools=cliqtomedia/google-jobs-scraper.
  • Smallest useful input:
{ "queries": ["python developer"], "location": "Berlin", "maxJobs": 10 }
  • Key output fields: title (job title), company (employer), location, salary (text or null), applyLinks (where to apply), status (complete, partial, not_found or error).
  • A 10-job run usually takes 10–60 seconds and costs $0.033 on the Free plan. Keep maxJobs small (10–50) and mode: "fast" for agent calls; 1,000 jobs take about 8 minutes.

Troubleshooting

The run failed at once

Symptom: run status FAILED in a few seconds, no rows. Likely reason: invalid input (INVALID_INPUT), for example no searches. Check: the run log and RUN_SUMMARY.message. Action: fix the input and start again.

A search returned one not_found row

Symptom: one row with status: "not_found". Likely reason: Google Jobs has no jobs for this search, place and filter. Check: statusReason and sourceUrl; open sourceUrl in a browser. Action: try a more common job title, a bigger city, or datePosted: "any".

Error rows with SOURCE_TIMEOUT or SOURCE_BLOCKED

Symptom: free error rows with errorCode SOURCE_TIMEOUT, SOURCE_UNAVAILABLE or SOURCE_BLOCKED. Likely reason: Google did not answer in 60 seconds after retries, or refused the request. Check: RUN_SUMMARY.http (requests, retries, timeouts, blocked). Action: run these searches again later. The Actor does not solve CAPTCHAs.

The run stopped with CAPPED and DEADLINE

Symptom: RUN_SUMMARY.status: "CAPPED", stopReason: "DEADLINE", fewer jobs than maxJobs. Likely reason: the run timeout was too short for the number of jobs. Check: the run timeout in the run options. Action: keep the default 900 seconds, or split the searches into several runs. Searches that did not start get free error rows.

Fewer jobs than maxJobs

Symptom: the run is COMPLETE with fewer jobs than you asked for. Likely reason: in fast mode Google shows about 10 jobs per search; filters drop jobs that do not match. Check: RUN_SUMMARY.counts (jobs, duplicates, filteredOut). Action: use mode: "deep" or add more searches.

FAQ

Do I need a Google account or API key?

No. The Actor reads the public Google Jobs results page without login, cookies or keys.

Is this the official Google Jobs API?

No. Google has no public API for Google Jobs search results. This Actor is not made by or linked to Google.

Why are some texts in German or French?

Google shows jobs in the language of the country you search. Search in Germany, and postedAt says vor 2 Tagen and employmentType says Vollzeit. postedAtApprox gives a date that is the same in every language.

Why is salary empty for most jobs?

Google shows a salary only when the job post or job board gives one. The Actor does not guess: no salary on Google means salary: null.

Can I get the recruiter's email or phone?

No. The Actor saves only the public job post and does not collect personal contact data.

Support

For bugs, questions or feature requests, open an issue on the Issues tab of this Actor. Include the run ID, your input and the error text. Never send tokens, cookies or private data.