Google Jobs Scraper avatar

Google Jobs Scraper

Pricing

from $28.00 / 1,000 results pages

Go to Apify Store
Google Jobs Scraper

Google Jobs Scraper

Search Google Jobs by keyword, location and country. Get structured job postings with parsed salary, posted date, job type and work mode. Pay per results page; empty searches are free.

Pricing

from $28.00 / 1,000 results pages

Rating

0.0

(0)

Developer

krammer liu

krammer liu

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

40 minutes ago

Last modified

Features

Limited permissions

Share

Search Google Jobs results by keyword, location and country, and get clean, structured job postings in an Apify dataset. You pay per Google results page fetched: $0.028 to $0.09 per results page (up to 10 jobs), depending on your Apify plan. Searches that return nothing are free.

What it does

Give it one or more search queries (and optionally locations). It runs every query and location pair as a separate Google Jobs search and delivers the postings as dataset items.

  • Searches Google Jobs results for 4 countries: United States, United Kingdom, India, Germany.
  • Returns title, company, location, full description, highlights, benefits, apply links and the raw salary, job type and posted text.
  • Adds structured fields parsed from the text: salary min/max/currency/period, posted date, employment types and work mode (remote or hybrid).
  • Filters by posting date and employment type, and can add the word "remote" to every search.
  • Removes duplicate postings inside one run and skips postings that have no title or company.
  • Charges once per Google results page (up to 10 jobs); searches with no results are free.

Use cases

  • Salary research. Search one role in several cities and compare salaryMin, salaryMax, salaryCurrency and salaryPeriod. Only postings where Google shows a salary have these fields.
  • Find companies that are hiring. Search a role and a city, then group the results by company. Recruiters and sales teams can use this list to see who is hiring for what, and where.
  • Daily job alerts. Run the Actor on an Apify schedule with datePosted set to 7d, and keep the job_id values you have already seen so you can drop them on your side (runs do not share duplicate memory). 7d plus your own job_id list gives you only new jobs and keeps more results per page than 24h: Google returns its most relevant jobs first, and in a busy search often only a few of them are from the last 24 hours.
  • Daily job hunt with an AI assistant. The examples repo has Python scripts and a Claude Code skill that scores new jobs against your resume and lists the ones to apply to. You still apply yourself.
  • Feed a job board or a spreadsheet. Every item has the same fields, so you can export the dataset or read it with the API and load it into your own database.
  • Give an AI agent live job data. Agents can call the Actor through the Apify API or the Apify MCP server. See Use with AI agents and the API.

How to get started

  1. Click Try for free (or Start) on this page. You need an Apify account; the Free plan works.
  2. Enter one or more search queries, for example software engineer.
  3. Optional: add locations, choose a country, and set datePosted, jobTypes or maxResultsPerSearch.
  4. Click Start. A search for 100 jobs usually finishes in less than a minute.
  5. Open the Output tab to see the jobs. Export them as JSON, CSV or Excel, or read them with the API.
  6. To repeat the search automatically, create a schedule for the Actor in Apify Console.

Input

FieldTypeRequiredDefaultDescription
queriesarray of stringsyes["software engineer"] in the Console1 to 20 search queries. Each query is searched separately with every location.
locationsarray of stringsno[]0 to 20 cities or regions, for example "New York, NY". Leave empty to search the whole country.
countrystringnousOne of us, gb, in, de.
languagestringnoempty (chosen from the country)One of en, de, hi, or empty. Empty means en for us, gb, in and de for de.
datePostedstringnoanyOne of any, 24h, 3d, 7d, 30d. Jobs with no posting time are kept.
maxResultsPerSearchintegerno1001 to 200. Upper limit of delivered jobs for each query and location pair.
jobTypesarray of stringsno[]Any of FULLTIME, PARTTIME, CONTRACTOR, INTERN. Empty means no filter.
remoteOnlybooleannofalseWhen true, the word "remote" is added to the text of every search.

The number of searches is the number of queries times the number of locations (at least 1). It must not exceed 100, or the run fails at start with a message that says so.

Example input:

{
"queries": ["software engineer", "data analyst"],
"locations": ["New York, NY", "Austin, TX"],
"country": "us",
"datePosted": "7d",
"jobTypes": ["FULLTIME"],
"maxResultsPerSearch": 50
}

Output

Each dataset item is one job posting.

FieldTypeDescription
job_idstringGoogle's identifier of the posting. Used to remove duplicates inside a run.
titlestringJob title.
companystringCompany name.
locationstring or nullLocation text as shown by Google.
descriptionstring or nullFull description text.
highlightsarray or nullSections such as qualifications and responsibilities: [{ "title", "items": [...] }].
apply_optionsarray or nullPlaces to apply: [{ "title", "link" }].
salarystring or nullSalary text as shown by Google.
benefitsarray of strings or nullBenefit labels, when Google shows them.
job_typestring or nullEmployment type text as shown by Google.
postedstring or nullPosted text as shown by Google, for example "3 days ago".
pageinteger or nullResult page the posting was found on.
searchQuerystringThe query that found the posting.
searchLocationstring or nullThe location that found the posting, or null if none was set.
countrystringThe country code used for the search.
salaryMin, salaryMaxnumber or nullSalary range parsed from salary. Same value when there is one number.
salaryCurrencystring or nullISO 4217 code (USD, GBP, EUR, INR). Null when the currency is unclear.
salaryPeriodstring or nullhour, day, week, month or year.
postedDatestring or nullYYYY-MM-DD (UTC): run start time minus the relative time in posted.
postedHoursAgointeger or nullThe same relative time in hours (a month counts as 30 days).
jobTypesarray or nullSubset of FULLTIME, PARTTIME, CONTRACTOR, INTERN.
workModestring or nullremote or hybrid when the title or location says so; otherwise null (null does not mean on-site).

A field is null when Google does not show it. The structured fields are parsed from English and German text only; for other text they are null.

Example item (abridged, company name replaced):

{
"job_id": "RtLv7vlPTbn2E40SAAAAAA==",
"title": "Staff Software Engineer - Card Technology",
"company": "Example Corp",
"location": "New York, NY (+3 others)",
"description": "Example Corp is hiring a Staff Software Engineer for its card technology team. ...",
"highlights": [{ "title": "Qualifications", "items": ["8+ years of software engineering experience"] }],
"apply_options": [{ "title": "Example Corp Careers", "link": "https://careers.example.com/jobs/12345" }],
"salary": "$150K–$200K a year",
"benefits": ["Health insurance"],
"job_type": "Full-time",
"posted": "3 days ago",
"page": 1,
"searchQuery": "software engineer",
"searchLocation": "New York, NY",
"country": "us",
"salaryMin": 150000,
"salaryMax": 200000,
"salaryCurrency": "USD",
"salaryPeriod": "year",
"postedDate": "2026-11-05",
"postedHoursAgo": 72,
"jobTypes": ["FULLTIME"],
"workMode": null
}

Supported countries

CodeCountryLanguagesDefault language
usUnited Statesenen
gbUnited Kingdomenen
inIndiaen, hien
deGermanyde, ende

A language that is not in the list for the chosen country is still searched, with a warning in the log that results may be sparse. A country outside this list fails the run at start.

Use with AI agents and the API

Python, with the apify-client package:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("krammer/google-jobs-scraper").call(run_input={
"queries": ["machine learning engineer"],
"locations": ["Berlin"],
"country": "de",
"language": "en",
"datePosted": "7d",
"maxResultsPerSearch": 30,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
print(job["title"], "|", job["company"], "|", job["salaryMin"], job["salaryCurrency"])

curl (starts the run, waits for it to finish and returns the dataset items; for large inputs use the asynchronous run endpoint instead):

curl -X POST "https://api.apify.com/v2/acts/krammer~google-jobs-scraper/run-sync-get-dataset-items" \
-H "Authorization: Bearer <YOUR_APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"queries": ["registered nurse"], "locations": ["Chicago, IL"], "maxResultsPerSearch": 20}'

Every input field has a description written for AI agents, so tools that read the input schema (for example the Apify MCP server) can read what each field is for.

Limits

  • Each search delivers at most maxResultsPerSearch jobs (1 to 200, default 100).
  • At most 100 searches per run (queries x locations), at most 20 queries and 20 locations.
  • The number of results depends on what Google shows for the query. A search can return fewer jobs than the maximum.
  • If you set a maximum total charge for the run, the run stops when it is reached and keeps the jobs already delivered.

FAQ

Why did I get fewer jobs than maxResultsPerSearch? Google may have fewer postings for that query. Also, the datePosted and jobTypes filters are applied to the results Google returns; the Actor does not fetch extra results to make up for removed ones. Duplicates and postings without a title or company are removed too.

Am I charged when a search returns nothing? No. A results page is charged only if it contains at least one job posting with a title and company. If Google returns no results, nothing is charged. Pages whose jobs are all removed by your filters, or were all delivered by an earlier search in the same run, are still charged, because those pages were fetched. The log explains why a search delivered nothing.

What counts as a duplicate? Postings with the same job_id inside one run. The first one is kept and later ones are dropped from the dataset. Billing is per results page, so the page that contained a duplicate is still charged. Runs do not share this memory, so a later run delivers the same posting again.

How do the filters work? datePosted keeps jobs whose postedHoursAgo is within 24 hours, 3 days, 7 days or 30 days. jobTypes keeps jobs whose jobTypes has at least one of the types you list. If Google does not show the posting time of a job, the job is kept (postedHoursAgo is null). If Google does not show the type of a job, the job is removed when jobTypes is set.

Does remoteOnly remove on-site jobs? No. It adds the word "remote" to the search text, so the search asks for remote jobs, but the results are not filtered. Use the workMode field of the output if you need to check each job.

Billing and failures

  • You are charged once for each Google results page fetched that contains at least one valid job posting: $0.028 to $0.09 per results page (up to 10 jobs), depending on your Apify plan (Free plan $0.09, Starter $0.036, Scale $0.032, Business $0.028).
  • You are not charged for searches with no results, pages with only invalid jobs (missing title or company), or searches that failed.
  • Pages are charged even if all their jobs were removed by your filters or were duplicates of an earlier search in the run.
  • If some searches fail, the run still finishes as SUCCEEDED. The status message says so, for example "Partially completed: 12 jobs delivered; 1 of 3 searches failed (...)". Result pages that were fetched are charged; failed searches are not. If no search could be fetched at all, the run is FAILED and nothing is charged.
  • The RUN_SUMMARY record in the default key-value store lists the outcome, the number of jobs, the failure reasons and the request ids of failed searches.
  • If the platform migrates your run to another server, the last batch of jobs may be sent again once. This is a known window.
  • Free Apify plans have a monthly allowance for this Actor. The allowance counts every result retrieved for your searches, including duplicates and jobs removed by your filters, because those results are still fetched. When it is used up, the run stops, nothing more is charged, and the status message shows the amount used. Paid Apify plans are not limited. The allowance resets at the start of each month (UTC).