# Google Jobs Scraper: Salaries, Descriptions, Apply Links (`datagleaner/google-jobs-scraper`) Actor

Scrape Google Jobs listings for any job search and place in 43 countries: title, company, location, source site, posted age, employment type, salary, full description, highlights and direct apply links. Up to ~80 jobs per search, date and job-type filters, no browser. $2 per 1,000 jobs.

- **URL**: https://apify.com/datagleaner/google-jobs-scraper.md
- **Developed by:** [Data Gleaner](https://apify.com/datagleaner) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Jobs Scraper: Salaries, Descriptions, Apply Links

**Google Jobs Scraper** turns any Google Jobs search into a clean table of job postings. Give it a search such as `registered nurse`, `data analyst` or `warehouse associate` and a place such as `Chicago, IL`. For each job you get the title, company, location, the site Google found it on (LinkedIn, Indeed, the employer's careers page...), posted age and an approximate posting date, employment type, salary as numbers with currency and period, Google's job highlights (qualifications, benefits, responsibilities), the **full description**, and **every "Apply on" link** as a direct URL. It covers **43 countries**, reaches **about 40 to 80+ distinct jobs per search** on busy searches, and filters by date posted and employment type. There is no browser and no login to set up. It costs **$2 per 1,000 jobs**, with no start fee.

### What you can do with it

- **Job market and salary research.** Pull the jobs for a role and city, then compare pay ranges (`salaryMin`, `salaryMax`, `salaryPeriod`), employers and job boards across cities or countries.
- **Recruiting and staffing leads.** See which companies are hiring for the roles you place, where they post, and how fresh each posting is (`postedAt`).
- **Job boards and aggregators.** Feed new postings with the full description and the original apply URLs into your own site or newsletter. Run it daily with `datePosted: "today"`.
- **Career tools and AI agents.** Clean, consistent fields in every country, ready for a spreadsheet, a matching model or an LLM prompt.
- **Labor market monitoring.** Track how many postings a role gets per week, which skills show up in the qualifications, and how many list a salary.

### Input

| Field | Type | What it does |
|---|---|---|
| `queries` | list of text | Searches as you would type them into Google Jobs: a title or skill (`nurse`, `python developer`). You can include the place (`warehouse jobs London`). Each search returns its own rows. |
| `location` | text | Optional. A city, region or "remote", added to every search (`Chicago, IL`, `Berlin`, `Toronto, ON`). Leave it empty when your searches already name the place. |
| `country` | code | The Google country: `us` (default), `uk`, `ca`, `au`, `de`, `fr`, `in` and 36 more. It decides which boards and employers Google shows when a search names no place. |
| `language` | code | Google's interface language, default `en`. It changes labels such as "Posted 3 days ago" and helps Google read filter words. Descriptions stay in the language they were written in. |
| `maxJobsPerQuery` | number | Default 50, max 150. Stop each search after this many distinct jobs. |
| `datePosted` | choice | `any` (default), `today`, `3days`, `week` or `month`. Jobs whose posted age is older than the window are dropped and not charged. |
| `employmentType` | choice | `any` (default), `fullTime`, `partTime`, `contractor` or `internship`. |
| `expandSearch` | yes/no | Default on: go past Google's first 10 jobs (see "How it gets more than 10 jobs"). Off: only the first 10, the cheapest and fastest option. |
| `maxConcurrency` | number | How many searches run in parallel. Default 3. |
| `proxyConfiguration` | proxy | Keep the default, Apify Proxy's Google SERP group. It is included in the price. |

Example:

```json
{
  "queries": ["registered nurse", "warehouse associate"],
  "location": "Chicago, IL",
  "country": "us",
  "maxJobsPerQuery": 60,
  "datePosted": "week"
}
```

An empty input `{}` runs a small example (5 jobs for "data analyst" in New York, NY), and the status message says so.

### Output

One row per job posting. Example (description shortened):

```json
{
  "position": 4,
  "title": "Registered Nurse - Healthcare Transformation Collaborative",
  "company": "Endeavor Health",
  "location": "Chicago, IL",
  "via": "Indeed",
  "postedAge": "5 days ago",
  "postedAt": "2026-10-16",
  "employmentType": "Full-time",
  "salary": "$37.25–$57.74 an hour",
  "salaryMin": 37.25,
  "salaryMax": 57.74,
  "salaryPeriod": "hour",
  "salaryCurrency": "USD",
  "workFromHome": null,
  "qualificationNote": "No degree mentioned",
  "benefits": ["Health insurance", "Dental insurance", "Paid time off"],
  "highlights": [
    {"title": "Qualifications", "items": ["Graduate from an accredited school of nursing", "Current Illinois Nursing licensure"]},
    {"title": "Benefits", "items": ["Tuition Reimbursement", "Retirement Options with Company Match"]},
    {"title": "Responsibilities", "items": ["Full Time, 40 hours", "Promotes safety measures to prevent patient and staff injuries"]}
  ],
  "description": "Registered Nurse - Healthcare Transformation Collaborative\n\nEndeavor Health is ...",
  "applyLinks": [
    {"source": "Indeed", "url": "https://www.indeed.com/viewjob?jk=..."},
    {"source": "LinkedIn", "url": "https://www.linkedin.com/jobs/view/..."}
  ],
  "applyUrl": "https://www.indeed.com/viewjob?jk=...",
  "otherTags": [],
  "jobId": "3rFQ6HlgQ6v4RFGcAAAAAA==",
  "googleJobUrl": "https://www.google.com/search?ibp=htl;jobs&q=registered+nurse+Chicago,+IL&htidocid=...",
  "searchQuery": "registered nurse",
  "searchLocation": "Chicago, IL",
  "country": "us",
  "language": "en",
  "searchVariant": "first page",
  "scrapedAt": "2026-10-21T19:10:03+00:00"
}
```

| Field | What it holds |
|---|---|
| `title`, `company`, `location` | As Google Jobs shows them. `location` can be "Anywhere" for remote jobs. |
| `via` | The site Google found the posting on: LinkedIn, Indeed, Glassdoor, a staffing agency, the employer's own careers site. |
| `postedAge`, `postedAt` | "3 days ago" as shown, and the approximate date it means (ISO 8601). |
| `employmentType` | "Full-time", "Part-time", "Contractor", "Internship", or a mix ("Full-time and Part-time"), in the page language. |
| `salary`, `salaryMin`, `salaryMax`, `salaryPeriod`, `salaryCurrency` | The pay text as shown, and the same as numbers: min, max, `hour` / `day` / `week` / `month` / `year`, and the ISO currency code. Set only when Google shows a salary. |
| `highlights` | Google's extracted job highlights, as `{title, items}` groups (Qualifications, Benefits, Responsibilities), all items included. |
| `description` | The full job description text, line breaks kept. |
| `applyLinks`, `applyUrl` | Every "Apply on" option as `{source, url}`, where `url` is the posting itself (not a Google redirect), with Google's tracking parameters removed. `applyUrl` is the first. |
| `benefits`, `qualificationNote`, `workFromHome`, `otherTags` | The chips on the job card: "Health insurance", "No degree mentioned", work from home. |
| `jobId`, `googleJobUrl` | Google's id for the posting (use it to match a job across runs) and a link that opens it in Google Jobs. |
| `searchQuery`, `searchLocation`, `country`, `language`, `searchVariant`, `scrapedAt` | Where the row came from: your search, and which narrower search found it (see below). |

Fill rates on 251 jobs from Apify runs in the US, UK and Germany (2026-10-22): title, company, location, source, description, apply links and job id 100%, employment type 96%, posted age 79%, Google highlights 49%, salary 47%, benefit chips 33%. 77% of descriptions are over 1,000 characters. A field is `null` (or an empty list) when Google does not show it for that job.

### How it gets more than 10 jobs

Google Jobs shows 10 jobs, then loads more only by scrolling inside a browser. This Actor does not run a browser. After the first 10, it runs **narrower searches of the same query**, each of which returns its own top 10: recent postings ("posted in the last 3 days", "posted this week"), Google's own filter chips for that search (such as "Remote" or "No degree"), employment types (part time, full time, internship, contractor), seniority (entry level, senior), and Google's date and distance tools. It merges them by `jobId`, so a job is saved and charged only once. Each row's `searchVariant` says which search found it ("first page", "part time", "Google filter: Remote"...), so you can keep or drop any of them. Rows found through the "Remote" chip can be remote jobs outside your city.

On Apify (2026-10-22): `registered nurse` and `warehouse associate` in Chicago reached 60 of 60 jobs each, `data analyst` and `electrician` in London 50 of 50 each. A narrow or filtered search stops sooner: `Lagerarbeiter` in Berlin, posted this week and full time, returned 21. The Actor stops a search when four narrower searches in a row add almost nothing new, and says so in the log.

### How much does it cost to scrape Google Jobs?

You pay per job saved to the dataset. This price is final:

| Event | Price | Per 1,000 |
|---|---|---|
| `job`: one job posting row | $0.002 | $2 |

There is no start fee. Nothing is charged for failed pages, retries, duplicates, or jobs dropped by the date filter. Platform usage and the Google SERP proxy are included in the price. The run stops by itself when it reaches your **maximum total charge**.

Examples:

- **One role in one city** (`registered nurse`, Chicago, 60 jobs): **$0.12**.
- **Salary research:** 20 roles × 50 jobs = 1,000 jobs = **$2.00**.
- **Daily new-jobs feed:** 30 searches × 20 jobs posted since yesterday, for a month = 18,000 jobs = **$36**.

### Limits

- **Google's first page holds 10 jobs**, and the rest come from narrower searches, so the total per search depends on how much Google has: about 40 to 80+ for busy roles in big cities, fewer for niche roles or tight filters. The maximum is 150 per search. To cover more, split by city or add related titles.
- **Speed.** Each Google page takes 2 to 70 seconds. On Apify, 2 searches of 60 jobs (22 pages) took about 3 minutes, and 2 searches of 50 jobs took about 2 minutes. Searches run in parallel (`maxConcurrency`).
- **Salary** appears only when the posting or Google shows one (about half of US postings). Descriptions on some boards are a preview of a few hundred characters, because that is all Google has.
- **Posted dates are approximate**: "3 days ago" becomes the date three days before the run.
- **Order.** `position` follows the order the jobs were found: the first page in Google's order, then each narrower search.
- Google can change its pages at any time. The Actor retries failed pages on a fresh connection, and the status message names any search that got no answer or had no matches. A run where nothing at all came back ends as FAILED with the reason, never as an empty success.

### Use with Python

```python
## pip install apify-client
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("datagleaner/google-jobs-scraper").call(
    run_input={"queries": ["data analyst"], "location": "Austin, TX", "maxJobsPerQuery": 50}
)
for job in client.dataset(run.default_dataset_id).iterate_items():
    print(job["title"], "|", job["company"], "|", job["salary"], "|", job["applyUrl"])
```

### FAQ

**Does it need a Google account, cookies or my own proxy?** No. It reads Google's public Jobs results through Apify Proxy's Google SERP group, which is included in the price.

**Can I get only new jobs every day?** Yes. Set `datePosted` to `today` and schedule the Actor daily. Use `jobId` to skip jobs you already have.

**Why do some rows have a different city?** Google Jobs sometimes includes nearby towns, and the "Remote" filter chip finds remote jobs. Check `location` and `searchVariant`, or set `expandSearch` to off for the first 10 jobs only.

**Which countries work?** 43, including the US, UK, Canada, Australia, India, Germany, France, Spain, Italy, the Netherlands, Japan, Singapore, Brazil and Mexico. Pick the `country` and, for local labels, the `language`.

**Are the apply links real?** Yes. Each `applyLinks` URL is the posting on the job board or careers site, without Google's redirect and without Google's `utm_` tracking parameters.

### Responsible use

This Actor collects job postings that Google shows publicly to anyone. It does not log in or collect private data. Job postings can include recruiters' names or contact details. If you store or process personal data, you are responsible for doing so lawfully (for example under the GDPR or CCPA), and for following the terms of the sites you use the data with.

# Actor input Schema

## `queries` (type: `array`):

What you would type into Google Jobs: a job title or skill (nurse, data analyst, python developer), optionally with a place (warehouse jobs London). One row per job posting found.

## `location` (type: `string`):

City, region or 'remote', added to every search (Chicago, IL / Berlin / Toronto, ON). Leave empty when your searches already name the place.

## `country` (type: `string`):

The Google country the search runs in. It decides which job boards and employers Google shows when the search names no place. The search is placed in the country's largest city.

## `language` (type: `string`):

Google interface language as a code (en, de, fr, es...). It changes labels such as 'Posted 3 days ago' and helps Google read filter words; job descriptions stay in the language they were written in.

## `maxJobsPerQuery` (type: `integer`):

Stop each search after this many distinct jobs. Google Jobs shows 10 jobs per results page; past 10 the Actor runs narrower searches of the same query (date windows, Google's own filter chips, employment types) and merges them without duplicates. Busy searches reach about 40 to 80 distinct jobs; niche ones fewer.

## `datePosted` (type: `string`):

Only jobs posted in this window. Google's date filter is used, and any job whose posted age is older is dropped before it is saved (and not charged).

## `employmentType` (type: `string`):

Only this kind of job, using Google Jobs' own employment-type matching.

## `expandSearch` (type: `boolean`):

On: reach up to Max jobs per search with narrower searches of the same query. Off: only the 10 jobs on Google's first page (cheapest and fastest). Rows found by a narrower search say which in searchVariant.

## `maxConcurrency` (type: `integer`):

How many searches run at once. Each Google page takes 5-70 seconds, so more parallel searches finish a long list sooner.

## `proxyConfiguration` (type: `object`):

Keep the default: Apify Proxy's Google SERP group, which is included in the price. Google sends other datacenter IPs a JavaScript page with no jobs.

## Actor input object example

```json
{
  "queries": [
    "software engineer"
  ],
  "location": "New York, NY",
  "country": "us",
  "language": "en",
  "maxJobsPerQuery": 10,
  "datePosted": "any",
  "employmentType": "any",
  "expandSearch": true,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "GOOGLE_SERP"
    ]
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "software engineer"
    ],
    "location": "New York, NY",
    "maxJobsPerQuery": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "GOOGLE_SERP"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datagleaner/google-jobs-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "queries": ["software engineer"],
    "location": "New York, NY",
    "maxJobsPerQuery": 10,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["GOOGLE_SERP"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("datagleaner/google-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "software engineer"
  ],
  "location": "New York, NY",
  "maxJobsPerQuery": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "GOOGLE_SERP"
    ]
  }
}' |
apify call datagleaner/google-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datagleaner/google-jobs-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/YWd7VWadTeAOSn9mm/builds/SbjVjWxg97P7ngl6o/openapi.json
