# Indeed Salary Jobs Scraper (`schnellscrapers/indeed-salary-jobs`) Actor

Extract Indeed jobs with normalized salary ranges, pay period, company, location, remote status, posted date, and apply URLs. Filter by minimum or maximum pay, salary period, remote work, job type, and freshness for recruiting alerts and compensation research. Pay per matching job.

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

## Pricing

$2.99 / 1,000 salary jobs

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/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

### What does Indeed Salary Jobs Scraper do?

Indeed Salary Jobs Scraper extracts job listings with employer-posted pay from Indeed and returns normalized salary ranges, pay periods, company, location, remote status, posting age, and apply links. It is built for recruiters, compensation researchers, job-board operators, and scheduled salary alerts that need matching rows instead of a large unfiltered dump.

Search one or more roles and locations, select a country domain, and filter the candidate rows by disclosed salary, hourly/monthly/yearly period, remote work, job type, freshness, radius, or date order. Salary filters run before dataset writes, so excluded jobs are not billed.

### What data can you extract from Indeed?

- **Compensation** — `salary.min`, `salary.max`, `salary.type`, `salary.currency`, and the original `salary.text`
- **Job identity** — `jobKey`, `title`, `viewJobUrl`, `postedRelative`, `postedAt`, and `scrapedAt`
- **Employer and place** — `company`, `companyIndeedUrl`, `companyRating`, `companyReviewCount`, `location`, `city`, `state`, and `country`
- **Work arrangement** — `remote`, `remoteWorkType`, and `jobTypes`
- **Hiring links and signals** — `thirdPartyApplyUrl`, `indeedApplyable`, `sponsored`, `urgentlyHiring`, and `snippet`
- **Search context** — `scrapedFromUrl`, `searchInput`, `urlInput`, and `scrapedAt` for routing and scheduled comparisons

### How to use Indeed Salary Jobs Scraper

1. Open Indeed Salary Jobs Scraper and click **Try for free**.
2. Add one or more objects to **Searches**, or paste Indeed search URLs into **Start URLs**.
3. Set `requireSalary`, `minSalary`, `maxSalary`, and `salaryPeriod` when you want a pay-focused feed. Add `remoteOnly`, `jobType`, `fromDays`, or `sort` to narrow the search.
4. Keep the residential proxy configuration enabled, then click **Start**.
5. Download the matching dataset as JSON, CSV, Excel, XML, or HTML, or read it through the Apify dataset API.

### How much does it cost?

Indeed Salary Jobs Scraper uses pay-per-event pricing. The launch price is **$2.99 per 1,000 matching job rows**. A row is billable only after it passes the salary and search filters and is written to the default dataset. The Apify free credit covers small test runs; start with 10–20 matches and a small page budget before scheduling larger searches.

### Input

Use `searches` for repeatable multi-role or multi-location runs. Each search can include `query`, `location`, and `country`, with optional Indeed search controls such as `remoteOnly`, `postedWithinDays`, `jobType`, `radius`, and `sort`. The global salary filters apply to every search in the run.

```json
{
  "searches": [
    { "query": "data analyst", "location": "Remote", "country": "us" },
    { "query": "compensation analyst", "location": "Boston, MA", "country": "us", "sort": "date" }
  ],
  "requireSalary": true,
  "minSalary": 80000,
  "salaryPeriod": "YEARLY",
  "maxItems": 50,
  "maxPagesPerSearch": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

### Output

Each dataset item is one matching Indeed job. Salary values are numeric when Indeed exposes a range; missing salary values are `null` in the nested object when `requireSalary` is off.

```json
{
  "jobKey": "a1b2c3d4e5f6g7h8",
  "title": "Senior Data Analyst",
  "company": "Northstar Health",
  "location": "Boston, MA",
  "city": "Boston",
  "state": "MA",
  "remote": false,
  "remoteWorkType": "IN_PERSON",
  "salary": {
    "min": 85000,
    "max": 110000,
    "type": "YEARLY",
    "currency": "USD",
    "text": "$85,000 - $110,000 a year"
  },
  "jobTypes": ["Full-time"],
  "postedAt": "2026-08-08T12:30:00.000Z",
  "viewJobUrl": "https://www.indeed.com/viewjob?jk=a1b2c3d4e5f6g7h8",
  "thirdPartyApplyUrl": "https://www.indeed.com/applystart?jk=a1b2c3d4e5f6g7h8",
  "scrapedAt": "2026-08-10T02:10:00.000Z"
}
```

### Integrations

Connect the dataset to [Make](https://apify.com/integrations/make), [n8n](https://apify.com/integrations/n8n), [Zapier](https://apify.com/integrations/zapier), Google Sheets, Airtable, webhooks, or a scheduled Apify task. Call the dataset from Python or Node with the [Apify API](https://docs.apify.com/api/v2).

### Related actors

- [Indeed Jobs Scraper](https://apify.com/schnellscrapers/indeed-jobs-scraper) — broader Indeed extraction for teams that need wider job fields.
- [Ashby Jobs Scraper](https://apify.com/schnellscrapers/ashby-jobs-scraper) — pull structured openings from public Ashby boards.
- [Greenhouse Jobs Scraper](https://apify.com/schnellscrapers/greenhouse-jobs-scraper) — pull structured openings from public Greenhouse boards.

### FAQ

#### How does Indeed Salary Jobs Scraper work?

It reads the job-card data that Indeed serves with its public search results, normalizes the salary values, applies the requested compensation filters, and writes only matching rows. The actor stays on the search-results path so salary feeds remain predictable and low cost.

#### Can I use Indeed Salary Jobs Scraper as an API?

Yes. Start a run through the Apify API, then read the run's default dataset. The API tab on the actor page provides ready-to-use HTTP, Python, and JavaScript examples.

#### Can I use Indeed Salary Jobs Scraper in Python or Node.js?

Yes. Use the `apify-client` package and iterate over the dataset after the run completes.

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("<your-username>/indeed-salary-jobs").call(run_input={
    "query": "data analyst",
    "location": "Remote",
    "country": "us",
    "requireSalary": True,
    "salaryPeriod": "YEARLY",
    "maxItems": 25
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["salary"]["text"])
```

#### Which countries are supported?

The actor routes searches to supported Indeed country domains including the US, UK, Canada, Australia, New Zealand, Germany, France, Spain, Italy, the Netherlands, Poland, India, Singapore, Japan, Brazil, and Mexico. Use a two-letter country code in each search.

#### Why do some jobs have no salary?

Salary is employer-provided and is not present on every Indeed card. Leave `requireSalary` on for a clean compensation feed, or turn it off when you need all matching job listings and can handle `null` salary values.

#### Is it legal to scrape Indeed?

This actor accesses job information that Indeed serves to anonymous visitors. You are responsible for using the output appropriately, checking the rules that apply to your use case and location, and handling any personal data in line with applicable requirements.

### Your feedback

If salary parsing, a country route, or a job-card layout needs attention, open an issue on the actor's **Issues** tab with the input and a small sample of the affected output.

# Actor input Schema

## `searches` (type: `array`):

List of Indeed searches to run. Each entry accepts `query`, `location`, `country`, `remoteOnly`, `postedWithinDays`, `jobType`, `radius`, and `sort`. Leave a field blank to broaden the search.

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

Optional: paste fully formed Indeed search URLs (for example, `https://www.indeed.com/jobs?q=data+analyst&l=Remote`). Used in addition to `searches`.

## `position` (type: `string`):

Shortcut for one search when `searches` and `startUrls` are empty. Use a role, skill, or company name such as `data analyst`.

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

Alias of `position` for a single search, such as `registered nurse`.

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

City, ZIP, locality, or `Remote`. Pairs with `position` or `query`.

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

Two-letter country code such as `us`, `uk`, `de`, `ca`, `au`, `fr`, or `in`. Selects the Indeed country domain.

## `jobType` (type: `string`):

Restrict the single-search shortcut to fulltime, parttime, contract, temporary, internship, or permanent jobs.

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

Distance from `location` in miles in the US or kilometers in most other countries.

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

Order results by `date` for newest postings or `relevance` for Indeed's default order.

## `fromDays` (type: `integer`):

Filter the single-search shortcut to listings posted within N days, for example `7` for the last week.

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

Alias of `fromDays` for the single-search shortcut. Use `7` to limit results to the last week.

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

Restrict the single-search shortcut to listings Indeed marks as remote.

## `requireSalary` (type: `boolean`):

Keep only listings with a numeric employer-posted salary range. Turn off to include jobs where Indeed does not show pay.

## `minSalary` (type: `number`):

Keep salary ranges that reach this amount in the selected pay period. For a range, the upper bound must meet the minimum.

## `maxSalary` (type: `number`):

Keep salary ranges that overlap this amount in the selected pay period. For a range, the lower bound must be at or below the maximum.

## `salaryPeriod` (type: `string`):

Match one normalized pay period: hourly, daily, weekly, monthly, or yearly.

## `maxItems` (type: `integer`):

Hard cap on matching job records across all searches. Indeed returns about 15 jobs per page; set this above your expected salary-match count.

## `maxItemsPerSearch` (type: `integer`):

Alias for `maxItems` when one search is provided.

## `maxPagesPerSearch` (type: `integer`):

Cap pages fetched per search. Indeed returns about 15 jobs per page, so 5 pages is roughly 75 candidates before salary filtering.

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

**Residential proxy is required.** Indeed blocks plain HTTPS and datacenter IPs within a few requests. Use the `RESIDENTIAL` Apify Proxy group.

## `dryRun` (type: `boolean`):

Parse and filter pages while logging candidate and match counts without writing dataset records.

## Actor input object example

```json
{
  "searches": [
    {
      "query": "software engineer",
      "location": "Remote",
      "country": "us"
    }
  ],
  "startUrls": [],
  "country": "us",
  "sort": "relevance",
  "remoteOnly": false,
  "requireSalary": true,
  "maxItems": 100,
  "maxPagesPerSearch": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "dryRun": false
}
```

# Actor output Schema

## `jobs` (type: `string`):

Flat list of Indeed job records — one record per job. Fields include jobKey, title, company, structured salary, location, posted date, snippet, apply URL, and search context.

# 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 = {
    "searches": [
        {
            "query": "software engineer",
            "location": "Remote",
            "country": "us"
        }
    ],
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("schnellscrapers/indeed-salary-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 = {
    "searches": [{
            "query": "software engineer",
            "location": "Remote",
            "country": "us",
        }],
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("schnellscrapers/indeed-salary-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 '{
  "searches": [
    {
      "query": "software engineer",
      "location": "Remote",
      "country": "us"
    }
  ],
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call schnellscrapers/indeed-salary-jobs --silent --output-dataset

```

## MCP server setup

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