ZipRecruiter Scraper avatar

ZipRecruiter Scraper

Pricing

from $0.77 / 1,000 jobs

Go to Apify Store
ZipRecruiter Scraper

ZipRecruiter Scraper

ZipRecruiter scraper API for US jobs 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 salary 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

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

6

Total users

2

Monthly active users

a day ago

Last modified

Features

Limited permissions

Share

ZipRecruiter scraper 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. Pay can be 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.

InputJob titles or keywords with a US or Canadian location, or ZipRecruiter URLs
OutputOne row per job: title, company, full location, employment type, remote flags, benefits, posted and reposted dates, employer apply link, pay with its source
Ceiling20,000 jobs per run, about 60 jobs per search (3 pages)
Account neededNone, 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 that really filter 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, so expect fewer jobs. 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 longer. 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 getField
The job and its stable IDsid, openSeatId, title, url
The companycompanyName, companyId, companyUrl, companyLogo
Where the job islocationText, city, state, stateCode, postalCode, county, countryCode
On-site, remote or hybridlocationTypes, locationTypeText, isRemote, isHybrid, isInPerson
Contract typeemploymentTypes, employmentTypeText
Pay the employer publishedsalaryMin, salaryMax, salaryMinAnnual, salaryMaxAnnual, salaryInterval, salaryText, salaryCurrency
ZipRecruiter's own pay estimateestimatedSalaryMin, estimatedSalaryMax, estimatedSalaryMinAnnual, estimatedSalaryMaxAnnual, estimatedSalaryInterval
Where the pay figure came fromsalarySource, salaryIsPublishedByEmployer, salaryIsEstimate, salaryShownOnSiteAsEstimate
Benefitsbenefits, benefitsText
Posted, reposted and still openpostedAt, repostedAt, postedAtRelative, isReposted, isActive, isNew, updatedAt
How to applyapplyUrl, applyRedirectUrl, applyType, hasZipApply
The textshortDescription, and with includeDescription on: description, companyRating, companyReviewCount, companyWebsite, companyIndustry, companyHq
The search that found itsearchQuery, searchLocation, searchUrl, page, position, scrapedAt

▶️ How to scrape ZipRecruiter jobs

  1. Open ZipRecruiter Scraper and click Try for free.
  2. Type a role into Job titles or keywords and a place into Location.
  3. Set Posted within, On-site / remote and the other filters if you want to narrow it.
  4. Set Maximum jobs. Start around 25 to see what the rows look like.
  5. 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 or 1-Click Apply filter is not billed.

📥 What you give it

{
"searchQueries": ["registered nurse"],
"location": "Austin, TX",
"days": "5",
"locationType": "only_remote",
"employmentType": "full_time",
"maxItems": 200
}
FieldDefaultWhat it is
searchQueriesnone, the form opens with registered nurseOne search per entry. Leave empty and set a location for the jobs there.
locationnone, the form opens with Austin, TXA 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.
startUrlsnoneZipRecruiter search URLs or individual job pages, pasted from the site.
daysany timePosted within the last 1, 5, 10 or 30 days.
radiusZipRecruiter's own 25 miles5, 10, 25, 50 or 5000 miles. Ignored for state-wide and country-wide searches.
locationTypeanyno_remote, only_remote or hybrid. hybrid keeps every job that isn't fully on-site, remote-optional ones included.
employmentTypeanyFull-time, part-time, contract, contract to hire, temporary, per diem or other.
experienceLevelanyno_experience, junior, mid or senior, as ZipRecruiter classifies them.
applyTypeanyhas_zipapply keeps only postings you can apply to on ZipRecruiter itself. The rest are dropped and not billed, so expect fewer jobs.
salaryMin, salaryMaxnoneZipRecruiter's own annual salary filter, which uses its own pay figure, estimates included.
onlyEmployerPublishedSalaryoffKeep only employer-published pay. Dropped rows are not billed.
includeDescriptionoffFull description and the company's review score.
maxItemsnone, the form opens with 50Total jobs for the run, up to 20,000. One search gives about 60 at most, so for more add keywords, or paste search URLs for other places.
egressModeautoLeave it on auto.
proxyConfigurationnoneOptional. 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"
}
FieldHow to read it
salarySourceemployer_provided, employer_description_parsed, ziprecruiter_estimate, ziprecruiter_internal_model or none. The first two are the employer's number.
salaryIsPublishedByEmployer, salaryIsEstimateThe same split as two booleans, for filtering in a spreadsheet.
salaryShownOnSiteAsEstimateWhether ZipRecruiter labels it as an estimate on its own page, which is not always the same thing.
applyUrlThe employer's own application page. applyRedirectUrl keeps the redirect if you want it.
postedAt, repostedAt, postedAtRelativeThe 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, isHybridOften 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

RowHow to spot itBilled
A jobIt has an id and no ok keyyes
The sample row_sample: true and charged: falseno
A diagnosticok: false, _diagnostic: true and an errorCodeno

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.

CodeWhat it means
NO_RESULTSThat search matched nothing, or the 1-Click Apply or employer-published pay filter left out every job it read. Pasted job links get the same note when the pay filter leaves out all of them. With 1-Click Apply on, a run can also stop early when many pages in a row have none; the note lists the searches it did not read.
BAD_URLA link that is not a ZipRecruiter search or job page.
JOB_UNAVAILABLEA pasted job has expired or been taken down.
NOT_SERVEDThree pasted job pages in a row did not come back, so the rest were not read. The note lists them. Run them again later.
UNKNOWN_FILTER_VALUEA filter value ZipRecruiter does not honour. It is left out with this note, and the search runs without it.
SEARCH_PAGE_UNAVAILABLETwo pages of results in a row did not come back, so that search stopped there.
TIME_LIMITThe 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.
COST_LIMITThe maximum cost per run you set would not cover a single job, so nothing was read. Raise it and run again.
UNEXPECTED_ERRORThe run stopped early on an unexpected error. The results before this row are kept.

Notes never fail the run, even a TIME_LIMIT or COST_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:

  1. Run this for registered nurse with location set to Texas and onlyEmployerPublishedSalary on.
  2. Compare salaryMinAnnual and salaryMaxAnnual by city. Every figure is the employer's own.
  3. Paste the busiest companyName values 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 60 jobs per search (3 pages). 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 States for 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.
  • 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.
  • postedAt can be years old on a reposted job. Read repostedAt alongside 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 wantUse
US jobs with pay marked published or estimatedThis one
LinkedIn job postings by keyword and locationLinkedIn Jobs Scraper
Every open role on one company's careers page, with the apply linkCareer Site Jobs Scraper
Jobs from Indeed, with pay and the employer's profileIndeed 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. Expect fewer jobs, 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.

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?

The API tab has code for Python, JavaScript and the CLI. MCP clients like Claude and ChatGPT use https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/ziprecruiter-scraper; coding assistants can load our skill file. All three bill your Apify account at the same price.

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.