# Google Jobs Scraper: Job Listings by Keyword and City (`oski/google-jobs-scraper`) Actor

Scrape Google Jobs for any keyword and city in 30 countries. Get title, company, location, posted date, salary when shown, job type, full description and the apply link. Several search wordings per keyword return 60 to 70 unique jobs. No login, no API key. Pay per job, $5 per 1,000.

- **URL**: https://apify.com/oski/google-jobs-scraper.md
- **Developed by:** [Oski](https://apify.com/oski) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Security:** Limited permissions
- **Stats:** 3 total users, 2 monthly users, 69.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.85 / 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.
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: Salaries, Descriptions, Apply Links

Get job listings from Google's jobs search, which pulls together LinkedIn, Indeed, ZipRecruiter, Glassdoor, job boards and company career sites in one place. Type a job title and a city, and every job comes back with the company, location, job type, posted date, pay when listed, the full description, and **direct apply links** to the real job page instead of Google redirects.

Tired of a Google Jobs scraper that stops at 10 results, fails one run in five, or charges per page whether or not it finds anything? Google shows only 10 jobs per page, so this actor searches smart variations of your query (posted today, part time, contract, entry level and more), removes duplicates, and keeps going until it reaches your number or the variations run out. In testing, 6 searches returned 292 unique jobs in about two minutes, with a direct apply link on every one.

> **Also from Oski:** [LinkedIn Jobs Scraper](https://apify.com/oski/linkedin-jobs-scraper) for LinkedIn's own listings, and [ATS Jobs Scraper](https://apify.com/oski/ats-jobs-scraper) for every open job straight from a company's careers page.

### What you can use it for

- **Recruiters and agencies** building a daily list of new openings in their niche and city, with the employer and apply link.
- **Job boards and aggregators** filling a niche board with fresh listings from across the web.
- **Sales teams** spotting companies that are hiring right now, a strong signal they have budget.
- **Labour-market researchers** tracking pay, job types and demand by city.
- **Job seekers** getting one clean list of everything posted this week, without opening a dozen sites.
- **AI builders** collecting real job descriptions for matching, search or training data.

### How to use it

1. Under **Job titles or keywords**, add one or more searches, for example `accountant` or `registered nurse`.
2. Add **Locations** (cities or regions) and pick the **Country**. Leave locations empty to search the whole country.
3. Set **Max jobs per search** and **Max jobs in total**, optionally a **Date posted** window or **Job types**, then click **Start**.
4. When it finishes, open the **Output** tab and download as CSV, Excel, JSON or HTML. The **Search summary** shows how many jobs each search found and why any came back empty.

### How much does it cost?

- **$0.002 start fee** per run.
- **$0.005 per search** that Google answers (one keyword in one location), including searches where Google shows no jobs. Searches that fail outright are free.
- **$0.005 per job** delivered. A job found by two of your searches is delivered and charged once.

| You run | You get | Maths | Cost |
|---|---|---|---|
| 1 search | 50 jobs | $0.002 + $0.005 + 50 x $0.005 | about $0.26 |
| 10 searches | 500 jobs | $0.002 + 10 x $0.005 + 500 x $0.005 | about $2.55 |
| 40 searches | 2,000 jobs | $0.002 + 40 x $0.005 + 2,000 x $0.005 | about $10.20 |

### What you get for each job

In a 292-job test across New York and Chicago: company and full description on every job, location on 99%, job type on 91%, qualifications on 89%, posted date on 81% and pay on 59% (pay only appears when the employer lists it). Every one of the 1,383 apply links resolved to the real job page.

```json
{
  "title": "Software / Data Engineer (First Technology Hire - NYC Private Equity)",
  "company": "Averity",
  "location": "New York, NY",
  "remote": false,
  "job_type": "Full-time",
  "posted_at": "2026-10-03",
  "posted_at_exact": true,
  "posted_text": "13 hours ago",
  "salary_text": "125K–175K a year",
  "salary_min": 125000,
  "salary_max": 175000,
  "salary_currency": "USD",
  "salary_period": "year",
  "via": "LinkedIn",
  "apply_url": "https://www.linkedin.com/jobs/view/software-data-engineer-first-technology-hire-nyc-private-equity-at-averity-4473191168",
  "apply_options": [{"source": "LinkedIn", "url": "https://www.linkedin.com/jobs/view/...", "google_url": "https://www.google.com/goto?url=..."}],
  "description": "How would you like to be the first technology hire at a NYC private equity firm...",
  "description_is_preview": false,
  "qualifications": ["..."],
  "responsibilities": ["..."],
  "benefits": ["..."],
  "tags": ["Health insurance"],
  "keyword": "software engineer",
  "location_searched": "New York",
  "country": "US",
  "google_area": "New York, NY",
  "found_by_query": "software engineer New York"
}
```

When the page shows pay without a currency sign, the currency is taken from the country you searched.

### Input

| Field | What it does |
|---|---|
| Job titles or keywords | One search per line. A pasted Google search link also works. |
| Locations | Cities or regions, each searched with every keyword. Optional. |
| Country | Which Google to search (30 countries). |
| Max jobs per search | 10 jobs per Google page; more uses variations. 60 to 75 unique jobs is a typical ceiling for one keyword and city. |
| Max jobs in total | The run stops here. |
| Date posted | Any time, past 24 hours, 3 days, week or month. |
| Job types | Full-time, part-time, contract, internship, temporary. |
| Remote jobs | Include, leave out, or remote only. |

Example for a daily scheduled run:

```json
{
  "keywords": ["accountant", "financial analyst"],
  "locations": ["London", "Manchester", "Birmingham"],
  "country": "GB",
  "datePosted": "today",
  "maxJobsPerSearch": 50,
  "maxJobs": 1000
}
```

### Countries

Tested with full results in the United States, United Kingdom, Canada, India, Singapore, South Africa, the United Arab Emirates, Germany and France. In **Germany and France**, Google shows only a short description preview, flagged with `description_is_preview: true`; every other field is complete. In **Australia and Ireland**, Google rarely shows a jobs panel at all, so most searches there come back empty. The other countries in the list use the same method but have not been tested one by one.

### If something looks wrong

| You see | What it means | What to do |
|---|---|---|
| "showed no Google jobs panel" | Google does not list jobs for that search in that country (common in Australia and Ireland). | Try a nearby large city, or another country. |
| "had no matching jobs on Google" | Google found nothing for that wording. | Use a broader title, for example "nurse" instead of a niche speciality. |
| Fewer jobs than Max jobs per search | Google ran out of new jobs for that search. | Add more locations or related titles: each one is a fresh pool of jobs. |
| "was refused by Google" | A temporary block on Google's side. | Run it again later. |
| Short descriptions | Germany and France show previews only. | Follow the apply link for the full text. |

### Tips for bigger runs

- Breadth beats depth: 10 related titles across 5 cities finds far more unique jobs than one title with a huge limit.
- For monitoring, schedule a daily run with **Date posted: Past 24 hours**.
- Put all your searches in one run: the start fee is paid once and four searches run at a time.

### Scheduling and integrations

Run it on a schedule in Apify, send results to Google Sheets, Slack, Make, Zapier or n8n, or call it from your own code:

```bash
curl -X POST "https://api.apify.com/v2/acts/oski~google-jobs-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["data analyst"], "locations": ["New York"], "country": "US", "maxJobsPerSearch": 30}'
```

### FAQ

**Is it legal?** It reads job listings that are publicly shown on Google search. You are responsible for how you use the data, so respect privacy and anti-spam law in your country.

**Do I need a Google account or API key?** No. The actor uses Apify's Google search proxy, which is included in the run.

**Why not just page through Google?** Google returns only the first 10 jobs per search to automated requests; later pages come back empty. The variations are how the actor gets past that.

**How fresh is the data?** Live: each run searches Google at that moment.

**What if it breaks?** Open an issue on the actor's page and it gets fixed fast.

### Other scrapers from Oski

- [LinkedIn Jobs Scraper](https://apify.com/oski/linkedin-jobs-scraper): LinkedIn listings with salaries and full descriptions.
- [ATS Jobs Scraper](https://apify.com/oski/ats-jobs-scraper): every open job from company careers pages on Greenhouse, Lever, Workday, Ashby and 9 more.
- [Website Contact Finder](https://apify.com/oski/website-contact-finder): emails and phone numbers of the companies you found hiring.
- [UK Decision Maker Finder](https://apify.com/oski/uk-decision-maker-finder): directors and owners of UK companies from their websites.

# Actor input Schema

## `keywords` (type: `array`):

What to search for, one per line, for example a job title or skill. Each keyword is searched in every location below. A Google search link pasted here also works.

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

Cities or regions in the country below, one per line. Leave empty to search the whole country.

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

Which Google to search. Google shows a jobs panel in most countries listed; in Australia and Ireland it rarely does, and in Germany and France it shows short description previews.

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

Google shows 10 jobs per page, so for more the actor searches variations (posted today, part time, entry level and so on) and removes duplicates. About 60 to 75 unique jobs is a typical ceiling for one keyword and city.

## `maxJobs` (type: `integer`):

The run stops after this many jobs. About $5 for 1,000 jobs. 0 means no limit.

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

Only jobs posted in this window. Past 24 hours suits a daily scheduled run.

## `jobTypes` (type: `array`):

Keep only these job types. Leave empty for all.

## `remoteJobs` (type: `string`):

Whether to include jobs marked remote or work from home.

## `searchUrls` (type: `array`):

Paste Google Jobs search links to run their exact query and country. These run as one page each, without variations.

## `resolveApplyLinks` (type: `boolean`):

Turn Google apply redirects into the real job page address (LinkedIn, Indeed, the employer site). On by default; it adds no cost.

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

Google interface language code, for example en, de or fr. English gives the most consistent fields.

## `concurrency` (type: `integer`):

How many searches to run in parallel.

## Actor input object example

```json
{
  "keywords": [
    "accountant",
    "registered nurse",
    "software engineer"
  ],
  "locations": [
    "London",
    "Manchester"
  ],
  "country": "US",
  "maxJobsPerSearch": 30,
  "maxJobs": 100,
  "datePosted": "any",
  "remoteJobs": "include",
  "resolveApplyLinks": true,
  "language": "en",
  "concurrency": 4
}
```

# Actor output Schema

## `overview` (type: `string`):

One row per job: title, company, location, type, posted date, pay, source and apply link.

## `allFields` (type: `string`):

Every field, including the full description, qualifications, responsibilities, benefits and every apply option.

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

One entry per search: jobs found, Google requests used, the variations tried and why a search returned nothing.

# 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 = {
    "keywords": [
        "data analyst"
    ],
    "locations": [
        "New York"
    ],
    "maxJobsPerSearch": 30,
    "maxJobs": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("oski/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 = {
    "keywords": ["data analyst"],
    "locations": ["New York"],
    "maxJobsPerSearch": 30,
    "maxJobs": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("oski/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 '{
  "keywords": [
    "data analyst"
  ],
  "locations": [
    "New York"
  ],
  "maxJobsPerSearch": 30,
  "maxJobs": 100
}' |
apify call oski/google-jobs-scraper --silent --output-dataset

```

## MCP server setup

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