# Indeed Jobs Scraper (`s-r/indeed-jobs-scraper`) Actor

- **URL**: https://apify.com/s-r/indeed-jobs-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Jobs, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## Indeed Jobs Scraper

An Indeed scraper that returns job postings with the salary already parsed into a minimum, a maximum and a period, plus the employer's rating and review count. No login, no API key, no browser, no unblocking service.

It works because it does not ask as a browser. Indeed answers a browser user-agent with HTTP 403 from every exit, and serves the full page to a crawler.

### What you get

- **Salary as numbers**, not a string. `salary_min`, `salary_max`, `salary_period` (yearly, monthly, hourly) and `salary_currency`, taken from Indeed's own extraction. Around 80% of rows in a typical search carry one
- **Employer rating and review count** on the same row as the job, so you can filter a listing by what people who work there say about it
- **Job types, shifts and benefits** as lists, parsed out of Indeed's taxonomy rather than guessed from the description
- **Sponsored versus organic** as a boolean, so paid placements do not quietly skew a market analysis
- **14 national Indeed sites** with the exit pinned per country, so a Dutch search returns euros and a UK one pounds
- **Multiple search terms and locations in one run**, fanned out and deduplicated on Indeed's own job key
- **`posted_at` as a real timestamp**, not "7 days ago"
- **Charged per row, not per compute unit.** A flat $0,002 start fee plus what you actually receive

### Why this one is cheaper to run

Request indeed.com with an ordinary browser user-agent from any IP we have and you get **HTTP 403**. That is why the Indeed actors on the market either drive a headless browser or pay a third-party unblocking service, and why their prices run up to $5 per 1.000 rows.

Ask for the same URL as a crawler and Indeed returns the full 2 MB page, because it wants its listings in search results and AI answers. One plain HTTP request, no browser, no unblocker. That cost difference is the reason this actor is priced at $1,50 rather than $5.

The second thing worth knowing is where the data is. The rendered page shows 16 job cards. `window.mosaic.providerData` carries **around 40**, each with 116 fields including the parsed salary range and the company rating. Reading the DOM gets you a third of the jobs and a fraction of the fields.

### Input

| Field | Type | Required | Default | What it does |
|---|---|---|---|---|
| `queries` | array | yes | `["data engineer"]` | Job titles or keywords. Give several |
| `locations` | array | no | `["New York"]` | Every term is run against every location |
| `market` | select | no | `us` | Which national Indeed site, and therefore the currency |
| `posted_within` | select | no | `any` | `24h`, `3d`, `week`, `2weeks` |
| `job_type` | select | no | `any` | Full-time, part-time, contract, temporary, internship |
| `remote_only` | boolean | no | `false` | Restrict to remote-tagged jobs |
| `sort` | select | no | `relevance` | `relevance` or `date` |
| `limit` | integer | no | `100` | Jobs to return across all searches, 1 to 2000 |
| `retries` | integer | no | `4` | Retry attempts per search |

### Output

```json
{
  "position": 1,
  "job_id": "70c2803e703ec745",
  "title": "Data Engineer",
  "company": "ComputerPeople Staffing",
  "company_rating": 4.8,
  "company_reviews_count": 4,
  "location": "Buffalo, NY 14221",
  "is_remote": false,
  "url": "https://www.indeed.com/viewjob?jk=70c2803e703ec745",
  "salary_min": 100000,
  "salary_max": 135000,
  "salary_period": "YEARLY",
  "salary_currency": "USD",
  "salary_text": "$100,000 - $135,000 a year",
  "job_types": [
    "Full-time"
  ],
  "posted_at": "2026-08-24T05:00:00Z",
  "posted_relative": "7 days ago",
  "easy_apply": true,
  "is_sponsored": false,
  "snippet": "Design and maintain data pipelines ...",
  "market": "us",
  "query": "data engineer",
  "search_location": "New York"
}
```

### Use cases

**Salary benchmarking.** `salary_min`, `salary_max` and `salary_period` come out of Indeed's own extraction rather than a regex over prose, so a run across one title in ten cities gives you a comparable distribution rather than a pile of strings. Filter to `is_sponsored: false` first, because paid placements over-represent agencies.

**Recruitment market mapping.** Run your competitor set as `queries` and your operating region as `locations`. `company_rating` and `company_reviews_count` on the same row tell you which of them are hiring hard and which have a reputation problem, which is the pair that predicts who is about to lose people.

**Feeding a job board.** Job keys are stable, so a scheduled run with `posted_within: 24h` and `sort: date` deduplicates cleanly into an index. `snippet` is plain text with the markup stripped, ready for search or embedding.

**Tracking hiring as a business signal.** A company that posts twenty engineering roles in a month is doing something. Run their name as a query weekly, count rows, and you have an early indicator that no press release gives you.

### How it compares

| | this actor | `borderline/indeed-scraper` | `valig/indeed-jobs-scraper` |
|---|---|---|---|
| Per 1.000 jobs | **$1,50** | $5,00 | $0,10 |
| Actor-start fee | **none** | none | $0,001 |
| Salary parsed to min / max / period | **yes** | not stated | no |
| Employer rating and review count | **yes** | no | no |
| Sponsored-versus-organic flag | **yes** | no | no |
| Markets | **14** | fewer | fewer |
| Needs a browser or unblocker | **no** | likely | likely |

Honest about the other side: `valig/indeed-jobs-scraper` has 3.602 monthly users and charges $0,10 per 1.000, which is fifteen times cheaper than this actor. If you want titles and links in bulk and nothing else, that is the better buy. This one is for when the salary and the employer matter.

### Pricing

One event. `job` costs $0,0015 per job returned, which is $1,50 per 1.000. Jobs are deduplicated on Indeed's job key before billing, so the same posting appearing in two searches is charged once. A $0,002 start fee covers the run itself; everything else is charged per row you receive. No per-compute-unit charges.

### Limits and gotchas

- **First result page only.** Indeed serves `&start=10` and beyond as an empty shell to crawler user-agents. One search returns roughly 15 to 40 jobs depending on the market. **Add search terms and locations to go wider** rather than expecting deep pagination; that is what the array inputs are for.
- **Search count is capped at 60 per run** (terms multiplied by locations), because each pair is a separate page fetch.
- **Salary is present on roughly 8 in 10 US rows** and fewer in markets where employers publish less. A missing salary is a real absence, not a parse failure.
- **`company_rating` is 0 for employers with no reviews**, which is how Indeed represents it rather than a null.
- **Sponsored jobs appear in results** and are flagged. Filter them out before computing market statistics.
- **Job keys are per market.** The same role on indeed.com and nl.indeed.com has different keys, so cross-market deduplication needs a title-and-company match.

### FAQ

**Why does my Indeed scraper get 403?**
Because it asks as a browser. Indeed refuses browser user-agents from datacenter and residential IPs alike. This actor asks as a crawler and is served the full page.

**Do I need a proxy or an unblocking service?**
No unblocker and no browser. Requests egress from the market's own country so salaries and locations match that market.

**Can I get more than 40 jobs for one search?**
Not from a single search: Indeed only serves the first page this way. Give more search terms and more locations instead, which is usually what you wanted anyway since it targets the segments you care about.

**Is the salary reliable?**
It is Indeed's own extraction, exposed as min, max, period and currency. Where the employer published a range, you get the range. Where they published nothing, the fields are empty rather than estimated.

**Which countries are supported?**
Fourteen: US, UK, Netherlands, Germany, France, Spain, Italy, Canada, Australia, India, Ireland, Belgium, Poland and Sweden.

### Related Actors

- [LinkedIn Jobs Scraper](https://apify.com/s-r/linkedin-jobs-scraper) — the same treatment for LinkedIn, with full descriptions
- [LinkedIn Company Finder](https://apify.com/s-r/free-linkedin-company-finder---linkedin-address-from-any-site) — resolve a website to its LinkedIn company page
- [Reddit Scraper](https://apify.com/s-r/reddit-scraper) — posts, comments and keyword search without an API key

# Actor input Schema

## `queries` (type: `array`):

Job titles or keywords. Give several: Indeed only serves its first result page to this actor, so more searches is how you get more jobs.

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

Cities, regions or postcodes as Indeed spells them. Every search term is run against every location, so 3 terms and 5 cities is 15 searches. Leave empty to search the whole market.

## `market` (type: `string`):

Which national Indeed site to read. The proxy exit is pinned to that country, so salaries come back in the local currency.

## `posted_within` (type: `string`):

Only return jobs published inside this window.

## `job_type` (type: `string`):

Filter by contract type.

## `remote_only` (type: `boolean`):

Restrict to jobs Indeed tags as remote.

## `sort` (type: `string`):

Relevance is Indeed's default. Date puts the newest first, which is what a monitoring schedule wants.

## `limit` (type: `integer`):

How many jobs to return across all searches, 1 to 2000. One search yields roughly 15 to 40 jobs.

## `retries` (type: `integer`):

Retry attempts per search, each with a different crawler user-agent and TLS fingerprint.

## Actor input object example

```json
{
  "queries": [
    "data engineer"
  ],
  "locations": [
    "New York",
    "Chicago"
  ],
  "market": "us",
  "posted_within": "any",
  "job_type": "any",
  "remote_only": false,
  "sort": "relevance",
  "limit": 100,
  "retries": 4
}
```

# Actor output Schema

## `results` (type: `string`):

One row per job posting.

## `summary` (type: `string`):

Searches run, pages that carried the payload, jobs returned and how many had a salary.

## `errors` (type: `string`):

Per-search failures with a code and a redacted message.

# 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 = {
    "queries": [
        "data engineer"
    ],
    "locations": [
        "New York"
    ],
    "limit": 100,
    "retries": 4
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/indeed-jobs-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 = {
    "queries": ["data engineer"],
    "locations": ["New York"],
    "limit": 100,
    "retries": 4,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/indeed-jobs-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 '{
  "queries": [
    "data engineer"
  ],
  "locations": [
    "New York"
  ],
  "limit": 100,
  "retries": 4
}' |
apify call s-r/indeed-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/indeed-jobs-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/Y2gNolJMPDyNRINhf/builds/TEVPo7yxsAjN8Dxg7/openapi.json
