# Google Jobs Scraper - Most Comprehensive (`kaix/google-jobs-scraper`) Actor

🔥 ~$0.5/1K jobs 🔥 Collect public Google Jobs results by keyword, location, date, job type, remote status, education signal and employer's website. Export normalized job details and application links without a Google account.

- **URL**: https://apify.com/kaix/google-jobs-scraper.md
- **Developed by:** [Kai](https://apify.com/kaix) (community)
- **Categories:** Jobs, Lead generation, Integrations
- **Features:** Limited permissions
- **Stats:** 16 total users, 5 monthly users, 94.4% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.04 / 1,000 jobs

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

Collect public Google Jobs results by job title, skill, location, or Google Jobs search URL. Get descriptions, salary data, qualifications, benefits, employer information, and application links when Google supplies them.

Find emails, phone numbers, and social profiles on employer websites. Search in a selected country and language. Save each job as an Apify Dataset item. No Google account is required.

### Use cases

- Recruitment research: find open roles by skill, employer, employment type, and location.
- Vacancy monitoring: repeat a search and compare the saved job datasets.
- Salary research: collect published pay ranges, currencies, and pay periods.
- Employer research: collect company websites, ratings, and published website contacts.
- Job data collection: build a dataset of descriptions, qualifications, benefits, responsibilities, and application links.

### Choose how to search

| Starting point | Input | Use it for |
| --- | --- | --- |
| A job title or skill | `keyword` and optional `location` | Search for jobs in an area. |
| An existing Google Jobs search | `searchUrl` | Keep the search text and URL filters. |

Each run accepts one keyword and one location, or one search URL. If you supply `searchUrl`, its search text takes priority over `keyword` and `location`.

### Choose what to collect

| Option | Default | Effect |
| --- | --- | --- |
| `includeJobDetails` | `false` | Request extra job details, including descriptions, employer websites, and ratings when available. Details already in the search results are kept with this option off. |
| `enrichContacts` | `false` | Read employer websites for emails, phone numbers, and social profiles. |

Website contacts work with either setting of `includeJobDetails`. A job must have an employer website supplied in the search results or extra job details. Contact collection is off by default.

### Search jobs in a location

```json
{
  "keyword": "software engineer",
  "location": "Bengaluru",
  "maxItems": 100,
  "locale": {
    "countryCode": "IN",
    "languageCode": "en"
  }
}
```

The location is part of the search text. For this example, the Actor searches for `software engineer jobs in Bengaluru`. Google selects the matching jobs. The location does not set a strict geographic boundary.

The Actor collects more results when needed. `maxItems` is an upper limit, not a required result count. It accepts a positive integer with no fixed upper cap. Google can return fewer jobs than requested.

#### Use a Google Jobs URL

```json
{
  "searchUrl": "https://www.google.com/search?q=certified+nursing+assistant+jobs+Fresno+CA&udm=8&gl=us&hl=en",
  "maxItems": 50,
  "includeJobDetails": true
}
```

Use an HTTPS Google search URL with a non-empty `q` parameter and either `udm=8` or `ibp=htl;jobs`. A selected-job URL fragment does not request that specific job. The Actor uses the search.

Country and language come from URL `gl` and `hl` values unless `locale` supplies them. The search text and encoded filters are kept. `locale`, `googleDomain`, and `filters.radiusKm` can replace URL settings.

#### Set the country, language, and Google domain

```json
{
  "keyword": "software engineer",
  "location": "Berlin",
  "googleDomain": "google.de",
  "locale": {
    "countryCode": "DE",
    "languageCode": "de"
  },
  "maxItems": 50
}
```

`locale.countryCode` controls Google `gl`. `locale.languageCode` controls Google `hl`. Use `"auto"` for the language to let Google select it. `googleDomain` sets the Google domain. These are separate controls.

#### Filter recent jobs by employment type

```json
{
  "keyword": "certified nursing assistant",
  "location": "Fresno, CA",
  "locale": {
    "countryCode": "US",
    "languageCode": "en"
  },
  "maxItems": 50,
  "filters": {
    "datePosted": "week",
    "jobTypes": ["full-time"],
    "radiusKm": 30,
    "salaryOnly": true
  }
}
```

Date, employment type, remote work, and no-degree filters are Google job filters. Salary, posting age, employer name, and source name filters use the returned job fields. The radius is a Google filter. Jobs outside that radius can appear.

#### Find employer contacts

```json
{
  "keyword": "nurse",
  "location": "Fresno, CA",
  "locale": {
    "countryCode": "US",
    "languageCode": "en"
  },
  "maxItems": 20,
  "includeJobDetails": true,
  "enrichContacts": true
}
```

This example requests job details and reads available employer websites for contacts. Contact collection can increase run time. A website error does not remove the job.

### Input reference

Supply `keyword` or `searchUrl`. Fields not listed here are not accepted. Each run saves its own results without checking jobs from previous runs.

| Field | Type | Default | Effect |
| --- | --- | --- | --- |
| `keyword` | string | none | Job title, skill, or search text. Required without `searchUrl`. Between 1 and 200 characters. |
| `location` | string | none | One city, region, country, or other location label. Up to 200 characters. |
| `searchUrl` | string | none | One HTTPS Google Jobs search URL. Its search text takes priority. |
| `googleDomain` | string | URL host or `google.com` | A supported Google search host, such as `google.com`, `google.co.uk`, or `google.co.in`. Supply the host without a URL scheme. |
| `maxItems` | integer, 1 or more | `10` | Requested maximum jobs. No fixed upper cap. |
| `includeJobDetails` | boolean | `false` | Request extra Google job details. A successful detail result has an additional charge. |
| `enrichContacts` | boolean | `false` | Read employer websites for emails, phone numbers, and social profiles. |
| `proxyConfiguration` | object | `{"useApifyProxy":true}` | Connection settings. The default Apify Proxy works. |
| `locale.countryCode` | string | URL `gl` or `IN` | Two-letter country code. Converted to uppercase. |
| `locale.languageCode` | string | URL `hl` or `en` | Google language code, such as `en`, `de`, or `zh-CN`. Converted to lowercase. `auto` lets Google select the language. |
| `fetchDetails` | boolean | `true` | No effect. Kept for older saved inputs. Use `includeJobDetails` to request extra details. |

#### Filter reference

| Field | Type or values | Default | Effect |
| --- | --- | --- | --- |
| `filters.datePosted` | `any`, `past-day`, `3-days`, `week`, `month` | `any` | Use Google's date filter. |
| `filters.jobTypes` | string\[] | `[]` | Use `full-time`, `part-time`, `contract`, and/or `internship`. Search each selected type. |
| `filters.remoteOnly` | boolean | `false` | Use Google's remote work filter. |
| `filters.noDegreeMentionedOnly` | boolean | `false` | Use Google's no-degree filter. |
| `filters.radiusKm` | positive number | none | Search radius in kilometres. Jobs outside the radius can appear. |
| `filters.postedWithinHours` | positive number | none | Keep known posting dates within this age. Jobs with an unknown posting date are excluded. Relative dates are estimates. |
| `filters.salaryOnly` | boolean | `false` | Keep jobs with a salary label or salary amounts. |
| `filters.companyFilter` | string\[] | none | Keep employers whose names contain at least one supplied value. Matches ignore letter case. |
| `filters.excludeCompanies` | string\[] | none | Remove employers whose names contain any supplied value. Matches ignore letter case. |
| `filters.viaFilter` | string\[] | none | Keep source names that contain at least one supplied value, such as `LinkedIn`. Matches ignore letter case. |

### Output

Each Dataset item is one job. Website contacts are added when you request them.

#### Field groups

| Group | Fields |
| --- | --- |
| Job identity | `id`, `title`, `company`, `location` |
| Description and highlights | `description`, `highlights`, `metadata`, `signals` |
| Employment and education | `employment`, `workArrangement`, `education` |
| Pay and dates | `salary`, `dates` |
| Employer and location details | `companyDetails`, `locationDetails` |
| Applications and sources | `links`, `applyOptions`, `applyUrl`, `applyLinkCount`, `source`, `sourceLinks` |
| Website contacts | `emails`, `phoneNumbers`, `socialProfiles`, `contactsStatus` |
| Collection context | `meta`, optional `jobDetails`, optional `structuredData` |

#### Field types

| Field | Type | Contents |
| --- | --- | --- |
| `id` | string | Google job ID. |
| `title` | string | Job title. |
| `company` | string or `null` | Employer name. |
| `location` | string or `null` | Original location label. Separate city, state, and country fields are not added. |
| `metadata`, `signals` | string\[] | Job labels supplied by Google. |
| `description` | object | `text` and `html`, each a string or `null`. |
| `highlights` | object | `qualifications`, `benefits`, and `responsibilities`, each a string array. |
| `employment` | object | `types`: string\[]. Labels are kept as supplied. |
| `workArrangement` | object | `type`: `remote`, `hybrid`, `on-site`, or `unknown`; `label`: string or `null`. |
| `education` | object | `label`: string or `null`. |
| `salary` | object | Original pay text and available structured values. See below. |
| `dates` | object | Posting label, posting date, estimate flag, and closing date. See below. |
| `companyDetails` | object | Employer links, logo, and ratings. See below. |
| `locationDetails` | object | `additionalCount`, `latitude`, and `longitude`: number or `null`. Coordinates are available for some jobs only. |
| `links`, `sourceLinks` | object\[] | Each link has `label`: string or `null`, and `url`: string. Links that Google sends as redirects, such as links to review sites and to the employer website, stay as Google redirect links and can be relative. |
| `applyOptions` | object\[] | Each option has `provider`: string or `null`, `url`: string, and `direct`: boolean or `null`. |
| `applyUrl` | string or `null` | Main application URL. |
| `applyLinkCount` | number | Number of distinct application URLs. |
| `source` | object | `name`, `url`, and `domain`: string or `null`. A matching application link supplies the URL when available. |
| `meta` | object | Collection time, result position, page count, and search context. See below. |
| `jobDetails` | optional object | `status`: `loaded` or `failed`. Added when extra details are requested. A job has no `jobDetails` when it shares the employer details of another job in the run. |
| `structuredData` | optional object | Job posting data in the schema.org `JobPosting` format, when available. Its child fields vary by job. |
| `emails` | optional string\[] | Ranked email addresses from the employer website, up to ten. |
| `phoneNumbers` | optional string\[] | Distinct published website phone numbers. Separators are removed. A supplied `+` prefix and `;ext=` extension are kept. Country codes are not guessed. |
| `socialProfiles` | optional object | Profile URLs grouped by network, up to three per network. |
| `contactsStatus` | optional string | Website visit result. See [Website contacts](#website-contacts). |

#### Nested field types

| Object | Fields |
| --- | --- |
| `salary` | `text`: string or `null`; `disclosed`: boolean; `min`, `max`: number or `null`; `currency`: string or `null`; `period`: `hour`, `day`, `week`, `month`, `year`, or `null`. |
| `dates` | `postedText`, `postedAt`, `validThrough`: string or `null`; `postedAtEstimated`: boolean or `null`. Dates use ISO format. |
| `companyDetails` | `logoUrl`, `websiteUrl`, `moreJobsUrl`, `webResultsUrl`: string or `null`; `ratings`: object\[]. |
| `companyDetails.ratings[]` | `source`: string; `value`: number; `count`: number or `null`; `url`: string. |
| `socialProfiles` | `facebook`, `instagram`, `linkedin`, `twitter`, `youtube`, `tiktok`, `pinterest`, `whatsapp`: string\[] of profile URLs. `twitter` includes X profiles. |
| `meta` | `source`: `google-jobs`; `scrapedAt`: ISO date string; `position`: number; `pagesProcessed`: number; `search`: object. |
| `meta.search` | `keyword`, `countryCode`, `languageCode`: string; `location`: string or `null`. These describe the search, not the job's address. |

#### Selected job fields

This example shows some fields from one Fresno job. A full Dataset item has more fields.

```json
{
  "id": "mBdGpYoWEsTQB2vIAAAAAA==",
  "title": "Certified Nursing Assistant (CNA)",
  "company": "Sunnyside Rehab of Fresno",
  "location": "Fresno, CA",
  "employment": {
    "types": ["Full-time"]
  },
  "salary": {
    "text": "$19 an hour",
    "disclosed": true,
    "min": 19,
    "max": 19,
    "currency": "USD",
    "period": "hour"
  },
  "highlights": {
    "benefits": ["Dental insurance", "Health insurance", "Paid time off"]
  },
  "education": {
    "label": "No Degree Mentioned"
  },
  "jobDetails": {
    "status": "loaded"
  }
}
```

Phone values can use these formats:

```json
{
  "phoneNumbers": ["+14155550123", "02079460958;ext=42"]
}
```

This phone example shows the format only. It is not a contact record for the employer above.

### Search and field limits

#### Result count and pagination

There is no fixed cap on the result count. The Actor stops when it reaches `maxItems` or when Google has no more new jobs. A very large search can fail if it takes too long. If this occurs, use a lower `maxItems`.

The Actor collects more results when needed and removes duplicate jobs. No page input is needed.

#### Optional job details

With `includeJobDetails: false`, you get the descriptions and other details that Google shows in the search results. With `true`, the Actor collects more details for each job. This can increase run time.

`jobDetails.status: "loaded"` means the Actor got usable extra details for the job. It does not guarantee a website, ratings, or a description. If the extra details cannot be loaded, the job keeps the details from the search results and reports `failed`.

Jobs of one employer in a run share the employer details: `companyDetails.websiteUrl`, `logoUrl`, `moreJobsUrl`, `webResultsUrl`, and `ratings`. The Actor loads the details of one job for each employer name. The other jobs of that employer get the employer details and no `jobDetails`. They keep the other details from the search results, and they are not charged for details.

#### Country, language, and job variation

Available fields can differ by job, country, and language. Empty arrays and `null` values can mean that the information is not available for that job. Optional fields can be absent.

The Actor reads job labels in many languages. A field can be empty when Google words a label in a way that the Actor does not recognize. `applyOptions[].direct` is set for English labels only.

Salary amounts are `null` when the Actor cannot identify them. Posting dates calculated from relative labels have `postedAtEstimated: true`. Work arrangement and employment types are not taken from the description text. Benefit text is kept in `highlights.benefits`; separate benefit flags and seniority levels are not added.

#### Employer websites and application links

Application links are the employer or job board URLs when Google supplies them. Links to review sites in `sourceLinks` and `companyDetails.ratings` stay as Google redirect links and can be relative. Links inside description text are not changed.

`companyDetails.websiteUrl` is usually the domain that Google shows, such as `example.com`, with no scheme. Employer websites come from the returned job data. The Actor does not search for a missing employer website. Jobs without a website remain in the output.

#### Website contacts

With `enrichContacts`, the Actor reads the employer website and up to three linked contact, legal, team, or about pages on the same site. Jobs with the same website share one visit per run.

It finds email addresses on these pages, including protected or written-out forms such as `info [at] example [dot] com`. Addresses on the website's own domain rank first, then free mailboxes, then other domains. Placeholder and platform addresses are removed. Addresses whose domain cannot receive mail are also removed.

It collects only numbers that the website marks as phone numbers. It does not collect other digit sequences from page text. It removes duplicate numbers across pages. Supported numbers have 7 to 15 digits, with an optional `+` prefix and an optional `;ext=` extension of up to ten digits. Local numbers keep their local form.

It reads social profiles for Facebook, Instagram, LinkedIn, X, YouTube, TikTok, Pinterest, and WhatsApp. Job boards, directories, and social network pages are skipped as websites. A supported social website link can still be added as a profile.

A website can have no published contacts, or it can block automated access. The Actor stops reading a page that is too slow or too large. Contact arrays can therefore be empty.

| `contactsStatus` | Meaning |
| --- | --- |
| `scraped` | The Actor read the website. Contact arrays can still be empty. |
| `skipped` | The website is a platform or social network page. It was not read for contacts. |
| `blocked` | The website refused automated access. |
| `failed` | The website did not load, returned an error, or did not return a usable page. |

Contact fields are added only to jobs with a website when `enrichContacts` is on. Jobs without a website stay unchanged. Turning `enrichContacts` off does not add contact fields.

### Charges

You pay for each job saved to the Dataset. With `includeJobDetails` on, each job with `jobDetails.status: "loaded"` has an extra `job-detail` charge. Jobs whose extra details fail, and jobs that share the employer details of another job, are not charged for details.

If the run reaches your maximum charge limit, the Actor stops saving jobs. The result can then contain fewer than `maxItems` jobs.

# Actor input Schema

## `keyword` (type: `string`):

Job title, skill, or keyword. Supply this field or a Google Jobs URL.

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

City, region, or country, such as Bengaluru or New York.

## `maxItems` (type: `integer`):

Maximum number of jobs to save. There is no fixed upper cap. Google can return fewer jobs.

## `fetchDetails` (type: `boolean`):

No effect. Kept for older saved inputs. Use Include job details to get extra details.

## `includeJobDetails` (type: `boolean`):

Get extra job details, employer websites, and ratings when Google supplies them. Each job with loaded details has an extra charge. This can increase run time. Details shown in the search results are kept when this option is off.

## `locale` (type: `object`):

Country and language used for Google Jobs results.

## `searchUrl` (type: `string`):

One HTTPS Google Jobs search URL. The search text and URL filters are kept. The URL country and language are used unless you set the search locale.

## `googleDomain` (type: `string`):

Google domain, such as google.com, google.co.uk, or google.co.in. Google can use another domain for some searches. The country code still sets the country.

## `enrichContacts` (type: `boolean`):

Get emails, phone numbers, and social profile links from employer websites when available.

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

Connection settings. Apify Proxy is enabled by default.

## `filters` (type: `object`):

Google filters and filters applied to the returned job fields.

## Actor input object example

```json
{
  "keyword": "software engineer",
  "location": "Bengaluru",
  "maxItems": 10,
  "fetchDetails": true,
  "includeJobDetails": false,
  "enrichContacts": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Normalized jobs collected from public Google Jobs results.

# 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 = {
    "keyword": "software engineer",
    "location": "Bengaluru",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kaix/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 = {
    "keyword": "software engineer",
    "location": "Bengaluru",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("kaix/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 '{
  "keyword": "software engineer",
  "location": "Bengaluru",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call kaix/google-jobs-scraper --silent --output-dataset

```

## MCP server setup

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