# Indeed Jobs Scraper (`wildorigins/indeed-jobs`) Actor

🏷️ From $2.80 / 1K | Export Indeed job listings with salary, location, job type and posting date. Fans the search across filters to return several times a single page of results, without an Indeed account.

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

## Pricing

from $2.80 / 1,000 job returneds

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

## Indeed Jobs Scraper

Export Indeed job listings as structured data: title, company, location, salary, job type, posting date and a description snippet. No Indeed account needed.

### 🔍 What does Indeed Jobs Scraper do?

It runs a job search on Indeed and returns every listing it finds as a clean row of data, ready for a spreadsheet, a database or your own product.

An Indeed search page shows 15 jobs and page two asks you to sign in. This scraper works around that without ever needing your credentials, so a typical city and job title returns around 57 unique jobs rather than 15. See [how it gets past 15 jobs](#how-does-it-get-more-than-15-jobs) below.

### 🧭 Is there an official Indeed API?

Not one you can sign up for. Indeed retired its public Job Search API, the old Publisher programme, and the APIs it still runs, such as Indeed Apply and Sponsored Jobs, are for posting and managing jobs and are limited to approved partner companies. There is no official self-serve route to read Indeed search results programmatically.

This Actor fills that gap by reading the same public search pages any visitor sees, and returning them as structured rows: one call in, JSON, CSV or Excel out, with salary text parsed into comparable figures and duplicates removed. No partner application, no key management, no browser automation of your own to maintain.

### 📊 What data can I extract from Indeed?

One row per job, deduplicated:

| | Field | What it holds |
|---|---|---|
| 🆔 | `jobId` | Indeed's own job key, stable across runs |
| 🏷️ | `title` | The job title as advertised |
| 🏢 | `company` | The company shown on the listing |
| 📍 | `location` | The location as Indeed displays it |
| 🏠 | `remote` | True when the listing is remote, from the flag or the location text |
| 📋 | `jobTypes` | Full-time, Part-time, Contract and so on, as Indeed lists them |
| 💰 | `salaryText` | The salary exactly as shown, for example "£45,000 - £55,000 a year" |
| 💰 | `salaryMin` | Lower bound parsed from the advertised salary |
| 💰 | `salaryMax` | Upper bound parsed from the advertised salary |
| 💰 | `salaryCurrency` | Currency of the parsed figures |
| 💰 | `salaryPeriod` | Period the figures refer to, year, month, day or hour |
| 📅 | `postedRelative` | Posting age as Indeed shows it, such as "3 days ago" |
| 📅 | `postedAt` | The posting date resolved to an ISO timestamp when available |
| 📝 | `snippet` | The short description Indeed shows on the card |
| 🔗 | `url` | Direct link to the listing |

### 💡 Why scrape Indeed?

**Salary benchmarking.** An HR manager pricing a data analyst opening in Manchester pulls every advertised range for that title in the region and writes the ad against real figures rather than survey data.

**Hiring signals.** A recruiter watching which companies are hiring for the same role in the same city runs the search weekly and diffs the company column.

**Job board and alerting products.** A newsletter that rounds up new remote junior developer roles every Monday feeds deduplicated listings straight into its send.

**Market research.** An analyst tracking whether warehouse hiring in the Midlands is rising or falling runs the same query monthly and charts the row counts.

**Career moves.** A job seeker who wants every listing for a niche title, not just the first 15, exports the lot to a spreadsheet and works through it with filters.

**Screening a specific employer.** Someone interviewing at a company pulls everything it currently advertises to see which teams are growing and what they pay.

### 🚀 How do I use Indeed Jobs Scraper?

1. Click **Try for free**.
2. Enter what you are searching for and where, for example `data analyst` in `London`.
3. Pick the country site to search with `country`, and cap the run with `maxResults`.
4. Click **Start** and wait for the run to finish.
5. Download the results as JSON, CSV or Excel, or pull them from the API.

### ⬇️ Input

```json
{
  "query": "data analyst",
  "location": "London",
  "country": "uk",
  "maxResults": 100
}
```

Either `query` or `location` is required.

| Field | Type | Default | What it does |
|---|---|---|---|
| `query` | string | | What to search for, exactly as you would type it into the Indeed search box |
| `location` | string | | A city, region or postcode to search near |
| `country` | string | `uk` | Which national Indeed site to search, as a two letter code. Match it to the location |
| `maxResults` | integer | `100` | The most jobs to return, which is also the most a run can charge |

### ⬆️ Output

#### Table view

Results arrive as a table you can sort and filter in the Console. There is a second view, Salary detail, that lines up the parsed pay figures for comparing listings against each other.

#### JSON

A typical row:

```json
{
  "jobId": "d21e90a08011fc27",
  "title": "Data Analyst",
  "company": "Example Analytics Ltd",
  "location": "London",
  "remote": false,
  "jobTypes": ["Full-time"],
  "salaryText": "£45,000 - £55,000 a year",
  "salaryMin": 45000,
  "salaryMax": 55000,
  "salaryCurrency": "GBP",
  "salaryPeriod": "year",
  "postedRelative": "3 days ago",
  "postedAt": "2026-08-07T00:00:00.000Z",
  "snippet": "We are looking for a data analyst to join...",
  "url": "https://uk.indeed.com/viewjob?jk=d21e90a08011fc27"
}
```

Download it from the run as JSON, CSV or Excel, or read it straight from the API.

### How does it get more than 15 jobs?

An Indeed search shows 15 jobs, and page two requires a signed in account. Rather than ask you for Indeed credentials, this scraper runs your search across several filters that split the results a different way, then merges and deduplicates them.

A typical city and job title returns around 57 unique jobs, measured on "data analyst" in London across the eight searches. The run stops early once the filters stop producing anything new, so you are not charged for queries that add nothing.

If you need more than that for one job title, run it per city rather than trying to go deeper in one place.

### ⏱️ How long does a run take?

Measured on real runs, so you know what normal looks like and can tell it apart from a run that has stalled.

| Jobs returned | Typical run time |
|---|---|
| 15, one search page | about 25 seconds |
| 65, all eight searches | 4 to 5 minutes |

Measured on 31 August 2026, after the browser was removed: warehouse in Manchester returned 65 unique jobs in 301 seconds and nurse in London returned 67 in 258. The equivalent runs took 1 to 2 minutes and 7 to 9 minutes before that, so the second row is now roughly twice as fast and returns more.

A narrow search finishes sooner and returns less, because it runs out of matching jobs rather than out of time: data analyst in London returns about 46.

Indeed sits behind Cloudflare, so every page is fetched through Apify's unblocker, which solves the challenge rather than simply carrying the request. That is most of the clock: the unblocker answers in 47 to 78 seconds a page and no amount of local speed changes it. Getting past the fifteen job ceiling means running the same search several ways rather than paging, so a run in the second row is eight full page loads rather than one.

That makes the run time close to a straight multiple of the pages fetched, so `maxResults` is the dial that controls it: 15 is one page, and each further 15 or so costs roughly another page. The first second or two of any run is the container starting rather than the work, and it is a plain Node container rather than a browser one, which is why that part is now negligible.

A run is never silently stuck. Every search variant is logged with the jobs it added, so you can watch the total climb, and jobs are written to the dataset as each variant completes rather than held back to the end, so a run that hits its time limit still leaves everything it had already collected.

**Set the run timeout to suit the size of the ask.** This Actor's default is 3600 seconds, which is comfortably more than the largest run in the table above (65 jobs across eight searches takes about 5 minutes). You are charged per delivered result rather than per minute, so a generous timeout costs you nothing and a tight one risks losing the run's work. Lower it only if you want a hard ceiling on how long a scheduled run may sit.

### 💰 How much does it cost?

You pay per unique job returned. Duplicates across filters are removed before charging, so one job is charged once no matter how many filters it appeared in. Set `maxResults` to cap what a run can cost.

$4.00 per thousand jobs on the free plan, falling with your Apify plan to $2.00 per thousand on Diamond. Runs that return nothing cost nothing.

Indeed is dearer per row than the rest of this catalogue and the reason is the unblocker rather than the scraping. Every page has to be solved past Cloudflare before it can be read, and that is a metered service. A search that only reaches public listing pages elsewhere reaches them here too, at a price that reflects what it takes to get them.

### 🔌 Integrations

Send results straight to Google Sheets, Slack, Airtable, Zapier, Make or your own webhook using [Apify integrations](https://docs.apify.com/platform/integrations). You can also trigger a run whenever something happens in another tool.

AI agents can run this Actor too, through the [Apify MCP server](https://mcp.apify.com). An agent connected to mcp.apify.com can discover it, read its input schema and start a run under the identifier `spookyweb/indeed-jobs`, then read the finished dataset. That means an assistant asked "what are data analyst roles paying in London right now" can call this Actor directly and answer from live listings.

### 🔗 Using Indeed Jobs Scraper with the Apify API

```bash
curl -X POST "https://api.apify.com/v2/acts/spookyweb~indeed-jobs/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "data analyst", "location": "London", "country": "uk", "maxResults": 100}'
```

Or with the Apify client:

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

const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('spookyweb/indeed-jobs').call({
  query: 'data analyst',
  location: 'London',
  country: 'uk',
  maxResults: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Full detail is in the [Apify API reference](https://docs.apify.com/api/v2), and every run is also callable from the [Python](https://docs.apify.com/api/client/python) and [JavaScript](https://docs.apify.com/api/client/js) clients.

### ❓ FAQ

#### Can I use the official Indeed API instead?

No. Indeed retired its public Job Search API, and the APIs it still operates are employer-side tools limited to approved partner companies. Reading the public search results is the practical route for most people.

#### Do I need an Indeed account or login?

No. Nothing here needs your credentials, and no account details are ever asked for or stored.

#### How many jobs can I get from one search?

Around 57 unique jobs for a typical city and job title, measured rather than estimated. The run stops when the filters stop finding anything new. To cover more of a market, run several narrower searches, splitting by city or by job title.

#### Do I need proxies?

No, proxy handling is built in and you do not need to supply or configure anything. Indeed sits behind Cloudflare, so requests are routed through Apify's unblocker, which is what accounts for most of a run's duration.

#### Why did my run return no jobs?

Usually the search genuinely has no matches, most often from a very narrow query or a misspelled location. Try broader keywords or a nearby city. An empty result is reported as a successful run with no rows, not as an error.

#### Can I scrape a specific company's jobs?

Yes, put the company name in `query` alongside the role, for example `data analyst Acme`. Indeed matches company names in its search.

### ⚖️ Is it legal to scrape Indeed?

Scraping publicly available data is legal in the UK, the EU and the US, and this scraper only ever reads pages that any visitor can see without logging in. It collects job adverts published by employers, which is business information rather than personal data.

It does not collect personal data about individuals, it does not log in, and it does not touch anything behind an account. If you go on to combine this data with personal data, that is on you to handle under GDPR. Apify's [ethical scraping guide](https://blog.apify.com/is-web-scraping-legal/) covers the wider picture.

### 👍 Your feedback

Found a bug, or want a field that is not here yet? Open an issue on the Actor's Issues tab. Requests that make the data more useful get built, and problems get fixed quickly.

### 🔎 You might also like

| Actor | What it does |
|---|---|
| [LinkedIn Jobs Scraper](https://apify.com/spookyweb/linkedin-jobs) | LinkedIn jobs with company enrichment and CV keyword matching, no login needed |
| [Reed Jobs Scraper](https://apify.com/spookyweb/uk-jobs-reed) | UK jobs from Reed with applicant counts and annualised salaries |
| [Totaljobs Scraper](https://apify.com/spookyweb/uk-jobs-totaljobs) | UK jobs from Totaljobs with duplicate agency repostings removed |

# Actor input Schema

## `query` (type: `string`):

What to search for, exactly as you would type it into the Indeed search box, for example "data analyst", "registered nurse" or "python developer". Broader terms return more results because each search is capped, so prefer "analyst" over a long phrase. Either this or a location is required.

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

A city, region or postcode to search near, for example "London", "Greater Manchester" or "SW1A 1AA". Leave empty to search the whole country. Either this or a job title is required.

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

Which national Indeed site to search, given as a two letter country code such as uk, us, ie, de or fr. This decides both the site searched and the country the request is routed through, so it should match the location you are searching.

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

The most jobs to return, which is also the most you can be charged for since charging is per unique job returned. A single Indeed search shows 15 jobs, so this actor runs the search across several filters to go beyond that; expect roughly 57 unique jobs for a typical city and job title. This is also the main control on how long a run takes, because each further 15 jobs is another page fetched through the unblocker and roughly another minute. The run stops early once filters stop producing new jobs.

## Actor input object example

```json
{
  "query": "data analyst",
  "location": "London",
  "country": "uk",
  "maxResults": 15
}
```

# Actor output Schema

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

One row per item: job listings with salary and type.

## `runSummary` (type: `string`):

Counts and stop reason for the run.

# 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 = {
    "query": "data analyst",
    "location": "London",
    "maxResults": 15
};

// Run the Actor and wait for it to finish
const run = await client.actor("wildorigins/indeed-jobs").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 = {
    "query": "data analyst",
    "location": "London",
    "maxResults": 15,
}

# Run the Actor and wait for it to finish
run = client.actor("wildorigins/indeed-jobs").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 '{
  "query": "data analyst",
  "location": "London",
  "maxResults": 15
}' |
apify call wildorigins/indeed-jobs --silent --output-dataset

```

## MCP server setup

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

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/BkcKc9frZp43LeRM7/builds/0yPx8YyRgXcl0ADsl/openapi.json
