Arcadium Data Scrapers
Home / Tutorials / Google Jobs listings to CSV

Google Jobs scraper: export job listings with salary and apply links to CSV

Recruiters, job boards and labour-market analysts use Google Jobs because it gathers postings from job boards and company career sites in one place. It has no export, and one search page shows 10 jobs.

arcadium/google-jobs takes search queries and places and returns one JSON row per job: title, company, location, posted date, salary as shown and parsed into min, max, currency and period, job type, the full description and every apply link. When Google lists the company’s own applicant tracking system posting, that link is picked as applyUrl. No login; recruiter names, emails and phone numbers are never output.

Cost of this example on the Apify Free plan: 60 × $0.0081 = $0.486 ($0.189 on the Apify Gold plan and higher), plus $0.001 per GB of memory when the run starts.

What you need

Step 1: Run it in the Apify Store (no code)

  1. Open arcadium/google-jobs on the Apify Store and sign in (a free Apify account works).
  2. Type the roles into Search queries, one per line, the way you would type them into Google.
  3. Add the places under Locations, for example Austin, TX or Berlin. Each query runs once per location.
  4. Set Date posted to week and Max jobs per search to 30. Above 10, the actor also runs the filter variants Google offers on the page and merges them without duplicates.
  5. Optional: set a maximum cost per run in the run options as a hard cap.
  6. Click Start. Rows appear in the Output tab; export them as JSON, CSV or Excel.

The same input as JSON (paste it in the JSON tab of the input form):

{
  "queries": [
    "data analyst",
    "business analyst"
  ],
  "locations": [
    "Austin, TX"
  ],
  "datePosted": "week",
  "maxResultsPerQuery": 30
}

Step 2: Call it over the Apify API

One HTTP call runs the actor and returns its rows. It suits runs up to about five minutes; for longer runs start the run asynchronously and read the dataset when it finishes.

curl -X POST "https://api.apify.com/v2/acts/arcadium~google-jobs/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries":["data analyst","business analyst"],"locations":["Austin, TX"],"datePosted":"week","maxResultsPerQuery":30}'

Step 3: Run it from Python

With apify-client 3.x, call() returns a Run object: read the dataset id as run.default_dataset_id (older examples use run["defaultDatasetId"], which no longer works).

# pip install "apify-client>=3"
import csv, os

from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/google-jobs").call(run_input={
    "queries": ["data analyst", "business analyst"],
    "locations": ["Austin, TX"],
    "datePosted": "week",
    "maxResultsPerQuery": 30,
})
rows = list(client.dataset(run.default_dataset_id).iterate_items())  # apify-client 3.x

keys = ["jobId", "title", "companyName", "location", "postedAt", "salaryText",
        "salaryMin", "salaryMax", "salaryPeriod", "employmentTypes", "via", "applyUrl"]
with open("google-jobs.csv", "w", newline="") as f:
    w = csv.DictWriter(f, fieldnames=keys, extrasaction="ignore")
    w.writeheader()
    for r in rows:
        if r.get("rowType") != "job":
            continue
        s = r.get("salary") or {}
        w.writerow({**r, "salaryMin": s.get("min"), "salaryMax": s.get("max"), "salaryPeriod": s.get("period"),
                    "employmentTypes": ", ".join(r.get("employmentTypes") or [])})
for e in (r for r in rows if r.get("rowType") == "error"):
    print("no jobs:", e.get("input"), e.get("code"), e.get("message"))

Step 4: Run it from JavaScript

// npm install apify-client
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/google-jobs').call({
  "queries": [
    "data analyst",
    "business analyst"
  ],
  "locations": [
    "Austin, TX"
  ],
  "datePosted": "week",
  "maxResultsPerQuery": 30
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Step 5: Ask an AI assistant (MCP)

Apify’s hosted MCP server turns the actor into one tool. Add it to Claude, Cursor, VS Code or any MCP client:

{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=arcadium/google-jobs",
      "headers": {
        "Authorization": "Bearer <APIFY_TOKEN>"
      }
    }
  }
}

Then ask, for example:

Use arcadium/google-jobs to find data analyst jobs in Austin, TX posted this week. Group them by company, show the salary range where one is listed and give me the direct apply link of each job.

More clients and the local setup on the MCP page.

New jobs every day

Save the input as a Task in Apify Console, set datePosted to today and add a daily Schedule. jobId is Google’s id of the posting and stays the same across searches and runs: keep the ids you have seen and the new ones are the new jobs.

Other countries and languages

Set country to the Google market and language to the interface language. Labels such as "3 days ago" follow the language; postedAt, employmentTypes and salary.period are normalised for en, de, fr, es, it, pt and nl.

{
  "queries": [
    "Pflegefachkraft"
  ],
  "locations": [
    "Berlin",
    "Hamburg"
  ],
  "country": "DE",
  "language": "de"
}

Which company ATS a job links to

With "jobsDbExport": true each row gets a jobsDb object: the ATS (Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor or Workday), the company’s board on it, the ATS posting id and every apply URL without tracking parameters. It suits recruiting and sales teams that use hiring as a buying signal.

Output fields

Every row has a rowType; filter on it first. Failed inputs come back as free rows with a code and message. The fields this tutorial uses, from the actor’s dataset schema:

FieldWhat it holds
rowTypeKind of row. Filter on this first. Values: 'job': one job posting from Google Jobs (charged). 'error': a search found nothing or could not be read; see code and message (free).
jobIdGoogle's document id of the posting (htidocid), e.g. d6Zuw_TVelot7iRuAAAAAA==. The same posting keeps it across queries and runs: use it to deduplicate.
titleJob title as published, e.g. Software Development Engineer II.
companyNameHiring organisation as Google lists it, e.g. Amazon Web Services, Inc.
locationJob location as Google shows it, e.g. Seattle, WA or Berlin. Remote jobs may say Anywhere.
viaSite Google read the posting from, e.g. LinkedIn, Indeed, Acme Careers (the 'via ...' line).
postedAtApproximate posting date (yyyy-mm-dd) computed from postedAgo on the run day; '30+ days ago' gives a lower bound. Null when Google gave no age.
salaryTextSalary as Google shows it, e.g. $144K–$194K a year, 30 € pro Stunde. Null when not stated.
salarySalary parsed from salaryText: min, max (equal for a single value), currency (ISO code), period (hour, day, week, month, year).
employmentTypesNormalised employment types: FULLTIME, PARTTIME, CONTRACTOR, INTERN, TEMPORARY. Empty when unknown.
descriptionJob description text as Google shows it (includeDescription). Emails and phone numbers replaced with [email] and [phone].
descriptionCompleteTrue when description is the full text; false when Google showed only a preview (some markets show about 400 characters).
applyUrlBest apply link: the company's own applicant tracking system posting when Google lists one, else Google's first apply option.
applyOptionsEvery apply option Google lists: source (site name), label (button text), url, domain and ats (greenhouse, lever, workday, ... when the URL is a company job board).
jobsDbjobsDbExport only: atsJobId (<ats>___<posting id>, as career-site-jobs names it), ats, boardToken, boardKey, atsUrl, applyUrls without tracking parameters, fingerprint (sha1 of company|title|location).

All fields: Google Jobs Scraper guide.

Cost per run

Pay per event: you pay for the rows delivered, at the actor’s live Apify price on 2026-11-03. Error, coverage and summary rows are free.

WhatRowsPrice per row (Free plan)Subtotal
Job: 2 queries x 1 location x up to 30 jobs60$0.0081$0.486

Cost of this example on the Apify Free plan: 60 × $0.0081 = $0.486 ($0.189 on the Apify Gold plan and higher), plus $0.001 per GB of memory when the run starts. Higher Apify plans pay less per row. The Store page always has the current price.

Limitations

Links