To scrape Google Jobs, send a role and a city to a scraper that opens Google's public Jobs panel and saves each listing as a row: title, company, location, the board Google credits (LinkedIn, Indeed, a careers site), posting age, schedule, highlights such as qualifications and benefits, and the apply links. The fastest way is the Google Jobs Scraper on Scrape.ly. It handles the browser Google insists on and costs $4 per 1,000 jobs, with no Google account or proxy of your own.
Because Google Jobs collects openings from many job boards and company sites, one search gives you a cross-board view of a market that no single board offers. This guide covers the no-code steps, the API (curl, Python, Node.js and AI agents over MCP), the cost and the pitfalls, all from a real run on 23 October 2026: software engineer jobs in San Francisco.
What data you can get from Google Jobs
The Google Jobs Scraper writes one row per job. These are the fields you'll use most:
| Field | What it holds |
|---|---|
title, company_name | Job title and employer |
location, search_location | The place on the listing ("San Francisco, CA", "Anywhere") and the place you searched |
via | The source Google credits: LinkedIn, Indeed, ZipRecruiter, a company careers site |
description | The job description text |
extensions, detected_extensions | Tags such as "3 days ago", "Full-time", a salary range, "No degree mentioned" |
job_highlights | Google's Qualifications, Benefits and Responsibilities lists |
apply_options | Where to apply, with links |
share_link, source_link | Google's share link for the job and the source page |
query, country, language, google_domain | The search context of the row |
total_jobs_found, pages_processed, search_timestamp | Run details |
Salary, highlights and apply links appear only when Google shows them for that listing.
How to scrape Google Jobs without code
- Open the Actor's page in the Scrape.ly Store.
- Pick a ready-made input. We used Software engineer jobs in San Francisco, 10 jobs. Other presets cover jobs from the last 24 hours and nursing jobs in Berlin.
- Change the role and city to yours. This is the exact input of our run:
{
"query": "Software Engineer",
"location": "San Francisco, CA",
"maxResults": 10,
"country": "us",
"language": "en",
"googleDomain": "google.com",
"postedWithin": "any"
}- Click Start. Our run took 13 seconds; the publisher's tests put typical runs at 50 to 120 seconds, depending on how quickly Google lets a browser session through.
- Export the jobs as JSON, CSV or Excel.
The fields that matter most:
query: the role or keywords, as you'd type them into Google Jobs.location: a city gives the closest match. If a location search comes back thin, the run retries once with the city added to the query.maxResults: up to 100 jobs per run, about 10 per page.country,language,googleDomain: pick the market, for examplede,deandgoogle.defor Germany.postedWithin:any,24h,3d,7dor30d. Listings without a date stay in.locationRadiusKm: optional radius around the location.
How to scrape Google Jobs with the API
Create an API token under Settings → API & Integrations and export it as SCRAPELY_TOKEN.
Our run finished in 13 seconds, so the synchronous endpoint returned the jobs in one request:
curl -X POST "https://api.scrape.ly/v2/actors/openrole~google-jobs-scraper/run-sync-get-dataset-items" \
-H "Authorization: Bearer $SCRAPELY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query": "Software Engineer", "location": "San Francisco, CA", "maxResults": 10, "country": "us", "postedWithin": "any"}'The synchronous call waits up to 45 seconds and answers 408 if the run needs longer, while the run keeps going. Because Google sometimes takes a minute or two to let a session through, use the asynchronous flow (/runs, then wait, then read the dataset) for scheduled jobs; the Actors API docs show it.
Python (pip install scrapely-client-python). call() waits however long the run takes. Google often puts the pay range in the Benefits highlights rather than in a tag, so this example checks both:
import os
from scrapely_client import ScrapelyClient
client = ScrapelyClient(os.environ["SCRAPELY_TOKEN"], api_url="https://api.scrape.ly")
run = client.actor("openrole/google-jobs-scraper").call(
run_input={"query": "Software Engineer", "location": "San Francisco, CA", "maxResults": 10, "country": "us"}
)
print(run.status) # SUCCEEDED, FAILED, ABORTED or TIMED-OUT
for job in client.dataset(run.default_dataset_id).iterate_items():
tags = job.get("detected_extensions") or {}
pay = tags.get("salary") or next(
(item for h in job.get("job_highlights") or [] for item in h["items"] if "$" in item), "")
print(f'{job["company_name"][:22]:22} {job["via"][:16]:16} {tags.get("posted_at", ""):12} {pay[:60]}')Node.js (npm install scrapely-client):
import { ScrapelyClient } from 'scrapely-client';
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN, baseUrl: 'https://api.scrape.ly' });
const run = await client.actor('openrole/google-jobs-scraper').call({
query: 'Software Engineer',
location: 'San Francisco, CA',
maxResults: 10,
country: 'us',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((j) => [j.title, j.company_name, j.via, (j.apply_options || []).map((a) => a.link)]));For AI agents, add the Scrape.ly MCP server. In Cursor, put this in ~/.cursor/mcp.json:
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}In Claude Code, run claude mcp add --transport http scrapely https://api.scrape.ly/mcp and sign in with /mcp. Then ask: "Use scrapely to run openrole/google-jobs-scraper for Software Engineer in San Francisco, 10 jobs, and give me a table of title, company, source and pay." When a run needs more than 45 seconds, the agent polls get-actor-run and then reads the rows. The Google Jobs API page shows the same Actor as an API product.
A real run: software engineers in San Francisco
We ran the "Software engineer jobs in San Francisco, 10 jobs" preset on 23 October 2026. It returned 10 jobs in 13 seconds and was charged $0.0808. The first five rows:
| Title | Company | Location | Via | Tags | Apply via |
|---|---|---|---|---|---|
| Staff Software Engineer - Autonomous Verification Platform | Uber | San Francisco, CA (+1 other) | Jobs.uber.com | 3 days ago, Full-time | Jobs.uber.com |
| Staff Software Engineer, Photos Create | San Francisco, CA | 2 days ago, Full-time | |||
| .NET Software Engineer | Deloitte | San Francisco, CA | Indeed | 5 days ago, 80K–115K a year, Full-time, No degree mentioned | Indeed |
| Senior Software Engineer — Employee Experience Engineering (EXE) | Block | San Francisco, CA | 2 days ago, Full-time | ||
| Software Engineer II, Merchant Intel 5 | Uber | San Francisco, CA (+1 other) | Jobs.uber.com | 10 days ago, Full-time, No degree mentioned | Jobs.uber.com |
Employers and job boards are businesses, so nothing needed masking. What the full ten show:
- Six sources in one search. The ten jobs came via LinkedIn (3), Uber's careers site (3), Indeed, ZipRecruiter, Callings.ai and Intuitive Surgical's careers site. That cross-board view is the main reason to scrape Google Jobs instead of one board.
- Pay hides in the highlights. Only 3 of 10 rows had a salary tag, but 9 of 10 carried a pay range inside
job_highlights, from Deloitte's "$80000 to $115000" to "$405,000—$485,000 USD" at Anthropic. Read both places. - Fresh listings. Every job was 2 to 10 days old, and each tag says so ("2 days ago").
- Structured highlights. Nine of ten had Qualifications, Benefits and Responsibilities lists, which makes skills analysis a matter of reading arrays instead of parsing prose.
- Remote shows up too. Two jobs were listed as "Anywhere" and two as "San Francisco, CA (+1 other)", so filter on
locationif you need on-site roles only.
The log, without the platform's start-up lines:
2026-10-23T03:01:20.064Z [Scrapely] Container started (setup 1.7 s)
2026-10-23T03:01:21.602Z [scrapely.actor] INFO query=Software Engineer location=San Francisco, CA country=us limit=10
2026-10-23T03:01:22.462Z [scrapely.actor] INFO page status=200 kind=challenge listings=0 profile=chrome146 proxied=True attempts=chrome146:challenge:200:92743
2026-10-23T03:01:22.462Z [scrapely.actor] INFO The jobs page needs a browser. Opening browser sessions.
2026-10-23T03:01:30.687Z [scrapely.actor] INFO browser sessions=1 exits=US listings=10
2026-10-23T03:01:31.195Z [scrapely.actor] INFO [Status message]: Saved 10 job listings.
2026-10-23T03:01:31.878Z [Scrapely] Container state: status=exited exitCode=0 oomKilled=falseThe third line is the reason DIY Google Jobs scrapers stall: a plain request gets Google's script challenge and zero listings. The Actor switched to a hosted browser on a US exit and had all ten jobs eight seconds later. You don't configure anything for it.
What it costs
The Actor charges one event: $0.004 per job saved, which is $4 per 1,000. A search that saves no jobs has no result charge. Compute, browser time and proxy traffic are billed as platform usage on top.
For our run: 10 jobs × $0.004 = $0.04 in job fees. The run was charged $0.0808 in total: $0.039 of browser time (Google requires a real browser for this page), $0.0018 of compute and well under a cent of proxy traffic and storage. A full 100-job run costs $0.40 in job fees plus its browser time. The Free plan's $5 of monthly credit covers dozens of searches like ours, and a maximum charge per run stops a run before it goes over your limit.
What to watch out for when scraping Google Jobs
- Up to 100 jobs per run. Google serves about 10 jobs per page, and each run collects up to 100 of them. For a whole market, split by city, keyword or posting window and run several searches in parallel.
- Google's traffic checks. Google shows a check to many browser exits. The Actor tries up to twelve fresh sessions, three at a time, preferring exits in the searched country. If all are checked, the run fails with a clear status instead of an empty "success". Spread your searches over time rather than starting many at once.
- Some countries have no Google Jobs. Australia, New Zealand, Ireland, South Korea, Poland, the Czech Republic, Turkey, Ukraine, Israel, Norway, Sweden, Finland and the Baltic states return no listings. Those runs stop before searching and are not charged.
- Apply links follow the open listing. Google loads apply options for the listing that is open, so the Actor keeps only links that belong to that job, and jobs from later pages often have just
share_link. Use it to open the job on Google. - Pay is optional. Salary tags, highlights and apply links appear only when Google shows them. Check
job_highlightsfor a pay range when the tag is missing. - Personal data. Job ads sometimes name a recruiter. Employers are businesses; a named recruiter is a person, so keep only what you need.
Is it legal to scrape Google Jobs?
The Actor reads Google's public Jobs search, the same page any visitor sees, without signing in. The listings are job ads that employers published to attract applicants, and the rows hold business facts: titles, companies, locations and posted pay.
Google's Terms of Service refer to the robots.txt instructions on its pages for automated access, so read the current terms and check how they apply to your project before you start.
Responsible practice keeps the footprint small: set maxResults and a maximum charge per run so each job stays at a modest volume, and use the listings for research rather than republishing Google's pages. Privacy law applies to anyone named in a job ad: a recruiter's name or email is personal data under the GDPR and the CCPA, so collect only what you need. Our guide on whether web scraping is legal covers the general rules. This is not legal advice; if Google Jobs data drives a commercial product, get legal advice for your use case.
Why Scrape.ly for Google Jobs
- There is no public API for the Jobs panel. Google's job-search API, Cloud Talent Solution, is a search engine for your own job content: it indexes the jobs you upload and searches "your corpus of jobs". It doesn't return the listings Google shows in Search. The Actor does.
- The browser is built in. ScrapingBee's tutorial needs
custom_google,render_jsand a custom scrolling script to load the panel before parsing it. Here the Actor detects Google's challenge and opens a hosted browser itself, as the log shows. - Structured rows, not HTML. Highlights arrive as arrays, apply options as title and link pairs, and tags as named fields (
posted_at,schedule_type,salary), ready for a spreadsheet, a database or an LLM. - One API for every job source. The same publisher maintains scrapers for the boards Google aggregates. Pair this run with our Indeed guide, LinkedIn jobs and the Indeed Scraper, or read the job scraping guide for the full workflow.
FAQ
Does Google have a Google Jobs API?
Not for the listings in Search. Google's Cloud Talent Solution is an API for searching job content you index yourself. To collect what Google Jobs shows for a role and city, use a scraper that reads the public panel, such as the Google Jobs Scraper.
Can I scrape Google Jobs with Python?
Yes. Install scrapely-client-python, call openrole/google-jobs-scraper with a query and location, and iterate over the dataset, as in the example above. You don't need Selenium, a headless browser or a proxy pool.
How many jobs can I get from one Google Jobs search?
Up to 100 per run, about 10 per page. Run several searches (other cities, keywords or posting windows) to go further.
Can I get only jobs posted in the last 24 hours?
Yes. Set postedWithin to 24h, or start from the last-24-hours preset. Listings without a date stay in, so check detected_extensions.posted_at too.
How much does it cost to scrape Google Jobs?
$0.004 per job, so $4 per 1,000, plus browser and compute usage. Our 10-job run was charged $0.0808 in total.




