Apify Actors / Google Jobs listings with salary and apply links
Apify ActorGoogle Jobs listings with salary and apply links
Google search has a jobs panel that pulls listings and their apply links into one place, 10 jobs per search. This Actor runs your searches there and saves one row per job with the title, company, location, salary when the listing shows one, the posted date, the full description and Google's job highlights.
Apply links are the posting's own URLs with Google's utm_ tracking tags removed, or Google's redirect link when the page doesn't carry the direct URL. Salaries are parsed into salaryMin, salaryMax, salaryPeriod and salaryCurrency and stay null when the listing shows none, because the Actor never guesses one. Pages that Google blocks, duplicates and jobs outside your filters aren't charged.
$0.004 per job saved · pay per result, no subscription
Price
| Event | Price | Charged when |
|---|---|---|
job | $0.004 | Each job saved to the dataset. Blocked or script-only pages, jobs outside your filters, duplicates and failed searches are free |
| Example run | Units | Cost |
|---|---|---|
| The input below (up to 30 jobs) | up to 30 × $0.004 | up to $0.12 |
| Empty form (up to 20 "software engineer" jobs) | up to 20 × $0.004 | up to $0.08 |
| 1,000 jobs | 1,000 × $0.004 | $4.00 |
What you get
salaryas shown, plussalaryMin,salaryMax,salaryPeriodandsalaryCurrency, all null when the listing shows no salary.applyUrlandapplyLinks, every apply link Google lists with its source name.descriptionup to 20,000 characters, andhighlightswith Google's Qualifications, Benefits and Responsibilities lists.jobIdfor tracking a job across runs, andpostedAgo,postedDaysAgoandpostedDateApproxfor its age.
Input
Set the run options in the Apify console, or send the same object through the API.
{
"queries": [
"data analyst"
],
"location": "Chicago, IL",
"datePosted": "3days",
"maxJobsPerQuery": 30
}Data analyst jobs near Chicago posted in the last 3 days, up to 30. Up to 50 searches per run and up to 500 jobs per search. The location is added to every search as "near Chicago, IL".
Output
{
"searchQuery": "software engineer",
"searchLocation": "Austin, TX",
"jobId": "eyJqb2IiOiIxIn0=",
"title": "Senior Software Engineer",
"company": "Acme Corp",
"location": "Austin, TX",
"isRemote": false,
"via": "Acme Careers",
"employmentType": "Full-time",
"salary": "$120K–$150K a year",
"salaryMin": 120000,
"salaryMax": 150000,
"salaryPeriod": "year",
"salaryCurrency": "$",
"postedAgo": "3 days ago",
"postedDaysAgo": 3,
"postedDateApprox": "2026-11-02",
"applyUrl": "https://careers.acme.example/jobs/123",
"applyLinks": [
{ "title": "Acme Careers", "url": "https://careers.acme.example/jobs/123" }
],
"description": "We build things...",
"descriptionTruncated": false,
"highlights": [
{ "title": "Qualifications", "items": ["5+ years of experience with Python", "Experience with AWS"] }
],
"position": 1,
"page": 1,
"matchedSearch": "software engineer jobs near Austin, TX",
"source": "google",
"googleJobsSearchUrl": "https://www.google.com/search?q=software+engineer+jobs+near+Austin%2C+TX&udm=8&hl=en&gl=us",
"scrapedAt": "2026-11-05T12:00:00.000Z"
}The output example from the README, trimmed. postedDateApprox is the scrape date minus the age Google shows, a day-level estimate that is null for "30+ days ago". The dataset has a Jobs view and a Salaries view.
Run it from your own code
The Actor takes the same input as a JSON body. This call starts a run, waits for it and returns the dataset items.
curl -X POST "https://api.apify.com/v2/acts/zovo-one~google-jobs-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"queries": ["data analyst"], "location": "Chicago, IL", "datePosted": "3days", "maxJobsPerQuery": 30}'A sync call waits at most 300 seconds. For longer runs, start a run with POST /v2/acts/zovo-one~google-jobs-scraper/runs, wait for it, then read /v2/datasets/<defaultDatasetId>/items.
Limits
Google shows 10 jobs per search, so for more the Actor runs the same search again with the date and job type refinements Google offers and keeps only new jobs. A query stops after 3 refined searches in a row bring nothing new, or after about 2 searches per 10 jobs asked for (25 at most). Expect roughly 100 to 150 jobs at most for a broad search; 500 is a ceiling you set, not a promise. Up to 50 searches per run, 200 characters per search and 100 characters for the location. Descriptions longer than 20,000 characters are cut and descriptionTruncated is true. Salary is read in English, German, French, Spanish, Portuguese, Italian and Dutch; other languages, currencies and formats leave the salary fields null. Each page gets about 150 seconds across its tries.
Questions
How do I scrape Google Jobs for one city?
Put the job title in queries and the city in location, for example "Chicago, IL". The Actor adds plain phrases to the search, like "near Chicago, IL" and "in the last 3 days", the same way Google's own filter buttons do. Each search's googleJobsSearchUrl opens that same search in your browser.
Why are the salary fields empty on some rows?
The listing shows no salary, and the Actor never guesses one. A bound the listing doesn't give stays null too, so "$100K+ a year" has salaryMax null. The currency is the symbol Google shows, so a "$" in Canada stays "$" and isn't turned into USD.
Why did I get fewer jobs than I asked for?
Google shows 10 jobs per search, and paging stops early when the refined searches bring no new jobs. In our tests 20 jobs took 2 searches and 50 jobs took 6. Expect roughly 100 to 150 jobs at most for a broad search.
What happens when Google blocks a page?
Google answers plain connections with a page that asks you to turn on JavaScript. That's why the default proxy is Apify Proxy with the GOOGLE_SERP group, which Apify runs for Google Search pages. If Google sends a JavaScript page, a captcha or HTTP 429, the Actor fetches the page again through the proxy, up to 4 tries per page, and none of these pages are charged. If 30 pages in a row come back script-only, the run stops and fails with a message.
Can I use my own SerpApi key?
Yes. Set source to serpapi and paste your key into serpApiKey. The Actor then calls SerpApi's google_jobs API and returns the same row format. SerpApi bills you for each search on your own plan, and this Actor still charges $0.004 per saved job. Your key is stored as a secret input and is never written to the log or the run report.
Does it remove duplicate jobs?
Yes, with dedupe on (the default). A job already saved by another search in the same run is skipped and not charged, matched on its Google job ID, or on title, company, location and apply URL. Repeats inside one search are always skipped.
Support this work
If this Actor saves you time, you can support the work on GitHub Sponsors. Monthly tiers start at $5, and one-time tiers start at $15. Sponsorship is optional, and the tool works the same without it.
Related tools
Built and maintained by Zovo. Actor on Apify · All Actors.