# Job Listings & Salary Scraper for ZipRecruiter (US, UK, IE, CA) (`haketa/ziprecruiter-scraper`) Actor

ZipRecruiter job & salary scraper/API (US, UK, Ireland, Canada): search by keyword/location; export title, company, salary, location, type, date, description, apply URL. No login. Independent tool, not affiliated with or endorsed by ZipRecruiter; trademarks belong to their owners.

- **URL**: https://apify.com/haketa/ziprecruiter-scraper.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Features:** Limited permissions
- **Stats:** 25 total users, 4 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

<h1 align="center">ZipRecruiter Scraper 💼 — Jobs, Salary, Quick Apply & Geo (US, UK, IE, CA)</h1>

<p align="center">
  <img src="https://img.shields.io/badge/Platform-ZipRecruiter-237A3E?style=for-the-badge" alt="ZipRecruiter" />
  <img src="https://img.shields.io/badge/Markets-UK_%7C_IE_%7C_US_%7C_CA-0066CC?style=for-the-badge" alt="Markets" />
  <img src="https://img.shields.io/badge/Data-Jobs_%2B_Salary_%2B_Geo-FF9500?style=for-the-badge" alt="Job Data" />
  <img src="https://img.shields.io/badge/Scale-1%2C000%2B_Pagination-8E44AD?style=for-the-badge" alt="1,000+ Pagination" />
  <img src="https://img.shields.io/badge/Export-JSON_%7C_CSV_%7C_Excel_%7C_API-2ECC71?style=for-the-badge" alt="Export" />
</p>

**Scrape ZipRecruiter job listings into a clean, structured B2B dataset — no login and no coding.** This **ZipRecruiter scraper** extracts job postings from [ziprecruiter.co.uk](https://www.ziprecruiter.co.uk), [ziprecruiter.ie](https://www.ziprecruiter.ie), [ziprecruiter.com](https://www.ziprecruiter.com), and [ziprecruiter.ca](https://www.ziprecruiter.ca) with **job title, hiring company, normalized salary range, employment type, posted & expiration dates, exact geo coordinates, Quick Apply status, and full HTML + plain-text job descriptions**.

Export your **ZipRecruiter data** in bulk to **JSON, CSV, Excel, or API** — ready for your ATS, CRM, B2B lead generation pipeline, compensation benchmark database, or AI/LLM workflow.

> 💡 **Built for** recruitment & staffing agencies, B2B sales teams tracking hiring-intent signals, compensation and labor-market analysts, job-board aggregators, and AI teams building skill-extraction and salary-prediction datasets.

***

### ⚡ At a glance

| Feature | Details |
| :--- | :--- |
| **🌍 Supported Markets** | United Kingdom (`uk`), Ireland (`ie`), United States (`us`), and Canada (`ca`) |
| **🔍 Search Modes** | Keyword + Location search, Remote-only filter, Date-posted filter (`1`, `5`, `10`, `20` days), or direct `startUrls` |
| **📊 Rich Job Schema** | 28 structured fields including normalized `salaryMin`/`salaryMax`, `employmentType`, `latitude`/`longitude`, `quickApply`, and full descriptions |
| **🔢 Pagination & Scale** | Unlocked **1,000+ results pagination** (`maxPages: 0` unlimited default, governed by `maxRecords`) |
| **🛡️ Deduplication** | 100% deduplicated within every run by canonical numeric `jobId` |
| **⚡ Speed & Modes** | Fast list-only mode (`scrapeDescription: false`, ~5× faster) or full detail enrichment (`scrapeDescription: true`) |
| **📤 Export Formats** | JSON, CSV, Excel (XLSX), XML, RSS, and live Apify REST API / Webhooks |

***

### 📋 Table of contents

- [Why scrape ZipRecruiter?](#-why-scrape-ziprecruiter)
- [What this ZipRecruiter scraper does](#-what-this-ziprecruiter-scraper-does)
- [Use cases](#-use-cases)
- [Input parameters](#-input-parameters)
- [Output schema & field reference](#-output-schema--field-reference)
- [Pagination & 1,000+ scale](#-pagination--1000-scale)
- [How to use](#️-how-to-use)
- [Integrations & workflows](#-integrations--workflows)
- [Tips for best results](#-tips-for-best-results)
- [FAQ](#-faq)
- [Related scrapers](#-related-scrapers)
- [Changelog](#-changelog)

***

### 🔎 Why scrape ZipRecruiter?

ZipRecruiter is one of the world's largest online recruitment marketplaces across North America, the United Kingdom, and Ireland. Every public job posting contains high-value B2B intelligence: which companies are actively expanding headcount, what roles and tech stacks they are hiring for, what compensation bands they offer, where their offices are located, and whether they use instant in-platform applications.

Gathering this data manually is impractical: search results paginate ~20 jobs at a time across dozens of pages, exact posting dates and geo coordinates are embedded inside individual job pages, and compensation figures appear in mixed hourly, daily, and annual formats. This **ZipRecruiter data extractor** automates the entire workflow — walking every result page, normalizing salaries and locations, deduplicating by `jobId`, and delivering structured records ready for analytics or outreach.

**Common reasons teams scrape ZipRecruiter:**

- 🎯 **Hiring-intent B2B lead generation** — companies posting multiple engineering, sales, finance, or operations roles have active budget; trigger outbound sequences the day a role goes live.
- 💰 **Salary & compensation benchmarking** — compare `salaryMin`, `salaryMax`, `salaryCurrency`, and `salaryPeriod` across cities, regions, and job titles.
- 🤝 **Agency recruitment & candidate sourcing** — monitor open requisitions across your niche and identify employers struggling to fill specialist roles.
- 📈 **Labor-market & macroeconomic research** — track remote-work share (`isRemote`), contract vs. full-time ratios (`employmentType`), and hiring velocity over time.
- 🤖 **AI & LLM training pipelines** — feed clean `descriptionText` and `descriptionHtml` into skill-taxonomy extractors, resume matchers, and salary-estimation models.
- 🗺️ **Geo-spatial workforce mapping** — plot hiring clusters on maps using native `latitude` and `longitude` coordinates without paying for third-party geocoding APIs.

***

### ✨ What this ZipRecruiter scraper does

- ✅ **Multi-market job search (`uk`, `ie`, `us`, `ca`)** — search by job title, skill, or company name in any city, state, postcode, or nationwide.
- ✅ **Direct Start-URL support (`startUrls`)** — paste any pre-filtered ZipRecruiter search URL from your browser and scrape it directly.
- ✅ **Unlocked 1,000+ deep pagination** — automatically walks `?page=1, 2, 3…` with `maxPages: 0` (unlimited default) until your `maxRecords` target is reached or listings are exhausted.
- ✅ **Full job-detail enrichment (`scrapeDescription`)** — optionally visits each job page to capture full HTML & plain-text descriptions, exact `postedDate` and `validThrough` dates, `employmentType`, `latitude`/`longitude`, `companyUrl`, and the `quickApply` flag.
- ✅ **Built-in salary parser** — normalizes `$60k - $90k`, `£45,000 - £55,000 per annum`, `€25/hr`, and structured salary metadata into numeric `salaryMin`, `salaryMax`, `salaryCurrency`, and `salaryPeriod`, with an automatic fallback scan of the job description.
- ✅ **Smart location & postcode parser** — splits raw location strings into clean `city`, `state` (expanding region codes like `ENG` → `England`), `postcode` (UK postcodes, Irish Eircodes, Canadian postcodes, US ZIPs), and `country`.
- ✅ **Remote-work detection** — automatically flags remote and work-from-home listings (`isRemote: true`) from title, location, and description signals.
- ✅ **Fast list-only mode** — set `scrapeDescription: false` for rapid, high-volume discovery runs at a fraction of the time.

***

### 🎯 Use cases

| Team / Role | How they use this ZipRecruiter Scraper |
| :--- | :--- |
| 🎯 **B2B Sales & RevOps (Lead Gen)** | Scrape companies hiring for roles that buy your product (e.g., `"head of compliance"`, `"devops engineer"`, `"warehouse manager"`), deduplicate by `company`, and enrich decision-makers in your CRM. |
| 🤝 **Staffing & Recruiting Agencies** | Schedule daily runs with `datePosted: "1"` (Past 24 hours) to spot newly opened roles in London, Manchester, Dublin, Toronto, or New York before rival agencies pitch. |
| 💰 **HR & Compensation Consultants** | Pull 1,000+ listings per role category to calculate median, 25th-percentile, and 75th-percentile salary bands across regions. |
| 🗂️ **Niche Job Boards & Aggregators** | Populate vertical job boards (healthcare, logistics, fintech, remote-only) with live listings, `applyUrl` links, and clean snippets. |
| 📊 **Workforce & Economic Analysts** | Track month-over-month posting volume, regional hiring shifts, and remote-work adoption across UK, Irish, US, and Canadian markets. |
| 🤖 **AI & Data Science Teams** | Ingest thousands of full job descriptions (`descriptionText` / `descriptionHtml`) to train NER skill extractors and automated job-classification models. |

***

### 📥 Input parameters

All fields are optional — leaving the input completely empty runs a built-in diverse sample across popular job categories so your first run always returns clean data.

| Field | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `country` | `string` | `"uk"` | Target ZipRecruiter market: `"uk"` (`ziprecruiter.co.uk`), `"ie"` (`ziprecruiter.ie`), `"us"` (`ziprecruiter.com`), or `"ca"` (`ziprecruiter.ca`). UK and Ireland offer the fastest, most dependable results. |
| `keyword` | `string` | `""` (prefill `"software engineer"`) | Job title, skill, or company name to search (e.g., `"software engineer"`, `"registered nurse"`, `"accountant"`). Leave empty for a mixed sample across 10 popular job titles. |
| `location` | `string` | `""` (prefill `"London"`) | City, state, region, or postcode (e.g., `"London"`, `"Manchester"`, `"Dublin"`, `"New York, NY"`). Leave empty to search nationwide. |
| `remoteOnly` | `boolean` | `false` | When `true`, filters the search to remote / work-from-home listings only. |
| `datePosted` | `string` | `"any"` | Filter by posting recency: `"any"` (Any time), `"1"` (Past 24 hours), `"5"` (Past 5 days), `"10"` (Past 10 days), or `"20"` (Past 20 days). |
| `scrapeDescription` | `boolean` | `true` (prefill `false`) | Visit each job's detail page for full description, geo coordinates, employment type, exact dates, and Quick Apply status. Turn `false` for ~5× faster list-only runs. |
| `maxRecords` | `integer` | `100` | Maximum total jobs to return (`0` = unlimited, or set `1000`+ for large-scale harvests). |
| `maxPages` | `integer` | `0` | Maximum listing pages to walk per search (`0` = unlimited, governed by `maxRecords`). |
| `requestDelay` | `integer` | `1000` | Polite delay between requests in milliseconds (`300`–`10000`). |
| `startUrls` | `array` | `[]` | Advanced: paste one or more ZipRecruiter search URLs directly. Overrides `keyword` and `location`. |
| `proxyConfiguration` | `object` | `RESIDENTIAL` (`GB`) | Apify Proxy configuration. Match the residential proxy country (`GB`, `IE`, `US`, `CA`) to your chosen `country` market for optimal reliability. |

#### Input examples

**1. Fast UK job discovery run (list-only mode):**

```json
{
  "country": "uk",
  "keyword": "software engineer",
  "location": "London",
  "scrapeDescription": false,
  "maxRecords": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "GB"
  }
}
```

**2. Rich detail enrichment with full descriptions, geo & Quick Apply:**

```json
{
  "country": "uk",
  "keyword": "property manager",
  "location": "London",
  "remoteOnly": false,
  "datePosted": "any",
  "scrapeDescription": true,
  "maxRecords": 250,
  "requestDelay": 800,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "GB"
  }
}
```

<details>
<summary><strong>3. Deep 1,000+ multi-search harvest across multiple URLs (click to expand)</strong></summary>

```json
{
  "country": "uk",
  "startUrls": [
    "https://www.ziprecruiter.co.uk/jobs/search?q=software+engineer&l=London",
    "https://www.ziprecruiter.co.uk/jobs/search?q=data+analyst&l=London",
    "https://www.ziprecruiter.co.uk/jobs/search?q=project+manager&l=Manchester",
    "https://www.ziprecruiter.co.uk/jobs/search?q=accountant&l=Birmingham"
  ],
  "scrapeDescription": false,
  "maxRecords": 1000,
  "maxPages": 0,
  "requestDelay": 600,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "GB"
  }
}
```

</details>

<details>
<summary><strong>4. Ireland market search with country-matched IE residential proxy (click to expand)</strong></summary>

```json
{
  "country": "ie",
  "keyword": "registered nurse",
  "location": "Dublin",
  "datePosted": "10",
  "scrapeDescription": true,
  "maxRecords": 300,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "IE"
  }
}
```

</details>

***

### 📤 Output schema & field reference

Every job record uses a consistent 28-field JSON structure whether `scrapeDescription` is enabled or disabled.

```json
{
  "jobId": "635719110",
  "slug": "635719110-property-manager",
  "title": "Property Manager",
  "company": "Hobdens Property Management",
  "companyUrl": null,
  "location": "Littlehampton, ENG, GB",
  "city": "Littlehampton",
  "state": "England",
  "postcode": null,
  "country": "United Kingdom",
  "latitude": 50.81137,
  "longitude": -0.54078,
  "isRemote": null,
  "salaryMin": 40000,
  "salaryMax": 48000,
  "salaryCurrency": "GBP",
  "salaryPeriod": "year",
  "salaryRaw": "£40,000 - £48,000/year",
  "employmentType": "Full Time",
  "quickApply": false,
  "postedDate": "2026-10-31",
  "validThrough": "2026-11-30",
  "postedDateDisplay": "31 Oct",
  "descriptionText": "Job Description PROPERTY MANAGER Hobdens Property Management • Competitive • Hybrid - Littlehampton ROLE OVERVIEW You will take ownership of a well-established residential portfolio across East Sussex and West Sussex...",
  "descriptionHtml": "<h3>Job Description</h3><div><p><strong>PROPERTY MANAGER</strong></p>...</div>",
  "descriptionSnippet": "Job Description PROPERTY MANAGER Hobdens Property Management • Competitive • Hybrid - Littlehampton...",
  "applyUrl": "https://www.ziprecruiter.co.uk/jobs/635719110-property-manager",
  "listingUrl": "https://www.ziprecruiter.co.uk/jobs/635719110-property-manager",
  "searchKeyword": "property manager",
  "searchLocation": "London",
  "searchUrl": "https://www.ziprecruiter.co.uk/jobs/search?q=property+manager&l=London",
  "market": "UK",
  "scrapedAt": "2026-11-10T02:00:00.000Z"
}
```

#### 💼 Job identity & company fields

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| 🆔 `jobId` | `string` | 🟢 High (100%) | Unique numeric ZipRecruiter job identifier (primary deduplication key). |
| 🔗 `slug` | `string` | 🟢 High (100%) | Canonical URL slug (`{jobId}-{title-slug}`). |
| 🏷️ `title` | `string` | 🟢 High (100%) | Job title as published on the listing card. |
| 🏢 `company` | `string` | 🟢 High (~99%) | Hiring organization or recruitment agency name. |
| 🌐 `companyUrl` | `string` | 🟡 Conditional | Employer website URL when published in detail metadata. |
| 🕒 `employmentType` | `string` | 🟢 High (~87% w/ detail) | Normalized schedule type (`Full Time`, `Part Time`, `Contract`, `Temporary`, `Intern`). |
| ⚡ `quickApply` | `boolean` | 🟢 High (~87% w/ detail) | `true` when the job supports instant in-platform application (`directApply`). |

#### 📍 Location & geo fields

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| 📍 `location` | `string` | 🟢 High (100%) | Raw human-readable location string from the listing card. |
| 🏙️ `city` / `state` | `string` | 🟢 High (~98%) | Parsed city and normalized state/region/county (`ENG` → `England`). |
| 📮 `postcode` | `string` | 🟡 Conditional | Extracted UK postcode, Irish Eircode, Canadian postal code, or US ZIP when present. |
| 🌍 `country` / `market` | `string` | 🟢 High (100%) | Full country name (`United Kingdom`, `Ireland`, etc.) and 2-letter market code (`UK`, `IE`, `US`, `CA`). |
| 🧭 `latitude` / `longitude` | `number` | 🟢 High (~87% w/ detail) | Exact decimal geographic coordinates from the job detail page. |
| 🏠 `isRemote` | `boolean` | 🟡 Conditional | `true` when the title, location, or description indicates remote / work-from-home eligibility. |

#### 💰 Compensation, dates & content fields

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| 💵 `salaryMin` / `salaryMax` | `number` | 🟡 Conditional (~43%) | Numeric minimum and maximum pay when disclosed by the employer (card + description fallback). |
| 💱 `salaryCurrency` / `salaryPeriod` | `string` | 🟢 High / 🟡 Conditional | Currency code (`GBP`, `EUR`, `USD`, `CAD`) and pay period (`hour`, `day`, `week`, `month`, `year`). |
| 🏷️ `salaryRaw` | `string` | 🟡 Conditional (~43%) | Raw compensation string as displayed on the listing or detail page. |
| 📅 `postedDate` / `validThrough` | `string` | 🟢 High (~87% w/ detail) | Exact ISO-8601 (`YYYY-MM-DD`) posting date and expiration date from detail metadata. |
| 🗓️ `postedDateDisplay` | `string` | 🟢 High (~95%) | Short date badge shown on the search card (e.g., `"31 Oct"`, `"Just posted"`). |
| 📄 `descriptionSnippet` | `string` | 🟢 High (~99%) | Short summary snippet captured directly from the search results page. |
| 📝 `descriptionText` / `descriptionHtml` | `string` | 🟢 High (~87% w/ detail) | Complete plain-text and HTML job description (populated when `scrapeDescription: true`). |
| 🔗 `listingUrl` / `applyUrl` | `string` | 🟢 High (100%) | Canonical ZipRecruiter listing URL and application redirect/entry URL. |
| 🔎 `searchKeyword` / `searchLocation` / `searchUrl` | `string` | 🟢 High (100%) | Provenance fields recording the exact search query and URL that produced the record. |
| ⏱️ `scrapedAt` | `string` | 🟢 High (100%) | ISO-8601 UTC timestamp of extraction. |

***

### 🔁 Pagination & 1,000+ scale

ZipRecruiter serves **~20 job cards per search result page**. This actor is engineered for both rapid sampling and **1,000+ record bulk extraction**:

- **Automatic multi-page walking (`maxPages: 0`):** By default, `maxPages` is `0` (unlimited), meaning the scraper advances through `?page=1, 2, 3…` automatically until it reaches your `maxRecords` target or the search results end.
- **Zero-duplicate guarantee:** Every job card is checked against an in-memory `Set` of seen `jobId` values. If ZipRecruiter repeats a sponsored listing across pages or wraps pagination at the end of a result set, the scraper detects the duplicate-only page and stops cleanly.
- **Scaling past single-query limits (`1,000+` jobs):** To harvest several thousand jobs in one run, pass multiple city or role URLs in `startUrls` (or run a broad blank/multi-term sweep with `maxRecords: 1000+`). The actor iterates through every search sequentially and deduplicates across the entire dataset.

***

### ⚙️ How to use

1. Open **ZipRecruiter Scraper** in the Apify Console.
2. Pick your **Market (`country`)** — `uk` or `ie` for European markets, `us` or `ca` for North America.
3. Enter a **Search Keyword** (e.g., `"software engineer"`) and **Location** (e.g., `"London"`), or paste custom URLs into **Start URLs**.
4. Choose whether to enable **Scrape Full Description (`scrapeDescription`)** — leave `false` for fast list-only discovery or set `true` for full descriptions, exact dates, and geo coordinates.
5. Set **Max Records (`maxRecords`)** (e.g., `100` for a quick run or `1000`+ for a deep harvest) and click **Start**.

***

### 🔌 Integrations & workflows

- **HubSpot, Salesforce & Pipedrive** — automatically create or enrich company accounts when a target prospect posts new roles on ZipRecruiter.
- **Clay, Apollo & Hunter** — pipe scraped `company` names and `city`/`state` locations into contact-enrichment waterfalls to find hiring managers' verified emails.
- **Google Sheets & Looker Studio** — schedule recurring runs and track live salary bands and open-role counts by city.
- **Make, Zapier & n8n** — trigger instant Slack or email alerts whenever a high-priority role matches your keyword and salary criteria.
- **Snowflake, BigQuery & Postgres** — ingest daily job snapshots via Apify Webhooks keyed on `jobId`.

***

### 💡 Tips for best results

- 🌍 **Match your proxy country to the market:** In `proxyConfiguration`, keep `apifyProxyCountry: "GB"` for `country: "uk"`, set `"IE"` for `country: "ie"`, `"US"` for `country: "us"`, and `"CA"` for `country: "ca"`. Country-matched residential IPs ensure consistent local results.
- ⚡ **Use list-only mode for high-speed prospecting:** When your primary goal is discovering *which companies are hiring* (`company`, `title`, `location`, `salaryRaw`, `descriptionSnippet`), set `scrapeDescription: false` to run ~5× faster.
- 📅 **Use `datePosted: "1"` or `"5"` on scheduled runs:** If you run the scraper daily or every few days, filtering to recent postings avoids re-scraping older listings and keeps compute usage minimal.
- 🔀 **Combine multiple `startUrls` for 1,000+ harvests:** Group 5–10 regional or role-specific search URLs into a single run with `maxRecords: 2000` for a unified, deduplicated dataset.

***

### ❓ FAQ

**How many jobs can I scrape in a single run?**
You can extract **hundreds to thousands of unique jobs** per run. Set `maxRecords` to your desired cap (e.g. `1000`) or `0` for unlimited, and leave `maxPages: 0` so pagination continues automatically.

**Why are some `salaryMin` / `salaryMax` values `null`?**
Employers on ZipRecruiter choose whether to disclose compensation on a listing. In typical runs, ~40–50% of postings include an explicit salary range. Whenever pay is disclosed on the card, in the detail metadata, or inside the description text, the scraper extracts and normalizes it.

**Why do I get 0 results if I switch markets without changing the proxy country?**
ZipRecruiter routes traffic based on IP geography. Always pair `country: "uk"` with `apifyProxyCountry: "GB"`, `country: "ie"` with `"IE"`, `country: "us"` with `"US"`, and `country: "ca"` with `"CA"`.

**What happens if a narrow search matches 0 jobs?**
The actor logs a clear status message and exits cleanly without throwing a run failure, keeping your scheduled pipelines and health monitors green.

**Can I run this actor programmatically from Python or Node.js?**
Yes — use the `apify-client` package in Python or JavaScript, or call the Apify REST API directly to start a run and download the dataset in JSON, CSV, or Excel.

#### API Quickstart (Python & Node.js)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("haketa/ziprecruiter-scraper").call(run_input={
    "country": "uk",
    "keyword": "software engineer",
    "location": "London",
    "scrapeDescription": False,
    "maxRecords": 100,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "GB"
    }
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["jobId"], job["title"], job["company"], job["location"], job["salaryRaw"])
```

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('haketa/ziprecruiter-scraper').call({
    country: 'uk',
    keyword: 'data analyst',
    location: 'London',
    scrapeDescription: true,
    maxRecords: 100,
    proxyConfiguration: { useApifyProxy: true, apifyProxyGroups: ['RESIDENTIAL'], apifyProxyCountry: 'GB' },
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Extracted ${items.length} ZipRecruiter jobs`);
```

***

### 🔗 Related scrapers

- [SEEK Scraper — Australia & NZ Jobs with Salary](https://apify.com/haketa/seek-scraper)
- [Xing Jobs Scraper — DACH Job Listings & Salaries](https://apify.com/haketa/xing-jobs-scraper)
- [Naukri Scraper — India Jobs, Salary & Company Ratings](https://apify.com/haketa/naukri-scraper)
- [GulfTalent Jobs Scraper — Gulf Jobs, Salaries & Leads](https://apify.com/haketa/gulftalent-jobs-scraper)
- [Arbeitsagentur Job Scraper — Germany Jobs, Salary & Contact](https://apify.com/haketa/arbeitsagentur-scraper)
- [RemoteOK Scraper — Remote Jobs, Skills & Salary](https://apify.com/haketa/remoteok-scraper)

***

### 📋 Changelog

| Version | Date | Updates |
| :--- | :--- | :--- |
| **v1.2** | **2026-11** | **Unlocked 1,000+ job pagination:** removed the 100-record clamp when users explicitly request `maxRecords > 100` on default/multi-term runs, set `maxPages` default to `0` (unlimited, governed by `maxRecords`), and improved per-search scaling across multi-query runs. |
| **v1.1** | **2026-11** | Added JWT `data-track` job ID extraction for UK affiliate-redirect cards, stripped literal escape sequences from `descriptionHtml`/`descriptionText`, and improved UK/IE/CA postcode & region normalization. |
| **v1.0** | **2026-05** | Initial release supporting US, UK, Ireland, and Canada markets with salary normalization, geo coordinates, and full job-detail enrichment. |

# Changelog

This Actor's version history is a separate document: https://apify.com/haketa/ziprecruiter-scraper/changelog.md

# Actor input Schema

## `country` (type: `string`):

Which ZipRecruiter site to search. Pick the country whose jobs you want. United Kingdom and Ireland return the most dependable results.

## `keyword` (type: `string`):

Job title, skill or company to search for. Examples: 'software engineer', 'registered nurse', 'remote python developer', 'amazon'. Leave empty to pull a ready-made mixed sample of popular jobs.

## `location` (type: `string`):

City, state, postcode or region to focus the search. Examples: 'London', 'Manchester', 'Dublin', 'New York, NY'. Leave empty to search nationwide.

## `remoteOnly` (type: `boolean`):

Only return listings tagged as remote / work-from-home.

## `datePosted` (type: `string`):

Only return listings posted within the selected time window.

## `scrapeDescription` (type: `boolean`):

Visit each job's detail page to pull the full description, geo coordinates, employment type, posted / valid-through dates, the Quick Apply flag and any disclosed salary. Turn off for faster list-only scraping.

## `maxRecords` (type: `integer`):

Maximum total jobs to return. Set 0 for unlimited (the site shows up to ~25 results per page across many pages).

## `maxPages` (type: `integer`):

Maximum number of listing pages to walk per search. 0 = unlimited (bounded by Max Records).

## `requestDelay` (type: `integer`):

Delay between requests. 800-1500 ms keeps the run polite and stable; raise it for large runs.

## `startUrls` (type: `array`):

Optional. Paste any ZipRecruiter search URL directly (e.g. 'https://www.ziprecruiter.com/jobs-search?search=devops\&location=Austin%2C+TX'). When provided, this overrides the Keyword / Location / Market fields above. Most users can ignore this.

## `proxyConfiguration` (type: `object`):

ON by default — Apify RESIDENTIAL rotates a fresh IP per request so the run stays stable. For the UK site keep the country as GB; for Ireland set it to IE. Matching the proxy country to the market gives the most consistent results.

## Actor input object example

```json
{
  "country": "uk",
  "keyword": "software engineer",
  "location": "London",
  "remoteOnly": false,
  "datePosted": "any",
  "scrapeDescription": false,
  "maxRecords": 100,
  "maxPages": 0,
  "requestDelay": 1000,
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}
```

# Actor output Schema

## `jobId` (type: `string`):

Numeric ZipRecruiter job id

## `title` (type: `string`):

Job title

## `company` (type: `string`):

Hiring company name

## `city` (type: `string`):

Work location city

## `state` (type: `string`):

State, region or county

## `country` (type: `string`):

Country (US / United Kingdom / Ireland / …)

## `salaryRaw` (type: `string`):

Human-readable salary range

## `salaryMin` (type: `string`):

Numeric minimum salary

## `salaryMax` (type: `string`):

Numeric maximum salary

## `employmentType` (type: `string`):

Full Time / Part Time / Contract / …

## `quickApply` (type: `string`):

True when ZipRecruiter offers in-platform apply

## `isRemote` (type: `string`):

True when the listing is tagged remote

## `postedDate` (type: `string`):

ISO date the job was posted

## `listingUrl` (type: `string`):

Canonical ZipRecruiter job URL

## `scrapedAt` (type: `string`):

ISO timestamp of the scrape

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "country": "uk",
    "keyword": "software engineer",
    "location": "London",
    "datePosted": "any",
    "scrapeDescription": false,
    "maxRecords": 100,
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "GB"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/ziprecruiter-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "country": "uk",
    "keyword": "software engineer",
    "location": "London",
    "datePosted": "any",
    "scrapeDescription": False,
    "maxRecords": 100,
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "GB",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/ziprecruiter-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "country": "uk",
  "keyword": "software engineer",
  "location": "London",
  "datePosted": "any",
  "scrapeDescription": false,
  "maxRecords": 100,
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}' |
apify call haketa/ziprecruiter-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,haketa/ziprecruiter-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/g9ExX88Tc0hcOdOit/builds/E1hdinnfHpFk53ljw/openapi.json
