Google Jobs Scraper With Per-Result Billing
A Google Jobs scraper that charges for every listing it hands you and nothing else. Give it a role and a location, get one flat row per opening, and know the bill before the run starts because the math is results times price.
When to use this skill
- The user asks for a "google jobs scraper" or wants to scrape Google Jobs openings.
- They want listings for a role, company, city, or country as a flat dataset.
- They want cost that scales with rows delivered rather than pages fetched.
- They want to exclude specific employers or job boards from the output.
Not for: salary analytics (there is no numeric salary field), LinkedIn-only listings (use the LinkedIn Jobs API), or employer reviews (use the Glassdoor Reviews API).
What you get (one flat row per listing)
Verified on a live run:
title and job_title (identical strings, so pick either one)
company_name, location, via (the platform hosting the listing, such as LinkedIn or a company careers site)
description (full posting text, often 1,500 characters or more)
job_highlights (array of {title, items} blocks such as Qualifications, Responsibilities, Benefits)
extensions (raw tag strings such as "22 hours ago", "Full-time")
detected_extensions (posted_at and schedule_type on every row, plus work_from_home and qualifications when present on that listing)
apply_options (array of {title, link} direct apply links, one per hosting platform)
source_link (canonical link to the posting), share_link (Google Jobs permalink), job_id (dedupe key)
- Echoed run context on every row:
query, country, language, google_domain, search_timestamp, total_jobs_found, pages_processed
Every row carries its own search context, so you can merge several runs into one table and still tell where each listing came from.
Prerequisites
The Actor
Run it with the Apify CLI
Scrape a role in a city, capped at 10 listings:
apify actors call "johnvc/google-jobs-scraper---pay-per-result" -i '{"query":"software engineer","location":"Austin, TX","country":"us","language":"en","num_results":10}' \
--json \
--user-agent apify-awesome-skills/apify-google-jobs-scraper \
2>/dev/null
Scrape a country-wide search on a local Google domain, skipping two job boards:
apify actors call "johnvc/google-jobs-scraper---pay-per-result" -i '{"query":"data analyst","location":"United Kingdom","country":"uk","google_domain":"google.co.uk","language":"en","num_results":50,"via_filter_list":["Indeed","ZipRecruiter"]}' \
--json \
--user-agent apify-awesome-skills/apify-google-jobs-scraper \
2>/dev/null
Every call carries the three flags this repo expects: --json (or --format json), --user-agent apify-awesome-skills/apify-google-jobs-scraper, and 2>/dev/null.
Run it from Claude or another AI agent (MCP)
The Actor is MCP-ready. Add the hosted server URL:
https://mcp.apify.com/?tools=actors,docs,johnvc/google-jobs-scraper---pay-per-result
Then ask, for example: "Scrape Google Jobs for 20 warehouse supervisor openings near Columbus and give me the apply links." MCP setup docs: https://docs.apify.com/platform/integrations/mcp
Workflow
- Build the query.
query is the only required field, and it takes a job title, skill, or company name. Add location (city, state, or country) to narrow it.
- Set localization. Send
country and language explicitly. Google Jobs returns nothing when neither is supplied, and the Actor has to guess from google_domain and log a warning.
- Cap the volume.
num_results is the direct cost lever here because you pay per row. The minimum accepted value is 10; the maximum is 1000.
- Filter before you pay.
company_filter_list and via_filter_list drop matching rows during collection, so excluded listings never reach the dataset and never get billed.
- Estimate cost, then confirm with the user if the run is large. See
references/gotchas.md.
- Run the Actor and read the dataset. Dedupe across runs on
job_id.
Inputs
query (string, required): job title, skill, or company
location (string): city, state, or country. Empty plus a country value falls back to the country name
country (enum: None, us, ca, uk, de, fr, au, jp, in, br, mx)
language (enum, 100 plus codes, default None)
google_domain (enum, default google.com)
num_results (integer 10 to 1000, default 100): the billing lever
max_pagination (integer 0 to 100, default 0 = unlimited)
company_filter (string, comma separated) or company_filter_list (array): exclude employers
company_filter_regex (boolean, default false): treat the company filters as regular expressions
via_filter (string) or via_filter_list (array): exclude source platforms
include_lrad (boolean) plus lrad_value (string, miles): radius search
max_delay (integer 0 to 10, default 1): seconds between requests
output_file (string): custom filename for the saved results file
Cost
Billing is per result in the default dataset. Ten listings cost ten result charges, one hundred listings cost one hundred. Live per-result prices and confirmation thresholds are in references/gotchas.md.
Honest limits
- No numeric salary field and no experience-level field. Pay figures sometimes appear inside
job_highlights Benefits text, but that is free text you would have to parse yourself, not a structured field.
posted_at is a relative string such as "22 hours ago", so freshness filtering happens on your side after the run.
pages_processed came back as 0 on the verified run, so treat it as unreliable and count dataset rows instead.
- Google Jobs inventory varies by region and query, so
num_results is a cap and not a guarantee.
- Company and source filters are case sensitive unless you turn on
company_filter_regex.
Troubleshooting
- No results: send
country and language explicitly, then broaden the query or drop the location.
- Fewer rows than
num_results: normal, Google had fewer listings for that query.
- Insufficient funds: the Actor writes a single error row explaining the shortfall instead of failing silently. Add funds or lower
num_results.
See references/gotchas.md for cost guardrails and error recovery, and references/actor-index.md for the Actor routing table.
Related job-data Actors
1---2name: apify-google-jobs-scraper3description: Run a google jobs scraper that bills per listing, not per page, with the Apify Google Jobs Scraper API Pay Per Result Actor (johnvc/google-jobs-scraper---pay-per-result). Give a job title plus an optional location and get one flat row per opening with title, company_name, location, via (source platform), full description, job_highlights, detected_extensions (posted_at, schedule_type), apply_options direct links, source_link, and job_id. Built-in company_filter and via_filter drop unwanted employers or job boards before you pay for them. Use when the user asks for a google jobs scraper, wants to scrape Google Jobs openings for a role or city, needs a job listings dataset with predictable cost, or wants to exclude staffing agencies from the results. Pay-per-result billing, MCP-ready for Claude and other AI agents.4license: MIT5---67# Google Jobs Scraper With Per-Result Billing89A Google Jobs scraper that charges for every listing it hands you and nothing else. Give it a role and a location, get one flat row per opening, and know the bill before the run starts because the math is results times price.1011## When to use this skill1213- The user asks for a "google jobs scraper" or wants to scrape Google Jobs openings.14- They want listings for a role, company, city, or country as a flat dataset.15- They want cost that scales with rows delivered rather than pages fetched.16- They want to exclude specific employers or job boards from the output.1718Not for: salary analytics (there is no numeric salary field), LinkedIn-only listings (use the LinkedIn Jobs API), or employer reviews (use the Glassdoor Reviews API).1920## What you get (one flat row per listing)2122Verified on a live run:2324- `title` and `job_title` (identical strings, so pick either one)25- `company_name`, `location`, `via` (the platform hosting the listing, such as LinkedIn or a company careers site)26- `description` (full posting text, often 1,500 characters or more)27- `job_highlights` (array of `{title, items}` blocks such as Qualifications, Responsibilities, Benefits)28- `extensions` (raw tag strings such as "22 hours ago", "Full-time")29- `detected_extensions` (`posted_at` and `schedule_type` on every row, plus `work_from_home` and `qualifications` when present on that listing)30- `apply_options` (array of `{title, link}` direct apply links, one per hosting platform)31- `source_link` (canonical link to the posting), `share_link` (Google Jobs permalink), `job_id` (dedupe key)32- Echoed run context on every row: `query`, `country`, `language`, `google_domain`, `search_timestamp`, `total_jobs_found`, `pages_processed`3334Every row carries its own search context, so you can merge several runs into one table and still tell where each listing came from.3536## Prerequisites3738- Apify account (sign up at https://apify.com?fpr=9n7kx3&fp_sid=skillrepo).39- Authentication via `apify login`, or an `APIFY_TOKEN` environment variable (Apify Console, Settings, Integrations).4041## The Actor4243- Store page: https://apify.com/johnvc/google-jobs-scraper---pay-per-result?fpr=9n7kx3&fp_sid=skillrepo44- Actor ID: `johnvc/google-jobs-scraper---pay-per-result`45- Pricing: pay per result delivered to the dataset (see `references/gotchas.md`).4647## Run it with the Apify CLI4849Scrape a role in a city, capped at 10 listings:5051```bash52apify actors call "johnvc/google-jobs-scraper---pay-per-result" -i '{"query":"software engineer","location":"Austin, TX","country":"us","language":"en","num_results":10}' \53 --json \54 --user-agent apify-awesome-skills/apify-google-jobs-scraper \55 2>/dev/null56```5758Scrape a country-wide search on a local Google domain, skipping two job boards:5960```bash61apify actors call "johnvc/google-jobs-scraper---pay-per-result" -i '{"query":"data analyst","location":"United Kingdom","country":"uk","google_domain":"google.co.uk","language":"en","num_results":50,"via_filter_list":["Indeed","ZipRecruiter"]}' \62 --json \63 --user-agent apify-awesome-skills/apify-google-jobs-scraper \64 2>/dev/null65```6667Every call carries the three flags this repo expects: `--json` (or `--format json`), `--user-agent apify-awesome-skills/apify-google-jobs-scraper`, and `2>/dev/null`.6869## Run it from Claude or another AI agent (MCP)7071The Actor is MCP-ready. Add the hosted server URL:7273`https://mcp.apify.com/?tools=actors,docs,johnvc/google-jobs-scraper---pay-per-result`7475Then ask, for example: "Scrape Google Jobs for 20 warehouse supervisor openings near Columbus and give me the apply links." MCP setup docs: https://docs.apify.com/platform/integrations/mcp7677## Workflow78791. Build the query. `query` is the only required field, and it takes a job title, skill, or company name. Add `location` (city, state, or country) to narrow it.802. Set localization. Send `country` and `language` explicitly. Google Jobs returns nothing when neither is supplied, and the Actor has to guess from `google_domain` and log a warning.813. Cap the volume. `num_results` is the direct cost lever here because you pay per row. The minimum accepted value is 10; the maximum is 1000.824. Filter before you pay. `company_filter_list` and `via_filter_list` drop matching rows during collection, so excluded listings never reach the dataset and never get billed.835. Estimate cost, then confirm with the user if the run is large. See `references/gotchas.md`.846. Run the Actor and read the dataset. Dedupe across runs on `job_id`.8586## Inputs8788- `query` (string, required): job title, skill, or company89- `location` (string): city, state, or country. Empty plus a `country` value falls back to the country name90- `country` (enum: None, us, ca, uk, de, fr, au, jp, in, br, mx)91- `language` (enum, 100 plus codes, default None)92- `google_domain` (enum, default `google.com`)93- `num_results` (integer 10 to 1000, default 100): the billing lever94- `max_pagination` (integer 0 to 100, default 0 = unlimited)95- `company_filter` (string, comma separated) or `company_filter_list` (array): exclude employers96- `company_filter_regex` (boolean, default false): treat the company filters as regular expressions97- `via_filter` (string) or `via_filter_list` (array): exclude source platforms98- `include_lrad` (boolean) plus `lrad_value` (string, miles): radius search99- `max_delay` (integer 0 to 10, default 1): seconds between requests100- `output_file` (string): custom filename for the saved results file101102## Cost103104Billing is per result in the default dataset. Ten listings cost ten result charges, one hundred listings cost one hundred. Live per-result prices and confirmation thresholds are in `references/gotchas.md`.105106## Honest limits107108- No numeric salary field and no experience-level field. Pay figures sometimes appear inside `job_highlights` Benefits text, but that is free text you would have to parse yourself, not a structured field.109- `posted_at` is a relative string such as "22 hours ago", so freshness filtering happens on your side after the run.110- `pages_processed` came back as 0 on the verified run, so treat it as unreliable and count dataset rows instead.111- Google Jobs inventory varies by region and query, so `num_results` is a cap and not a guarantee.112- Company and source filters are case sensitive unless you turn on `company_filter_regex`.113114## Troubleshooting115116- No results: send `country` and `language` explicitly, then broaden the query or drop the location.117- Fewer rows than `num_results`: normal, Google had fewer listings for that query.118- Insufficient funds: the Actor writes a single error row explaining the shortfall instead of failing silently. Add funds or lower `num_results`.119120See `references/gotchas.md` for cost guardrails and error recovery, and `references/actor-index.md` for the Actor routing table.121122## Related job-data Actors123124- Google Jobs Scraper, pay per page edition: https://apify.com/johnvc/Google-Jobs-Scraper?fpr=9n7kx3&fp_sid=skillrepo125- LinkedIn Jobs API: https://apify.com/johnvc/linkedin-jobs-api?fpr=9n7kx3&fp_sid=skillrepo126- Glassdoor Reviews API: https://apify.com/johnvc/glassdoor-reviews-api?fpr=9n7kx3&fp_sid=skillrepo