# Indeed Jobs Scraper: Salary, Remote & Skills, 23 Countries (`tidydata-labs/indeed-jobs-scraper`) Actor

Scrape Indeed jobs by keyword and location in 23 countries. Each job comes with salary already split into min/max/period plus annual pay, a remote/hybrid/onsite flag, skills, benefits and full description. No login, no duplicates, pay only for jobs saved.

- **URL**: https://apify.com/tidydata-labs/indeed-jobs-scraper.md
- **Developed by:** [Tidy Data Labs](https://apify.com/tidydata-labs) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 job results

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?

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

## Indeed Jobs Scraper: Salary, Remote & Skills, 23 Countries

Scrape **Indeed** job listings by keyword and location and get data you can use straight away: salary already split into **min / max / period / currency** with **annual pay**, a **remote / hybrid / onsite** flag, job type, benefits, a **skills list**, posting date, full description and job URL. Works on 23 Indeed country sites.

**$3 per 1,000 jobs, residential proxy included.** You pay only for unique jobs saved to your dataset, never for duplicates or failed pages.

### Why use this Indeed scraper?

- **Salary you can sort and average.** Indeed shows pay as text like *"$33 - $48 an hour"* or *"£30,000 a year"*. You get `salaryMin: 33`, `salaryMax: 48`, `salaryPeriod: "hour"`, plus `salaryMinAnnual: 68640`, so hourly and yearly jobs sit on one scale.
- **Remote, hybrid or onsite in one field.** Filter remote jobs with `workArrangement = "remote"` instead of searching descriptions.
- **Skills and benefits as lists.** Count the skills employers ask for, or compare benefits across companies.
- **Clean, flat records.** One row per job with the same fields every time, ready for CSV, Excel, Google Sheets or a database.
- **Built to keep running.** Each search runs in a fresh browser session on residential proxy, results are de-duplicated, and the run stops on its own when new searches stop finding new jobs.
- **Spend caps you control.** Set **Max results** or a maximum charge per run, and the actor stops cleanly at the limit.

### What Indeed shows vs. what you get

| On Indeed | In your dataset |
|---|---|
| *$33 - $48 an hour* | `salaryMin` 33, `salaryMax` 48, `salaryPeriod` "hour", `salaryCurrency` "USD", `salaryMinAnnual` 68640, `salaryMaxAnnual` 99840 |
| *"This position is remote and can be located anywhere within the Continental US"* (in the description) | `workArrangement` "remote" |
| Requirements buried in a long description | `skills` \["SQL", "Tableau", "Power BI", "Forecasting", ...] |
| *Just posted* | `postedAt` "2026-10-02T05:00:00.000Z" |
| Benefits section | `benefits` \["Health insurance", "401(k) matching", "Paid parental leave", ...] |

### What does Indeed Jobs Scraper do?

Type in what you'd type into Indeed's search boxes (for example *"nurse"* in *"Austin, TX"*), choose how many jobs you want and how recent they should be, and the actor returns one structured record per job. It's built for:

- **Salary benchmarking:** compare pay across roles, cities and companies without re-parsing pay text yourself.
- **Labor-market and skills research:** see which skills, licenses and certifications employers ask for.
- **Job boards and aggregators:** feed fresh listings into your own site, newsletter or alerts.
- **Recruiting and sales intelligence:** track which companies are hiring, for what, and where.

It reads only Indeed's public, logged-out search and job pages. It never logs in and collects no data about job seekers.

### What data does it extract?

| Field | Example |
|---|---|
| `title` | Registered Nurse (RN) – Mobile IV Therapy |
| `company`, `companyRating` | United Airlines, 3.9 |
| `location`, `city`, `state`, `postalCode`, `country` | Austin, TX |
| `salaryText` (as shown) | $22 - $36 an hour |
| `salaryMin`, `salaryMax`, `salaryPeriod`, `salaryCurrency` | 22, 36, `hour`, `USD` |
| `salaryMinAnnual`, `salaryMaxAnnual` | 45760, 74880 |
| `salarySource` | `indeed` / `parsed` / `llm` |
| `workArrangement` | `remote` / `hybrid` / `onsite` |
| `jobType`, `jobTypes` | Full-time, \[Full-time, Part-time] |
| `benefits` | \[Health insurance, 401(k), Paid time off] |
| `postedAt`, `postedRelative` | 2026-10-04T05:00:00Z, "Just posted" |
| `shortDescription`, `description` | first 300 characters, full plain text |
| `skills` | \[BLS Certification, RN License, Patient monitoring, …] |
| `easyApply`, `isSponsored`, `urgentlyHiring` | true / false |
| `jobUrl` | https://www.indeed.com/viewjob?jk=… |

### How to scrape Indeed jobs

1. Click **Try for free**.
2. Enter **Keywords** and **Location**, pick the **Indeed country site**, and set **Max results** and **Posted within (days)**.
3. Click **Start**. Download the results as JSON, CSV, Excel or HTML, or pull them through the Apify API.

#### Input example

```json
{
    "keywords": "data analyst",
    "location": "Chicago, IL",
    "countryDomain": "www.indeed.com",
    "maxResults": 200,
    "postedWithinDays": 7
}
```

#### More input examples

Remote jobs only, last 3 days:

```json
{ "keywords": "python developer", "location": "Remote", "maxResults": 300, "postedWithinDays": 3 }
```

UK jobs, any date:

```json
{ "keywords": "registered nurse", "location": "Manchester", "countryDomain": "uk.indeed.com", "maxResults": 200, "postedWithinDays": 0 }
```

Fast, card-only results (title, company, location, salary; no full description):

```json
{ "keywords": "warehouse associate", "location": "Dallas, TX", "maxResults": 500, "fetchDetails": false }
```

#### Output example

```json
{
    "jobKey": "08f32bd70b67b819",
    "title": "Pediatric Private Duty Nurse (LVN/RN)",
    "company": "Private Household/Agency",
    "location": "Georgetown, TX 78626",
    "salaryText": "$22 - $36 an hour",
    "salaryMin": 22,
    "salaryMax": 36,
    "salaryPeriod": "hour",
    "salaryCurrency": "USD",
    "salaryMinAnnual": 45760,
    "salaryMaxAnnual": 74880,
    "salarySource": "indeed",
    "workArrangement": "onsite",
    "jobType": "Full-time",
    "jobTypes": ["Full-time", "Part-time"],
    "postedAt": "2026-10-04T05:00:00.000Z",
    "skills": ["CPR Certification", "BLS Certification", "RN License", "Pediatrics", "Tube feeding"],
    "jobUrl": "https://www.indeed.com/viewjob?jk=08f32bd70b67b819"
}
```

### How is salary normalized?

1. **Indeed's own structured pay** when the posting has it (`salarySource: "indeed"`).
2. Otherwise a **built-in parser** reads the displayed text in many formats: ranges, "from"/"up to", `K` suffixes, `£ € ₹` and other currencies, European `45.000 €` and Indian `5,00,000` number formats, hourly/daily/weekly/monthly/yearly (`salarySource: "parsed"`).
3. **Optional AI enrichment** (off by default): turn on *AI enrichment with Claude* and add your own Anthropic API key. Claude then fills in pay that appears only in the description, remote/hybrid hints and extra skills (`salarySource: "llm"`). This runs on your Anthropic account at roughly $0.002 per job with Claude Haiku.

Annualized values assume 2,080 hours, 260 days, 52 weeks or 12 months per year.

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

The actor uses pay-per-result pricing: **$0.003 per job saved** ($3 per 1,000). Platform usage, including the residential proxy, is included in that price. The Apify free plan's monthly credit covers about 1,500 jobs.

To cap your spend, set **Max results** or a maximum charge per run in the run options. The actor stops cleanly when it reaches either limit.

### How many results can I get?

Indeed shows logged-out visitors only the first page of results for any search. To get past that, the actor runs several first-page searches that slice your query in different ways (newest first, by distance, job type and experience level) and removes duplicates. A typical city-level search returns **100–400 unique jobs**. Broad national searches return more. The run stops by itself once new searches stop turning up new jobs, so you never pay for duplicates.

For larger collections, run several searches with narrower keywords or locations.

### Tips

- **Use residential proxy** (the default). Indeed blocks datacenter IPs.
- Turn off **Fetch full job details** for faster, cheaper-to-run searches when you only need the title, company, location and salary.
- Set **Location** to `Remote` to search remote jobs.
- Schedule the actor daily with **Posted within = 1** to build a running feed of new jobs.

### Guides

#### Guide 1: Build a salary benchmark for a role and city

1. Set **Keywords** to the role (for example `data analyst`) and **Location** to the city.
2. Set **Max results** to `300` and **Posted within (days)** to `30`.
3. Download the dataset as CSV or Excel. Use `salaryMinAnnual` and `salaryMaxAnnual` to compare hourly and yearly postings on the same scale, and `workArrangement` to compare work arrangements.

```json
{
  "keywords": "data analyst",
  "location": "Chicago, IL",
  "maxResults": 300,
  "postedWithinDays": 30
}
```

#### Guide 2: Get a daily feed of new jobs

1. Set your keywords and location, and set **Posted within (days)** to `1`.
2. Save the input as a **task** and add a daily **Schedule** in Apify Console.
3. Connect it to Google Sheets, Slack or email from the **Integrations** tab, so new postings arrive automatically each morning.

#### Guide 3: Compare the job market across countries

Pick another **Indeed country site** (for example `uk.indeed.com` or `ca.indeed.com`) and run the same keywords. Salaries are normalized to min/max per period in each run, so you can compare ranges between markets after converting currency.

#### Guide 4: Research which skills employers ask for

Keep **Fetch full job details** on. Each job includes a `skills` list taken from the description. Count the most common skills across a few hundred postings to see what employers want for a role.

#### Run it from code (API)

Replace `YOUR_APIFY_TOKEN` with your token from **Console > Settings > API & Integrations**. This call runs the actor and returns the results in one request:

```bash
curl -X POST "https://api.apify.com/v2/acts/tidydata-labs~indeed-jobs-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords":"nurse","location":"Austin, TX","maxResults":50}'
```

You can do the same with the `apify-client` package for Python or JavaScript, or connect the actor to Make, Zapier, n8n, Google Sheets or a webhook from the **Integrations** tab.

### Is it legal to scrape Indeed?

This actor collects only publicly available job postings that anyone can see without an account, and it does not collect personal data about job seekers. Job postings can still contain personal details, such as a recruiter's name, so make sure your use of the data complies with GDPR, CCPA and other applicable laws. Read Apify's blog post on [the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) for more.

### Integrations and API

Connect the results to Google Sheets, Slack, Zapier, Make, Airtable or a webhook, or call the actor from code with the [Apify API](https://docs.apify.com/api/v2) and the Python or JavaScript client.

### Feedback

Found a bug or need a field that's missing? Open an issue on the **Issues** tab. We usually reply within a day.

# Actor input Schema

## `keywords` (type: `string`):

Job title, skill or company to search for, exactly as you would type it into Indeed's "What" box.

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

City, state, ZIP/postcode or "Remote", as you would type it into Indeed's "Where" box. Leave empty to search the whole country.

## `countryDomain` (type: `string`):

Which Indeed country site to search.

## `maxResults` (type: `integer`):

Maximum number of unique jobs to save. You are charged per saved job.

## `postedWithinDays` (type: `integer`):

Only jobs posted in the last N days (Indeed's "Date posted" filter; 1, 3, 7 and 14 match Indeed's own options). Use 0 for any date.

## `fetchDetails` (type: `boolean`):

Open each job's detail page to get the full description, job types, benefits and better skills. Turn off for faster, card-only results (snippet instead of full description).

## `includeFullDescription` (type: `boolean`):

Add the full plain-text job description to each result. A 300-character short description is always included.

## `useLlm` (type: `boolean`):

Use Claude to fill gaps the built-in parser can't: salary stated only in the description, remote/hybrid hints and extra skills. Requires your own Anthropic API key; costs roughly $0.002 per job on your Anthropic bill. Off by default.

## `anthropicApiKey` (type: `string`):

Your Anthropic API key, used only when AI enrichment is on. Stored encrypted.

## `llmModel` (type: `string`):

Claude model for AI enrichment. Haiku is the cheapest and is plenty for this.

## `maxConcurrency` (type: `integer`):

How many Indeed searches to run in parallel. Higher is faster but more likely to be challenged.

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

Indeed blocks datacenter IPs. Residential proxy is strongly recommended.

## Actor input object example

```json
{
  "keywords": "nurse",
  "location": "Austin, TX",
  "countryDomain": "www.indeed.com",
  "maxResults": 20,
  "postedWithinDays": 7,
  "fetchDetails": true,
  "includeFullDescription": true,
  "useLlm": false,
  "llmModel": "claude-haiku-4-5",
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "keywords": "nurse",
    "location": "Austin, TX",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidydata-labs/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 = {
    "keywords": "nurse",
    "location": "Austin, TX",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("tidydata-labs/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 '{
  "keywords": "nurse",
  "location": "Austin, TX",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call tidydata-labs/indeed-jobs-scraper --silent --output-dataset

```

## MCP server setup

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