# Google Jobs Scraper & API: Salaries and Apply Links (`vncntlabs/google-jobs-scraper`) Actor

Google Jobs scraper and API for any job title in 76 countries: company, parsed salary, employment type, posted date, every job board with its apply link, highlights and optional full description. Remote, date and type filters, de-duplicated, plus a monitor mode that returns only new jobs.

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

## Pricing

from $2.00 / 1,000 job scrapeds

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 & API: salaries, apply links on every job board and new-job monitor

**Google Jobs scraper and API.** Search Google Jobs for any job title in 76 countries and get clean listings: company, location, salary parsed into numbers, employment type, posting date, every job board the job is posted on with its apply link, Google's qualifications, responsibilities and benefits, and optionally the full description. Run many titles x many locations at once, de-duplicated, or schedule monitor mode to get only new jobs.

Data comes from Google Jobs through a licensed SERP data API. There is no browser scraping, so there are no captchas and no proxies to pay for.

**Who it's for**

- Recruiters and staffing agencies sourcing openings and hiring companies.
- Job boards and aggregators filling their feeds.
- Sales teams finding companies that are hiring (a strong buying signal).
- Labor-market and salary researchers.
- Job seekers who want a daily feed of fresh openings.

### What you get

| | |
|---|---|
| **Search** | Job titles/keywords x locations (city, state/region, country or "Remote"), up to 50 queries and 10 locations per run, up to 200 jobs per search |
| **Filters** | Remote (only / exclude), date posted (24 h, 3 days, week, month), employment type (full-time, part-time, contractor, internship, temporary) |
| **Every job** | Title, company, logo, location, remote flag, primary source ("via LinkedIn") and its direct apply URL, salary text plus min/max/currency/period and yearly equivalents, employment types, posted date and "posted ago" |
| **Job boards** | `applyOptions`: every site listing the job (LinkedIn, Indeed, Glassdoor, ZipRecruiter, the company's careers page...) with an apply link and a "direct" flag. On average 4-7 boards per job |
| **Details** | Qualifications, responsibilities and benefits lists; full description text (optional) |
| **De-duplication** | The same job found by several queries or locations is returned once |
| **Monitor** | Schedule it: each run returns only jobs this monitor has not returned before |

### Input examples

Data analyst and nurse jobs in two cities:

```json
{ "queries": ["data analyst", "registered nurse"], "locations": ["Austin, TX", "Chicago, IL"], "maxJobsPerSearch": 50 }
```

Remote, full-time Python jobs posted this week, with descriptions:

```json
{ "queries": ["python developer"], "locations": ["Remote"], "postedWithin": "week",
  "employmentTypes": ["full_time"], "includeDescription": true }
```

Daily feed of new openings (schedule it in Apify):

```json
{ "mode": "monitor", "queries": ["product manager"], "locations": ["London", "Berlin"],
  "monitorStoreName": "pm-europe" }
```

**Locations** can be:

- `Austin, TX`, `Austin, Texas`, `Portland, Oregon`, `Toronto`, `Bangalore` (cities; add the state or country when a name is ambiguous; the run summary tells you which place was used)
- `Texas`, `Ontario, Canada`, `England` (regions)
- `United States`, `UK`, `Germany`, `India`... (76 supported countries; not Australia or Mexico)
- `Remote` (remote jobs in the US) or `Remote, United Kingdom`
- A DataForSEO location code such as `2840`

### Output

**Job row** (`type: "job"`), trimmed:

```json
{
  "jobId": "8IaZDCaCasjzUqz9AAAAAA==", "title": "Software Engineer (.NET, C# and Angular)", "company": "Numerator",
  "location": "United States", "isRemote": false, "via": "LinkedIn",
  "applyUrl": "https://www.linkedin.com/jobs/view/software-engineer-net-c%23-and-angular-at-numerator-4479791958",
  "applyBoards": ["LinkedIn", "Talents By Vaia", "Rovio"], "applyOptionsCount": 3,
  "applyOptions": [{ "source": "LinkedIn", "url": "https://www.google.com/goto?url=...", "direct": false }],
  "salary": "$91.8K–$138K a year", "salaryMin": 91800, "salaryMax": 138000, "salaryCurrency": "USD",
  "salaryPeriod": "year", "salaryYearlyMin": 91800, "salaryYearlyMax": 138000,
  "employmentType": "Full-time", "employmentTypes": ["full_time"],
  "postedAt": "2026-10-14T14:41:50Z", "postedAgo": "2 days ago", "daysSincePosted": 2,
  "qualifications": ["Strong Angular skills", "..."], "responsibilities": ["..."], "benefits": ["..."],
  "query": "software engineer", "searchLocation": "United States", "rankInSearch": 1
}
```

**Every run also writes:**

- A `search` row per query x location: `status` (`ok`, `no_results`, `error`, `not_processed`), jobs found, removed by filters, duplicates merged, delivered, charged, and the Google search URL.
- `skipped` rows for invalid or duplicate inputs (for example an unknown city).
- A run summary in the `OUTPUT` record.

Dataset views: **Jobs**, **Salaries**, **Run summary per search**. Export to JSON, CSV, Excel or via the API.

### Pricing (pay per event)

You pay only for results.

| Event | Charged when |
|---|---|
| **Job scraped** | Each job delivered to your dataset (monitor mode: each *new* job) |
| **Search processed** | Each query x location for which Google returned jobs (searches with no results are free) |
| **Actor start** | Once per run (Apify standard) |

**Never charged:** invalid inputs, searches with no results, provider errors and timeouts, duplicates removed across searches.

Set a maximum charge per run and the Actor stops cleanly before going over it.

**Apify free plan:** up to 3 queries, 1 location and 30 jobs per search per run.

### Good to know

- **Apply links.** `applyUrl` is the direct link of the primary listing (the "via" site). The links in `applyOptions` are Google redirect links (`google.com/goto?...`) that open the job on each board; they are what Google Jobs itself uses.
- **Filters run on the results.** Google Jobs only partly honours date and type filters, so the Actor applies them itself on each job and, when any filter is on, fetches up to twice as many results to compensate. Each search row shows how many jobs each filter removed. You are only charged for jobs delivered.
- **Dates.** About a third of listings show no posting date. With a date filter they are dropped unless *Keep jobs without a posting date* is on. `postedAt` is computed from Google's "3 days ago" text when no exact time is given.
- **Salaries** are shown for roughly 20-40% of jobs (more in the US). `salaryYearlyMin/Max` convert hourly/daily/weekly/monthly pay (2,080 hours, 260 days, 52 weeks, 12 months per year).
- **Speed.** Searches run in parallel through a queued API, in batches of up to 50: each batch usually takes 30-90 seconds. Monitor mode uses the standard (cheaper) queue and can take a few minutes.
- **Monitor runs.** Each query x location x filter combination keeps its own memory in your named key-value store. A job is new when the monitor has never returned it and it was posted after the previous run (minus a 2-day grace window) or has no date. Jobs cut off by your maximum charge or beyond *Max jobs per search* are not marked as seen, so they show up in the next run. Run one schedule per store name at a time.
- **Languages.** Pick the Google interface language; job texts stay in their original language. Salary parsing understands common currency and number formats (e.g. `50.000 €`, `₹6L`). Exact posting times are used in every language; relative "3 days ago" texts are parsed in English only.

### FAQ

**Is this legal?** Google Jobs results are public. This Actor retrieves them through a licensed third-party SERP API and does not log in or bypass any protection. You are responsible for how you use the data, including personal data protection laws.

**Why are there fewer jobs than I asked for?** Google Jobs has no more matches for that search and place, your filters removed some (see the search row), or duplicates were merged.

**Which countries are supported?** 76 countries: Algeria; Angola; Antigua and Barbuda; Austria; Bahrain; Bangladesh; Belgium; Belize; Bolivia; Botswana; Brazil; Canada; Costa Rica; Denmark; Dominica; Egypt; El Salvador; Ethiopia; France; Germany; Ghana; Greece; Guyana; India; Indonesia; Iraq; Italy; Japan; Jordan; Kazakhstan; Kenya; Kuwait; Kyrgyzstan; Lebanon; Lesotho; Libya; Malawi; Malaysia; Mauritius; Morocco; Mozambique; Namibia; Netherlands; Nigeria; Oman; Pakistan; Philippines; Portugal; Qatar; Rwanda; Saint Helena, Ascension and Tristan da Cunha; Saint Vincent and the Grenadines; Saudi Arabia; Seychelles; Sierra Leone; Singapore; Somalia; South Africa; Spain; Sri Lanka; Suriname; Switzerland; Tanzania; Thailand; The Bahamas; The Gambia; Trinidad and Tobago; Tunisia; Uganda; United Arab Emirates; United Kingdom; United States; Uzbekistan; Vietnam; Zambia; Zimbabwe. Not available: Australia, Mexico and other countries not listed.

**Attribution.** Place-name ranking uses population data from GeoNames (geonames.org, CC BY 4.0).

**Not affiliated with Google.** "Google" is a trademark of Google LLC and is used here only to describe the data source.

Questions or a missing feature? Open an issue on the Actor page.

# Actor input Schema

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

One search per line, as you would type it into Google Jobs (e.g. <code>data analyst</code>, <code>python developer</code>, <code>barista</code>). Up to 50. Every query is searched in every location.

## `locations` (type: `array`):

City, state/region or country, one per line: <code>Austin, TX</code>, <code>London</code>, <code>Ontario, Canada</code>, <code>Germany</code>. <code>Remote</code> = remote jobs in the United States; <code>Remote, United Kingdom</code> for another country. Up to 10. 76 countries are supported (not Australia or Mexico).

## `maxJobsPerSearch` (type: `integer`):

Jobs per query x location, in Google's order. Google Jobs shows up to about 200 per search.

## `mode` (type: `string`):

<b>Monitor</b>: schedule it (e.g. daily); each run returns only jobs this monitor has not returned before, so you get a feed of fresh openings.

## `remote` (type: `string`):

Remote only adds 'remote' to the search and keeps jobs Google marks as remote/anywhere or that say remote in the title or location.

## `postedWithin` (type: `string`):

Keep jobs posted within this period.

## `includeUndated` (type: `boolean`):

About a third of Google Jobs listings show no posting date. With a date filter they are dropped unless this is on.

## `employmentTypes` (type: `array`):

Keep jobs of any of these types (empty = all). Jobs whose type Google doesn't show are dropped when this is set.

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

Google interface language for the search (job texts stay in their original language).

## `includeApplyOptions` (type: `boolean`):

applyOptions: every site the job is posted on (LinkedIn, Indeed, company site, ...) with its apply link, plus applyBoards (names only).

## `includeHighlights` (type: `boolean`):

Google's job highlights as lists.

## `includeDescription` (type: `boolean`):

Adds the full description text (often 3-10 KB per job).

## `dedupeAcrossSearches` (type: `boolean`):

A job found by several queries or locations is returned (and charged) once, for the first search that found it.

## `monitorStoreName` (type: `string`):

Monitor mode keeps the job IDs it has seen in this named key-value store in your Apify account. Use different names for independent monitors.

## `monitorFirstRun` (type: `string`):

What the very first monitor run returns for a search.

## Actor input object example

```json
{
  "queries": [
    "data analyst",
    "registered nurse"
  ],
  "locations": [
    "United States"
  ],
  "maxJobsPerSearch": 30,
  "mode": "jobs",
  "remote": "any",
  "postedWithin": "any",
  "includeUndated": false,
  "employmentTypes": [],
  "language": "en",
  "includeApplyOptions": true,
  "includeHighlights": true,
  "includeDescription": false,
  "dedupeAcrossSearches": true,
  "monitorStoreName": "google-jobs-monitor",
  "monitorFirstRun": "return_all"
}
```

# Actor output Schema

## `jobs` (type: `string`):

No description

## `searches` (type: `string`):

No description

## `summary` (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": [
        "data analyst",
        "registered nurse"
    ],
    "locations": [
        "United States"
    ],
    "maxJobsPerSearch": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("vncntlabs/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": [
        "data analyst",
        "registered nurse",
    ],
    "locations": ["United States"],
    "maxJobsPerSearch": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("vncntlabs/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": [
    "data analyst",
    "registered nurse"
  ],
  "locations": [
    "United States"
  ],
  "maxJobsPerSearch": 30
}' |
apify call vncntlabs/google-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vncntlabs/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/a8Drgg6jOl72Cjb1m/builds/GIn90c0IKf1Emtk4g/openapi.json
