ZipRecruiter Scraper API - US Jobs, Salary & Apply URL
Pricing
from $0.77 / 1,000 jobs
ZipRecruiter Scraper API - US Jobs, Salary & Apply URL
Scrape ZipRecruiter jobs in the US by title and place. Each row has the title, company, location, employment type, remote flag, posted date and the employer's own apply link, with pay split into the employer's figure and ZipRecruiter's estimate. $0.80 per 1,000 jobs.
Pricing
from $0.77 / 1,000 jobs
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
5
Total users
3
Monthly active users
2 days ago
Last modified
Categories
Share
Scrape ZipRecruiter jobs with the employer's apply link and the pay marked published or estimated: search by title and place, or paste a search URL, and the jobs come back as rows with the title, company, city and state, employment type, remote or on-site, the exact posted date, and the employer's own apply link rather than a redirect.
The awkward part first, and it is the reason this exists. A lot of the pay on ZipRecruiter is
ZipRecruiter's own estimate, not the employer's number. Rows keep the two apart: employer figures
live in salaryMin and salaryMax, estimates live in estimatedSalaryMin and estimatedSalaryMax,
and salarySource says exactly where the number came from. They are never mixed into one column.
| Input | Job titles or keywords with a US or Canadian location, or ZipRecruiter URLs |
| Output | One row per job: title, company, full location, employment type, remote flags, benefits, posted and reposted dates, employer apply link, pay with its source |
| Ceiling | 20,000 jobs per run. About 750 per search is ZipRecruiter's own limit |
| Account needed | None, and nothing to install |
| Price | $0.80 per 1,000 jobs on the Free plan, a little less on paid plans. The free plan's $5 a month covers about 6,200 |
🔍 What ZipRecruiter Scraper does
Give it keywords and a location, or paste search URLs and job pages from the site. Leave the keywords empty and set a location and you get the jobs in that place.
Filter values are checked before anything runs. ZipRecruiter ignores a value outside its own vocabulary and returns the unfiltered board, so a typo would quietly get you every job in the country and bill you for it. Only values the site actually honours are accepted here, which is why the filters are pick-lists rather than free text.
onlyEmployerPublishedSalary is the strict version of the pay promise: it keeps only postings whose
figure came from the employer, either as a structured pay field or written into the description, and
drops ZipRecruiter's estimates. About 76% of postings survive it. Dropped rows never reach the
dataset and are not billed.
includeDescription adds the full description plus the employer's ZipRecruiter review score and
review count. It costs one extra request per job, so the run takes roughly three times as long. It
adds fields rather than rows, so the price does not move. Without it you still get a summary of
around 200 characters.
📋 What data you get from each ZipRecruiter job
| What you get | Field |
|---|---|
| The job and its stable IDs | id, openSeatId, title, url |
| The company | companyName, companyId, companyUrl, companyLogo |
| Where the job is | locationText, city, state, stateCode, postalCode, county, countryCode |
| On-site, remote or hybrid | locationTypes, locationTypeText, isRemote, isHybrid, isInPerson |
| Contract type | employmentTypes, employmentTypeText |
| Pay the employer published | salaryMin, salaryMax, salaryMinAnnual, salaryMaxAnnual, salaryInterval, salaryText, salaryCurrency |
| ZipRecruiter's own pay estimate | estimatedSalaryMin, estimatedSalaryMax, estimatedSalaryMinAnnual, estimatedSalaryMaxAnnual, estimatedSalaryInterval |
| Where the pay figure came from | salarySource, salaryIsPublishedByEmployer, salaryIsEstimate, salaryShownOnSiteAsEstimate |
| Benefits | benefits, benefitsText |
| Posted, reposted and still open | postedAt, repostedAt, postedAtRelative, isReposted, isActive, isNew, updatedAt |
| How to apply | applyUrl, applyRedirectUrl, applyType, hasZipApply |
| The text | shortDescription, and with includeDescription on: description, companyRating, companyReviewCount, companyWebsite, companyIndustry, companyHq |
| The search that found it | searchQuery, searchLocation, searchUrl, page, position, scrapedAt |
▶️ How to scrape ZipRecruiter jobs
- Open ZipRecruiter Scraper and click Try for free.
- Type a role into Job titles or keywords and a place into Location.
- Set Posted within, On-site / remote and the other filters if you want to narrow it.
- Set Maximum jobs. Start around 25 to see what the rows look like.
- Click Start, then download the dataset as JSON, CSV or Excel, or read it from the Apify API.
Start it with no keywords, location or URL and you get one sample row, which is not billed.
💰 How much does it cost to scrape ZipRecruiter jobs?
$0.80 per 1,000 jobs on the Free plan, a little less on paid plans. On the free plan, the $5 Apify gives you each month covers about 6,200 jobs.
One billed row per job delivered. The sample row is not billed, diagnostic rows are not billed, and a posting dropped by the employer-published-pay filter never reaches the dataset and is not billed.
📥 What you give it
{"searchQueries": ["registered nurse"],"location": "Austin, TX","days": "5","locationType": "only_remote","employmentType": "full_time","maxItems": 200}
| Field | Default | What it is |
|---|---|---|
searchQueries | none, the form opens with registered nurse | One search per entry. Leave empty and set a location for the jobs there. |
location | none, the form opens with Austin, TX | A city and state, a state, or United States. For Canada, a city with its province, like Toronto, ON. Left empty, ZipRecruiter picks one area itself, so set it. |
startUrls | none | ZipRecruiter search URLs or individual job pages, pasted from the site. |
days | any time | Posted within the last 1, 5, 10 or 30 days. |
radius | ZipRecruiter's own 25 miles | 5, 10, 25, 50 or 5000 miles. Ignored for state-wide and country-wide searches. |
locationType | any | no_remote, only_remote or hybrid. |
employmentType | any | Full-time, part-time, contract, contract to hire, temporary, per diem or other. |
experienceLevel | any | no_experience, junior, mid or senior, as ZipRecruiter classifies them. |
applyType | any | has_zipapply keeps only postings you can apply to on ZipRecruiter itself. |
salaryMin, salaryMax | none | ZipRecruiter's own annual salary filter, which uses its own pay figure, estimates included. |
onlyEmployerPublishedSalary | off | Keep only employer-published pay. Dropped rows are not billed. |
includeDescription | off | Full description and the company's review score. |
maxItems | none, the form opens with 50 | Total jobs for the run, up to 20,000. |
egressMode | auto | Leave it on auto. |
proxyConfiguration | none | Optional. Only if you want the run to go out through servers of your own. |
📤 What you get back
A real row from a run on 20 September 2026, with the long redirect token cut short:
{"id": "EazrVIHe3SD2W9b_kEu68w","openSeatId": "e8a515fa6f1a5372","title": "RN, Registered Nurse - IMC MedSurgical A","url": "https://www.ziprecruiter.com/c/CHRISTUS-Health/Job/RN,-Registered-Nurse-IMC-MedSurgical-A/-in-San-Marcos,TX?jid=e8a515fa6f1a5372","companyName": "CHRISTUS Health","companyId": "christus health","companyUrl": "https://www.ziprecruiter.com/co/CHRISTUS-Health/Jobs","locationText": "San Marcos, TX","city": "San Marcos","state": "Texas","stateCode": "TX","postalCode": "78666","county": "Hays","countryCode": "US","locationTypes": ["IN_PERSON"],"locationTypeText": "On-site","isRemote": false,"isHybrid": false,"isInPerson": true,"employmentTypes": ["FULL_TIME"],"employmentTypeText": "Full-time","salarySource": "ziprecruiter_internal_model","salaryIsEstimate": true,"salaryIsPublishedByEmployer": false,"salaryMin": null,"salaryMax": null,"salaryMinAnnual": null,"salaryMaxAnnual": null,"salaryInterval": null,"salaryCurrency": "USD","salaryText": null,"estimatedSalaryMin": 31.25,"estimatedSalaryMax": 49.75,"estimatedSalaryMinAnnual": 62500,"estimatedSalaryMaxAnnual": 99500,"estimatedSalaryInterval": "HOUR","salaryShownOnSiteAsEstimate": false,"benefits": [],"benefitsText": null,"postedAt": "2024-02-27T20:43:20Z","repostedAt": "2026-09-14T20:43:20Z","postedAtRelative": "5 days ago","isReposted": false,"isActive": true,"isNew": false,"updatedAt": "2026-09-19T22:49:08.815300215Z","applyType": "OPEN_EXTERNAL","hasZipApply": false,"applyUrl": "https://careers.christushealth.org/opportunity/rn-registered-nurse-imc-medsurgical-a-325738?utm_campaign=ZipRecruiterPPC-RN","applyRedirectUrl": "https://www.ziprecruiter.com/job-redirect?match_token=Cp8BChZFYXpyVklIZTNTRDJXOWJfa0V1Njh3...","shortDescription": "Description CHRISTUS Santa Rosa Hospital - San Marcos, which originated in 1923 as Hays County Soldiers, Sailors and Marines Memorial Hospital, opened at its current Wonder World Drive location in","description": null,"companyRating": null,"companyReviewCount": null,"searchQuery": "registered nurse","searchLocation": "Austin, TX","searchUrl": "https://www.ziprecruiter.com/jobs-search?search=registered+nurse&location=Austin%2C+TX","page": 1,"position": 1,"scrapedAt": "2026-09-20T07:08:28.109Z"}
| Field | How to read it |
|---|---|
salarySource | employer_provided, employer_description_parsed, ziprecruiter_estimate, ziprecruiter_internal_model or none. The first two are the employer's number. |
salaryIsPublishedByEmployer, salaryIsEstimate | The same split as two booleans, for filtering in a spreadsheet. |
salaryShownOnSiteAsEstimate | Whether ZipRecruiter labels it as an estimate on its own page, which is not always the same thing. |
applyUrl | The employer's own application page. applyRedirectUrl keeps the redirect if you want it. |
postedAt, repostedAt, postedAtRelative | The original posting date, when it was put back up, and ZipRecruiter's own wording. A row can carry an old postedAt and a recent repostedAt, as above. |
isRemote, isHybrid | Often false on jobs ZipRecruiter files as remote or hybrid, because the record carries no location type. Read the limits below. |
Two dataset views are set up in the Console: overview, and salaryHonesty, which puts the published and estimated pay columns side by side.
🧾 Reading the output
| Row | How to spot it | Billed |
|---|---|---|
| A job | It has an id and no ok key | yes |
| The sample row | _sample: true and charged: false | no |
| A diagnostic | ok: false, _diagnostic: true and an errorCode | no |
Job rows carry no charged field; the flag only marks the sample and diagnostic rows as not real
results. The sample row looks like a realistic posting in the Console table, so filter on _sample
rather than reading by eye.
| Code | What it means |
|---|---|
NO_RESULTS | That search matched nothing. |
BAD_URL | A link that is not a ZipRecruiter search or job page. |
JOB_UNAVAILABLE | A pasted job has expired or been taken down. |
UNKNOWN_FILTER_VALUE | A filter value ZipRecruiter does not honour. It is left out with this note, and the search runs without it. |
SEARCH_PAGE_UNAVAILABLE | Two pages of results in a row did not come back, so that search stopped there. |
TIME_LIMIT | The run got close to its time limit and stopped on its own. The jobs delivered before that are complete and charged. Give the run more time, or ask for fewer jobs, to get the rest. |
Notes never fail the run, except a TIME_LIMIT stop before any job came back.
💡 What people use it for
- Pay benchmarking that holds up, because estimates and employer figures sit in separate columns.
- Recruiting-market research: who is hiring for a role in a metro, and how the postings are worded.
- Feeding an applicant tool with
applyUrl, which points at the employer rather than a redirect. - Watching a role daily with Posted within at 1 day and diffing on
id.
Employer pay for one role across a state, then who else those employers want:
- Run this for
registered nursewithlocationset toTexasandonlyEmployerPublishedSalaryon. - Compare
salaryMinAnnualandsalaryMaxAnnualbycity. Every figure is the employer's own. - Paste the busiest
companyNamevalues into Career Site Jobs Scraper to see the other roles they have open on their own careers page.
🚧 What it does not do
- The US and Canada only. For Canada, write the city with its province, like
Toronto, ON; pay comes back in Canadian dollars. ZipRecruiter's UK, Australian and other country sites are separate and are not read. - About 750 jobs per search is ZipRecruiter's own depth. Split by city, role or date window to go wider rather than raising the cap.
- An empty location is not the whole country. ZipRecruiter picks one area. Type
United Statesfor a nationwide search. - The remote and hybrid flags miss a lot. In a test, 6 of 15 remote-only results and 1 of 10
hybrid ones carried the flag. Filter with On-site / remote instead of on
isRemote. - Full descriptions and company ratings need the extra fetch, and even then not every posting carries a description. Around four in five do.
- A single failed page of results is skipped and the run carries on, without a row in the dataset marking the gap. Compare the count you asked for against the count you got.
- A pasted URL keeps only the filters this actor lists. Any other filter on it is dropped without a note.
postedAtcan be years old on a reposted job. ReadrepostedAtalongside it.- It is not an official ZipRecruiter tool. Dami's Studio is independent and is not affiliated with or endorsed by ZipRecruiter, or by any other company named on this page.
🧭 Which jobs scraper do you need?
| If you want | Use |
|---|---|
| US jobs with pay marked published or estimated | This one |
| LinkedIn job postings by keyword and location | LinkedIn Jobs Scraper |
| Every open role on one company's careers page, with the apply link | Career Site Jobs Scraper |
❓ Questions people ask
Do I need a ZipRecruiter account?
No. These are public job pages, and there is nothing to sign in to.
How do I get only real employer salaries?
Turn on Only employer-published pay. Roughly three in four postings survive it, and the ones dropped are not billed.
What is the difference between the salary fields?
salaryMin and salaryMax are the employer's own figure. estimatedSalaryMin and
estimatedSalaryMax are ZipRecruiter's model. A row never puts one in the other's place.
Does the apply link go to the employer?
Yes. applyUrl is the employer's page. applyRedirectUrl
keeps the original if you need it.
Why is description empty?
Turn on Fetch full description and company rating. It triples the run time, which is why it is off by default.
Can I call it from code or connect it to an AI assistant?
Yes. The API tab has ready-made code
for Python, JavaScript and the command line. For Claude, ChatGPT or another MCP client, connect
https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/ziprecruiter-scraper. Either way the
run happens on your Apify account at the same price.
Is scraping ZipRecruiter legal?
These are public job postings. Apify's write-up on the legality of web scraping is a good starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the search or URL you used and the run ID. The
errorCode on the diagnostic row usually names the problem on its own.