# ZipRecruiter Job Scraper (`scraptivo/ziprecruiter-scraper`) Actor

Scrape job listings from ZipRecruiter, including title, company, location, description, and employment type. Search by keyword with optional locations and radius filters.

- **URL**: https://apify.com/scraptivo/ziprecruiter-scraper.md
- **Developed by:** [Scraptivo](https://apify.com/scraptivo) (community)
- **Categories:** Jobs, Lead generation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 jobs

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

**ZipRecruiter Job Scraper** collects job listings from [ZipRecruiter](https://www.ziprecruiter.com) and turns them into structured data for market research, salary benchmarking, and automated job alerts. Provide search terms with optional locations and a radius, run the Actor, and export titles, companies, descriptions, employment types, and geo-coordinates to JSON, CSV, Excel, or your preferred integration. Use it to analyze hiring demand, track compensation trends, and feed recruitment pipelines. Pricing starts at **$1 per 1,000 jobs**.

### What can you automate with ZipRecruiter Job Scraper?

- **Build a job database** — Collect titles, companies, locations, descriptions, and employment types from any ZipRecruiter search query.
- **Monitor hiring demand** — See which skills, roles, and locations employers are posting for, in real time.
- **Track compensation trends** — Pull structured, normalized listings for salary benchmarking across regions and industries.
- **Schedule recurring collection** — Run daily or weekly on the Apify Scheduler to keep job data fresh.
- **Feed recruitment workflows** — Push structured job data through the Apify API or a webhook into a CRM, dashboard, or internal tool.

### Who is this scraper for?

| Team | Workflow |
|---|---|
| Market researchers | Analyzing job-market trends, in-demand skills, and hiring volume. |
| Recruiters and agencies | Building prospect lists of active openings by role and location. |
| Data analysts | Feeding normalized job data into analytics dashboards and models. |
| Job-board operators | Aggregating listings into their own platform or recommendation engine. |

### What data can you collect from ZipRecruiter?

| Data group | Example fields | How it helps |
|---|---|---|
| Job identity | `title`, `url`, `datePosted`, `validThrough`, `description` | Identify and deduplicate records with the stable job `url`. |
| Employer | `companyName`, `companyUrl`, `companySameAs` | Understand who is hiring and enrich company profiles. |
| Location | `locationLocality`, `locationRegion`, `locationCountry`, `locationPostalCode`, `latitude`, `longitude` | Map openings geographically. |
| Employment | `employmentType`, `directApply` | Filter by full-time/part-time/contract and application type. |

### How to use ZipRecruiter Job Scraper

1. Open the [ZipRecruiter Job Scraper](https://apify.com/scraptivo/ziprecruiter-scraper) on Apify.
2. Enter one or more **Search Queries** such as "Python Developer" or "Data Scientist".
3. Optionally add **Locations** and a **Search Radius** in miles.
4. Set **Max Jobs** to control the number of listings (0 = unlimited).
5. Run the Actor and export the dataset or connect it to your workflow.

```json
{
    "searchQueries": ["Web Developer"],
    "locations": ["Berlin"],
    "radius": 0,
    "maxJobs": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": ["RESIDENTIAL"]
    }
}
```

### Example workflow

#### Track weekly Web Developer openings in Berlin

1. Schedule a run every Monday with `searchQueries` = `["Web Developer"]` and `locations` = `["Berlin"]`.
2. Export the dataset to a spreadsheet and keep `title`, `companyName`, `datePosted`, and `url`.
3. Compare this week's postings against last week's to spot new openings and closed roles.
4. Deduplicate user-side against the stable job `url`.

### Automate and integrate your results

- **Schedules** — Job postings change daily. Run **daily** for close hiring monitoring or **weekly** for market research. Create separate scheduled tasks per search query so each keeps its own dataset.
- **Webhooks** — Enable a webhook on run completion to push fresh listings into a CRM, Google Sheets, or Slack pipeline.
- **Exports and API** — Download results as JSON, CSV, or Excel from the Apify Console, or call the Actor from the API:

```shell
curl "https://api.apify.com/v2/acts/scraptivo/ziprecruiter-scraper/runs?token=YOUR-APIFY-TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "searchQueries": ["Web Developer"],
    "locations": ["Berlin"],
    "radius": 0,
    "maxJobs": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": ["RESIDENTIAL"]
    }
  }'
```

- **Deduplication** — The Actor appends new results on every run and does not deduplicate across runs. Use the stable job `url` when merging results.

### Input reference

| Field | Type | Required | Default | What it controls |
|---|---:|---|---|---|
| `searchQueries` | Array of strings | No | `[]` | Job titles, skills, or keywords to search. |
| `startUrls` | Array of URLs | No | — | Full ZipRecruiter search URLs (ignored when `searchQueries` is provided). |
| `locations` | Array of strings | No | `[]` | Cities, regions, or "Remote"; combined with each search query. |
| `radius` | Integer | No | `0` | Search radius in miles from each location (0 = any distance). |
| `maxJobs` | Integer | No | `0` | Maximum job listings to scrape (`0` = unlimited). |
| `proxyConfiguration` | Proxy object | No | Apify proxy, RESIDENTIAL | Proxy settings for the run. |

### Output example

Each dataset item is one job listing:

```json
{
    "title": "Web Developer",
    "url": "https://www.ziprecruiter.com/jobs/web-developer-123",
    "datePosted": "2025-01-15",
    "validThrough": "2025-03-15",
    "description": "We are looking for a skilled Web Developer to join our team...",
    "employmentType": "FULL_TIME",
    "directApply": true,
    "companyName": "Tech Corp",
    "companyUrl": "https://techcorp.com",
    "locationLocality": "Berlin",
    "locationRegion": "Berlin",
    "locationCountry": "DE",
    "locationPostalCode": "10115",
    "latitude": "52.5200",
    "longitude": "13.4050"
}
```

### How much does it cost to scrape ZipRecruiter?

The Actor uses pay-per-event pricing. Each job record pushed to the dataset counts as one `job` event, billed at **$0.001 per job** — that is **$1 per 1,000 jobs**. A one-time actor-start event is also charged per run (one event per GB of memory, minimum one). Compute units consumed are deducted from your Apify plan, and volume discounts on paid Apify plans reduce the per-1,000 rate. When your event spending limit is reached, the run stops gracefully.

### Reliability and responsible use

- **Proxy requirement** — The Actor defaults to the Apify proxy with the RESIDENTIAL group. Residential IPs are recommended for reliable access to ZipRecruiter.
- **Retries and rate limits** — The Actor includes built-in retry logic and handles rate limiting gracefully.
- **Conditional fields** — Location coordinates and postal codes are populated when available; some fields are nullable.
- **Public data** — The Actor collects publicly visible job listings from ZipRecruiter.
- **Responsible use** — Only use the data in ways that comply with ZipRecruiter's terms of service and applicable law.

### Frequently asked questions

#### Can I scrape ZipRecruiter by keyword and location?

Yes. Enter any keyword in `searchQueries` and optionally add `locations` and a `radius` in miles. Each search query is combined with each location for targeted results.

#### Can I schedule the ZipRecruiter Job Scraper to run automatically?

Yes. Open the **Scheduler** tab in Apify Console and set a recurring schedule — daily for close hiring monitoring or weekly for market research. Create separate scheduled tasks per search query.

#### What counts as one result?

A job record pushed to the dataset counts as one `job` result ($1 per 1,000 jobs). A small one-time actor-start event is also charged at the start of each run.

#### Why are some fields empty?

Fields such as `locationPostalCode`, `latitude`, and `longitude` are populated only when the platform provides them. A null value usually means ZipRecruiter has no data for that field.

#### How do I avoid duplicate records?

The Actor appends results on every run and does not deduplicate across runs. Use the stable job `url` as the key when merging a fresh run into existing data.

#### Do I need a proxy?

The Actor works out of the box with the default Apify residential proxy, which is recommended for reliable access to ZipRecruiter.

### Related Scraptivo automations

- **[LinkedIn Job Scraper](https://apify.com/scraptivo/linkedin-job-scraper)** — Collect job listings from LinkedIn with search and filter options.
- **[Upwork Jobs Scraper](https://apify.com/scraptivo/upwork-jobs-scraper)** — Scrape freelance job postings from Upwork for market research.
- **[Glassdoor Jobs Scraper](https://apify.com/scraptivo/glassdoor-jobs-scraper)** — Extract job listings and company data from Glassdoor.

### Support and custom workflows

Need a different field, source, or delivery workflow? Contact Scraptivo at scraptivo@gmail.com. Include the Actor name, sample URL, required fields, and expected volume so we can assess the request.

# Actor input Schema

## `searchQueries` (type: `array`):

Job titles, skills, or keywords (e.g. "Python Developer", "Data Scientist", "Registered Nurse Brooklyn"). Primary input for AI agents — no URL required. Combine with Locations below for location-specific searches.

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

Full ZipRecruiter search URLs copied from your browser (e.g. https://www.ziprecruiter.de/jobs/search?q=python\&l=Berlin). Optional override for power users — ignored when Search Queries are provided.

## `locations` (type: `array`):

City, state, or country names (e.g. "Berlin", "New York, NY", "Remote"). Leave empty for nationwide or remote search. Combined with each Search Query.

## `radius` (type: `integer`):

Search radius in miles from the location (0 = any distance). Applies to all location searches.

## `maxJobs` (type: `integer`):

Maximum number of job listings to scrape (0 = unlimited). Use a specific number to control costs and runtime.

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

Proxy settings for anti-bot protection. Apify Residential proxy recommended for reliable scraping.

## Actor input object example

```json
{
  "searchQueries": [
    "Web Developer"
  ],
  "startUrls": [
    {
      "url": "https://www.ziprecruiter.de/jobs/search?q=Web+Developer&l=Berlin"
    }
  ],
  "locations": [
    "Berlin"
  ],
  "radius": 0,
  "maxJobs": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

JSON array of scraped job records. Fetch this URL after the run completes to retrieve results.

## `run` (type: `string`):

Apify Console link to inspect this run's logs, input, and output.

# 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 = {
    "searchQueries": [
        "Web Developer"
    ],
    "startUrls": [
        {
            "url": "https://www.ziprecruiter.de/jobs/search?q=Web+Developer&l=Berlin"
        }
    ],
    "locations": [
        "Berlin"
    ],
    "maxJobs": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraptivo/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 = {
    "searchQueries": ["Web Developer"],
    "startUrls": [{ "url": "https://www.ziprecruiter.de/jobs/search?q=Web+Developer&l=Berlin" }],
    "locations": ["Berlin"],
    "maxJobs": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("scraptivo/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 '{
  "searchQueries": [
    "Web Developer"
  ],
  "startUrls": [
    {
      "url": "https://www.ziprecruiter.de/jobs/search?q=Web+Developer&l=Berlin"
    }
  ],
  "locations": [
    "Berlin"
  ],
  "maxJobs": 20
}' |
apify call scraptivo/ziprecruiter-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scraptivo/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/H4ylOgpGNyzkjB60G/builds/Vayw9kN3qNC5axSIJ/openapi.json
