Scraper for ZipRecruiter — Jobs, Pay & Benefits avatar

Scraper for ZipRecruiter — Jobs, Pay & Benefits

Pricing

from $2.50 / 1,000 results

Go to Apify Store
Scraper for ZipRecruiter — Jobs, Pay & Benefits

Scraper for ZipRecruiter — Jobs, Pay & Benefits

Export ZipRecruiter job listings by keyword and location: title, company, structured pay (min/max, period, annualised, employer vs estimate), benefits, remote/on-site, county and ZIP, 1-Click Apply flag and post dates. Optional full descriptions. No login. Not affiliated with ZipRecruiter.

Pricing

from $2.50 / 1,000 results

Rating

0.0

(0)

Developer

Logiover

Logiover

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

10 days ago

Last modified

Share

Independent tool — not affiliated with, endorsed by, or sponsored by ZipRecruiter, Inc. "ZipRecruiter" is a trademark of its owner and is used here only to describe the public website this Actor reads.

ZipRecruiter Jobs Scraper exports job listings from ziprecruiter.com by keyword and location — with structured pay (min / max / period / annualised, and where the number came from), benefits, remote / on-site / hybrid, location down to county and ZIP code, employment type, 1-Click Apply flag, company, and posting / refresh dates. Give it a list of keywords and a list of locations and it searches every combination, walks every result page, removes duplicates and hands you a clean dataset you can export to Excel, CSV, JSON, Google Sheets or pull through the API.

No ZipRecruiter account, no login, no API key. It reads the same public search pages a job seeker sees.


✨ What you get from every job

  • Job — title, ZipRecruiter job ID, canonical job URL, apply URL, short description, "new" and "urgently hiring" labels
  • Company — name, ZipRecruiter company ID, company jobs page, logo, worker-survey highlights ("Respectful managers", "Good training"…)
  • Pay — the text exactly as shown ($24 - $28/hr), plus numeric min / max, pay period (hour, day, week, month, year), annualised min / max, currency and a pay source column that tells you whether the employer published it, it was read from the job description, or it is a ZipRecruiter estimate
  • Location — city, county, state, state code, ZIP code, country, plus workplace type (On-site, Remote, Hybrid) and an isRemote flag
  • Terms — employment type (Full-time, Part-time, Contractor, Temporary, Per diem), benefits (Medical, Dental, Vision, Life, Retirement, PTO)
  • Timing — original posting date, last refresh date, "posted 3 days ago" text, last update timestamp, active flag
  • Apply — whether the job takes ZipRecruiter 1-Click Apply or sends you to the employer's site
  • Optional deep mode — full job description, industry, O*NET occupation code, education requirement, closing date, company website, company description and employer rating (1–10)

🎯 Who uses ZipRecruiter data and why

  • Staffing agencies & recruiters — lead generation. Every row is a company that is hiring right now, with the role, the location and often the pay. Filter by city and role, then reach out to the hiring company before your competitors do.
  • Compensation & HR analysts — pay benchmarking. Annualised min/max per role and city, with the pay source column so you can keep only employer-published figures for a clean benchmark.
  • Labour-market research. Track posting volume, remote share, contract vs full-time mix, and benefits coverage by occupation and metro, week after week.
  • Job boards & aggregators. Feed niche boards and newsletters with fresh, de-duplicated listings and canonical links.
  • Sales intelligence. Hiring is a buying signal: a company hiring 20 truck drivers or 10 nurses is growing. Pair the company column with Company Firmographics Scraper or Website Contact Scraper to reach decision makers.

🚀 How to scrape ZipRecruiter jobs

  1. Enter one or more Keywords (job titles or skills) — e.g. registered nurse, truck driver, python developer.
  2. Enter one or more Locations — City, ST, a state code (TX), a ZIP code (78701), Remote or United States. Leave it empty to search the whole United States.
  3. Optionally narrow it down: posted within, employment type, remote only, 1-Click Apply only, minimum salary, radius.
  4. Set Max jobs and press Start. Each keyword is searched in each location; the log names every search and how many listings ZipRecruiter reported for it.
  5. Download the results from the Storage / Dataset tab, or connect them to Google Sheets, Zapier, Make or a webhook.

📥 Input examples

Nurses in two cities, posted in the last 5 days

{
"keywords": ["registered nurse", "LPN"],
"locations": ["Houston, TX", "Dallas, TX"],
"postedWithin": "5",
"maxItems": 2000
}

Remote software jobs paying $150k+ anywhere in the US

{
"keywords": ["software engineer", "data engineer", "devops engineer"],
"locations": ["United States"],
"remoteOnly": true,
"minSalary": 150000,
"maxItems": 3000
}

Your own ZipRecruiter search URLs, with full descriptions and company websites

{
"startUrls": [
{ "url": "https://www.ziprecruiter.com/jobs-search?search=electrician&location=Phoenix%2C+AZ&days=10" }
],
"fetchDetails": true,
"maxItems": 200
}

All input fields:

FieldWhat it does
keywordsJob titles or skills. Each one is searched in each location. Empty = all jobs in the locations.
locationsCity, ST, state code, ZIP, Remote or United States. Empty = whole US.
startUrlsZipRecruiter search URLs (filters in the URL are kept).
radius5, 10, 25 (default), 50 or 100 miles around each location.
postedWithinAny time, last 24 hours, 5, 10 or 30 days.
employmentTypeAny, Full-time, Part-time, Contract, Temporary.
remoteOnlyOnly jobs tagged remote.
quickApplyOnlyOnly jobs that take ZipRecruiter 1-Click Apply.
minSalaryOnly jobs whose annualised pay range reaches this amount.
maxItemsTotal unique jobs to collect (0 = no limit).
maxPagesPerSearchCap pages (20 jobs each) per keyword × location (0 = all).
fetchDetailsOpen every job page for the full description, industry, O*NET code, education, company website and rating.
concurrencyResult pages loaded in parallel (default 40, max 50).
proxyConfigurationKeep the default UNBLOCKER group — ZipRecruiter refuses ordinary proxies.

Every filter offered here was checked against the live site and changes the result set. Filters that ZipRecruiter ignores (for example hybrid-only or internship) are deliberately not offered.

📤 Output example

A real row from a test run (truck driver jobs in Chicago, IL):

{
"jobId": "66a23d0a69f03797",
"listingKey": "xMCft84-e40fJGTzftEeJQ",
"title": "Delivery Driver Non CDL",
"company": "The Chefs' Warehouse",
"companyId": "0+yOssKc5YiowTxF6XFpdZJQNLQ=",
"companyUrl": "https://www.ziprecruiter.com/co/The-Chefs'-Warehouse/Jobs",
"companyLogo": "https://www.ziprecruiter.com/svc/fotomat/public-nosensitive-ziprecruiter-logos/company/27f017ff.jpeg",
"location": "Chicago, IL",
"city": "Chicago",
"county": "Cook",
"state": "Illinois",
"stateCode": "IL",
"postalCode": "60608",
"country": "United States",
"countryCode": "US",
"locationType": "On-site",
"isRemote": false,
"employmentType": "Full-time",
"payText": "$24 - $28/hr",
"payMin": 24,
"payMax": 28,
"payPeriod": "hour",
"payCurrency": "USD",
"payMinAnnual": 48000,
"payMaxAnnual": 56000,
"paySource": "Employer",
"payIsEstimated": false,
"benefits": "Medical, Dental, Life, Retirement, PTO",
"workplaceHighlights": "Good employer, Recommended by parents, Respectful managers, Uninterrupted breaks",
"isNew": false,
"isUrgent": false,
"postedAt": "2026-10-02T19:56:02.000Z",
"refreshedAt": "2026-10-02T19:56:02.000Z",
"postedAgo": "7 days ago",
"updatedAt": "2026-10-10T10:47:40.353Z",
"isActive": true,
"shortDescription": "About The Chefs' Warehouse The Chefs' Warehouse, Inc. ( combines exceptional quality and brand building with broadline food service distribution for more than 40 years. With Protein, Specialty,",
"isQuickApply": true,
"applyType": "ZipRecruiter 1-Click Apply",
"applyUrl": "https://www.ziprecruiter.com/job-redirect?match_token=Cp8BChZ4TUNmdDg0LWU0MGZKR1R6ZnRFZUpREiQwMWExMjcxNy0wNmIyLTc3YjAtOGQ3MC0xNWUzMjMzMTIwMjcaW0FBRTVtSDVxS0NFTXFtSTNqLVhxR1JnXzNiVjV5czhnVmQzVHRYQmlGam9OTDJwMVdNT0o3STUzYkpqQlFRRTctN29rbXNXaHRNYVd1VG5XQ0IyeVpmVmU3b00gqNgCEAEYqNgC",
"jobUrl": "https://www.ziprecruiter.com/c/The-Chefs-Warehouse/Job/Delivery-Driver-Non-CDL/-in-Chicago,IL?jid=66a23d0a69f03797",
"searchKeyword": "truck driver",
"searchLocation": "Chicago, IL",
"searchTotalResults": 519,
"page": 3,
"position": 60,
"scrapedAt": "2026-10-10T18:33:15.501Z"
}

All output fields

FieldTypeDescription
jobIdstringZipRecruiter's job ID (the jid in the job URL). Stable across searches; used for de-duplication.
listingKeystringZipRecruiter's listing key for this job card.
titlestringJob title as posted.
companystringHiring company name.
companyIdstringZipRecruiter's company identifier.
companyUrlstringZipRecruiter page listing all jobs from this company.
companyLogostringLogo image URL, when the company has one.
locationstringLocation as displayed, e.g. "Austin, TX".
citystringCity of the job.
countystringCounty of the job, when resolved.
statestringState name.
stateCodestringTwo-letter state code.
postalCodestringZIP code, when the posting is pinned to one.
countrystringCountry name.
countryCodestringTwo-letter country code.
locationTypestringOn-site, Remote, Hybrid or Remote optional, as ZipRecruiter displays it.
isRemotebooleanTrue when the job is tagged remote.
employmentTypestringFull-time, Part-time, Contractor, Temporary, Per diem…; empty when the employer did not say.
payTextstringPay exactly as shown on the job card, e.g. "$32 - $39/hr". Empty when ZipRecruiter shows no pay.
payMinnumberLower pay bound in the pay period below.
payMaxnumberUpper pay bound in the pay period below.
payPeriodstringhour, day, week, month or year.
payCurrencystringPay currency (USD).
payMinAnnualnumberLower bound annualised by ZipRecruiter (hourly × 2,000, weekly × 50).
payMaxAnnualnumberUpper bound annualised by ZipRecruiter.
paySourcestringWhere the pay figure comes from: Employer, Job description, ZipRecruiter estimate, or Not published (ZipRecruiter estimate).
payIsEstimatedbooleanTrue when the pay figures are ZipRecruiter estimates rather than published by the employer.
benefitsstringBenefits detected for the job, e.g. "Medical, Dental, Vision, Retirement, PTO".
workplaceHighlightsstringWorker-survey highlights ZipRecruiter shows for the employer, e.g. "Respectful managers".
isNewbooleanTrue when ZipRecruiter labels the job as new.
isUrgentbooleanTrue when the employer marked the job urgent.
postedAtstringWhen the job was first posted (ISO 8601, UTC).
refreshedAtstringWhen the posting was last refreshed or reposted (ISO 8601, UTC).
postedAgostringRelative age shown on the card, e.g. "3 days ago".
updatedAtstringWhen ZipRecruiter last updated the job record (ISO 8601).
isActivebooleanWhether the listing is still active.
shortDescriptionstringDescription snippet from the job card (about 200 characters).
isQuickApplybooleanTrue when the job accepts ZipRecruiter 1-Click Apply; false when applying happens on the employer site.
applyTypestring"ZipRecruiter 1-Click Apply" or "Employer website".
applyUrlstringZipRecruiter's apply link for the job (redirects to the employer site for external jobs).
jobUrlstringCanonical ZipRecruiter job page.
searchKeywordstringKeyword of the search that found this job.
searchLocationstringLocation of the search that found this job.
searchTotalResultsnumberNumber of listings ZipRecruiter reported for that search.
pagenumberResult page the job was found on.
positionnumberRank of the job in that search.
scrapedAtstringWhen this row was collected (ISO 8601).
descriptionstringFull job description as plain text. Only with "Open every job page".
industrystringIndustry of the posting. Only with "Open every job page".
occupationalCategorystringO*NET-SOC occupation code and title, e.g. "29-1141.00: Registered Nurses". Only with "Open every job page".
validThroughstringDate the posting is set to expire. Only with "Open every job page".
educationstringEducation requirement, e.g. "Associate degree (required)". Only with "Open every job page".
companyWebsitestringEmployer's own website, when ZipRecruiter knows it. Only with "Open every job page".
companyDescriptionstringOne-line company description. Only with "Open every job page".
employerRatingnumberWorker rating of the employer on a 1–10 scale (Breakroom survey). Only with "Open every job page".
employerRatingCountnumberNumber of worker responses behind the rating. Only with "Open every job page".

Empty cells are honest: they mean ZipRecruiter did not publish that value for that job. A missing pay range is never turned into 0, and a missing benefit list is never guessed.

💵 About the pay columns

ZipRecruiter attaches a pay range to almost every job, but not every range comes from the employer. The paySource column keeps them apart:

paySourceMeaningShare in our test runs
EmployerThe employer published the pay.42%
Job descriptionZipRecruiter read the pay from the description text.31%
Not published (ZipRecruiter estimate)The employer gave no pay; the numbers are ZipRecruiter's internal estimate, not shown on the card.21%
ZipRecruiter estimateA ZipRecruiter estimate that is shown on the card.5%

payIsEstimated is true for the last two. For salary benchmarking, filter on payIsEstimated = false. payMinAnnual / payMaxAnnual use ZipRecruiter's own annualisation (hourly × 2,000, weekly × 50), so hourly, weekly and yearly jobs can be compared on one scale.

📊 How many results can I get?

ZipRecruiter caps every single search at its own result count — typically 400 to 900 listings per keyword × location (measured: "truck driver" in Dallas, TX reported 728; "registered nurse" in Chicago, IL 670; "software engineer" in Dallas, TX 454). Pages past that point come back empty, so volume comes from the grid:

GridSearchesTypical yield
1 keyword × 1 city1400–900 jobs
3 keywords × 1 city3~1,500–2,000 jobs
2 keywords × 2 cities4~2,000–2,500 jobs
10 keywords × 10 cities100~40,000–60,000 jobs
20 keywords × 50 metros1,000several hundred thousand listings

Jobs that appear in more than one search (a remote job, a 50-mile overlap between two cities) are kept only once — de-duplication is by ZipRecruiter's job ID across the whole run. With a Max jobs limit and several searches, each search gets a fair share first, so three keywords give you a mix rather than whichever search answered first.

Measured on the Apify platform (October 2026):

RunResultTimeDuplicates
3 keywords × Dallas, TX1,200 unique jobs5 min 51 s0
2 keywords × Atlanta, GA + Chicago, IL1,500 unique jobs (430 / 356 / 366 / 366 per search)6 min 52 s0
2 keywords × Los Angeles, CA + Miami, FL (12 parallel)1,100 unique jobs (353 / 271 / 269 / 213 per search)4 min 3 s0
2 keywords × Houston, TX + Phoenix, AZ (default settings, after the speed update)1,000 unique jobs1 min 22 s0
Store example input50 jobs35–41 s0

⚡ Speed and cost

  • 1,000 jobs in about 80 seconds with the default settings — measured 81.6 s for 1,000 unique jobs (2 keywords × Houston, TX + Phoenix, AZ). The same input took 269 s before the speed update.
  • Rows stream in as pages land. On large runs the first rows appear within ~5 s (dozens of pages start at once); a small run waits for the proxy's first answer, typically 20–30 s. The 50-job example run finishes in 35–40 s.
  • How: 40 result pages are loaded at once and every page the limit needs is queued at the start, so no worker waits. ZipRecruiter is reached through Apify's unblocking proxy, which answers a page in 20–40 s and occasionally not at all — a page that is slow gets a duplicate request on a fresh connection and the first answer wins. The run stops the instant Max jobs is reached and cancels whatever is still loading.
  • Platform usage about $0.06 per 1,000 jobs (proxy + compute), on top of the per-result price. The unblocking proxy bills only pages it delivers; duplicate requests that lose the race are cancelled before they are billed.
  • Deep mode (fetchDetails) opens one extra page per job, so it is much slower. Use it for a focused list (a few hundred jobs), not for bulk exports.
  • Memory: 512 MB is plenty — peak measured at 106 MB with 40 pages in parallel.

💡 Tips

  • Daily monitoring: schedule the Actor with postedWithin: "1" and the same keywords and locations; you get only the last 24 hours of postings each day.
  • Bigger lists: add metros instead of widening the radius — ten 25-mile searches return far more distinct jobs than one 100-mile search.
  • Only real salaries: filter the dataset on payIsEstimated = false.
  • Remote jobs: either set remoteOnly: true or use Remote as a location.
  • Company lists: export the Companies hiring view — one row per job with company, logo, ZIP and the company's ZipRecruiter page.
  • Paste a URL: anything you set up on ziprecruiter.com (filters included) works as a start URL.

❓ FAQ

Do I need a ZipRecruiter account or API key? No. The Actor reads public search result pages — no login, no cookies, no API key.

Is there an official ZipRecruiter API for this? ZipRecruiter's APIs are for partners and employers posting jobs; there is no open API for searching listings. This Actor fills that gap with a no-code export.

Why does it need the UNBLOCKER proxy? ZipRecruiter answers ordinary datacenter and residential proxies with HTTP 403. Apify's UNBLOCKER group gets through reliably; the Actor selects it automatically. If you remove it, the log warns you.

How fast is it? About 80 seconds for 1,000 jobs with the default settings; rows appear in the dataset as each page lands. Larger runs scale with the number of searches; raise Parallel requests (up to 50) for very large grids.

What happens if ZipRecruiter blocks a request? A refused or failed page is retried on a fresh exit IP (up to four attempts). If nothing at all can be fetched, the run fails with the reason instead of reporting success with zero rows, so an empty result always means "no matching jobs", never "blocked". Every run writes a SUMMARY record (outcome, pages read, per-search counts) to the key-value store.

Why did a search return fewer jobs than ZipRecruiter's headline number? ZipRecruiter caps each search at its own result count and some listings are duplicates of jobs already collected from another search. Add more keywords or locations for more volume.

How accurate is the pay data? The numbers are exactly what ZipRecruiter holds for the job. Use paySource / payIsEstimated to tell employer-published pay from ZipRecruiter estimates (see the pay section above).

Can I get the full job description? Yes — turn on Open every job page. It also adds industry, O*NET occupation, education requirement, closing date, company website and employer rating.

Can I scrape jobs outside the United States? This Actor targets ziprecruiter.com (US listings). Use Remote as a location for remote roles open to US candidates.

How do I run it every day? Create a Schedule in Apify Console with the same input and postedWithin: "1". Combine with a webhook or the Google Sheets integration to get new jobs delivered automatically.

Can I export to Excel, CSV or Google Sheets? Yes. Every dataset exports to JSON, CSV, Excel, XML, RSS and HTML, and connects to Google Sheets, Zapier, Make, n8n, Airtable and webhooks.

Will the same job appear twice? No. Jobs are de-duplicated by ZipRecruiter's job ID across all searches in a run. Across separate runs, use jobId as your key.

Is scraping ZipRecruiter legal? The Actor only reads publicly available job listings, without logging in or bypassing any access control. Job postings are published to be seen. You are responsible for how you use the data — respect ZipRecruiter's terms, applicable law and privacy rules (GDPR/CCPA) where personal data is involved; job listings themselves rarely contain any.

🔌 Use it through the API

JavaScript (apify-client)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('logiover/ziprecruiter-jobs-scraper').call({
keywords: ['registered nurse'],
locations: ['Houston, TX', 'Dallas, TX'],
postedWithin: '5',
maxItems: 1000,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);

Python (apify-client)

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("logiover/ziprecruiter-jobs-scraper").call(run_input={
"keywords": ["truck driver"],
"locations": ["Atlanta, GA", "Chicago, IL"],
"maxItems": 1500,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
print(job["title"], job["company"], job["payText"])

HTTP (run synchronously and get the items)

curl -X POST "https://api.apify.com/v2/acts/logiover~ziprecruiter-jobs-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"keywords":["electrician"],"locations":["Phoenix, AZ"],"maxItems":200}'

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by ZipRecruiter, Inc. or any of its subsidiaries. All trademarks mentioned are the property of their respective owners. The Actor collects publicly available information only; it does not log in, does not bypass access controls, and does not collect private user data. You are responsible for using the output in line with the website's terms and with applicable law.

💬 Support

Missing a field or hit a problem? Open an issue on the Actor's Issues tab and include the run ID — every run's SUMMARY record shows exactly what happened.

📝 Changelog

2026-10-10 — speed update

  • Faster: 1,000 jobs in ~80 s instead of ~270 s. 40 pages in parallel by default (max 50), all pages for the limit queued up front, slow pages hedged with a duplicate request (first answer wins, the loser is cancelled and not billed), one spare page per search so the slowest page is never waited for, and an immediate stop with in-flight requests cancelled once Max jobs is reached.
  • Rows stream into the dataset page by page; the status line shows live progress.
  • Fixed: with many pages finishing at once, a run could save more rows than Max jobs. The limit is now exact.

2026-10-10

  • First release: keyword × location grid, all verified ZipRecruiter filters, structured pay with source, benefits, workplace type, county/ZIP location, 1-Click Apply flag, posting and refresh dates.
  • Reads both page formats ZipRecruiter serves (it switches between them at random).
  • Fair share of the row limit per search; de-duplication across searches by job ID.
  • Optional deep mode: full description, industry, O*NET occupation, education, closing date, company website, employer rating.
  • Runs that cannot reach ZipRecruiter fail with the reason instead of returning an empty success.