# Indeed Jobs Scraper — Pay Per Result (`smorgi_apps/indeed-jobs-scraper`) Actor

Scrape public Indeed job listings by keyword and location. Playwright browser + residential proxies, stable schema, pay per result (~$5 / 1,000 jobs).

- **URL**: https://apify.com/smorgi\_apps/indeed-jobs-scraper.md
- **Developed by:** [Smorgi Apps](https://apify.com/smorgi_apps) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 job listings

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

## Indeed Jobs Scraper — Pay Per Result

Scrape **public** Indeed job listings by keyword and location. Clean, stable dataset schema. Pay-per-event pricing.

**Store search keywords:** Indeed scraper · Indeed job scraper · Indeed jobs · jobs data · job listings scraper

***

### What you get

For each job:

| Field | Description |
|-------|-------------|
| `id` | Indeed job key |
| `title` | Job title |
| `company` | Company name |
| `companyRating` | Company rating when shown |
| `location` | Location string |
| `salary` | `{ min, max, period, currency, raw }` |
| `jobType` | e.g. Full-time |
| `postedAt` | ISO date when parseable, else relative text |
| `description` | Plain text |
| `descriptionHtml` | HTML description (when available) |
| `url` | Public job URL |
| `isRemote` | Remote heuristic |
| `scrapedAt` | ISO timestamp |
| `searchQuery` | Query that found this job |

### Example input

```json
{
  "queries": ["software engineer", "data analyst"],
  "location": "Remote",
  "country": "www.indeed.com",
  "maxItemsPerQuery": 50,
  "datePosted": "7",
  "parseFullDescription": true,
  "dedupeAcrossQueries": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

### Example output item

```json
{
  "id": "abc123def456",
  "title": "Software Engineer",
  "company": "Example Corp",
  "companyRating": 3.8,
  "location": "Remote",
  "salary": {
    "min": 120000,
    "max": 150000,
    "period": "year",
    "currency": "USD",
    "raw": "$120,000 - $150,000 a year"
  },
  "jobType": "Full-time",
  "postedAt": "2026-07-28T12:00:00.000Z",
  "description": "We are looking for a software engineer...",
  "descriptionHtml": "<div>We are looking for a software engineer...</div>",
  "url": "https://www.indeed.com/viewjob?jk=abc123def456",
  "isRemote": true,
  "scrapedAt": "2026-08-02T06:00:00.000Z",
  "searchQuery": "software engineer"
}
```

### Pricing (PPE)

| Event | Price | When charged |
|-------|-------|--------------|
| `apify-actor-start` | $0.00005 | Once per run (auto; first 5s compute waived) |
| `apify-default-dataset-item` (**Job listing**) | **$0.005** (~**$5 / 1,000 jobs**) | Each job written to the dataset |

Browser + residential proxies are required for Indeed reliability — that cost is baked into the per-job price so the Actor stays profitable without passing opaque platform usage on top.

Local PPE test:

```bash
ACTOR_TEST_PAY_PER_EVENT=true ACTOR_USE_CHARGING_LOG_DATASET=true npm run dry-run
```

### Reliability

- **Real Chromium browser** (Playwright) — plain HTTP clients get 403’d by Indeed
- Session pool + up to 6 retries; blocked sessions are retired
- Block / captcha heuristics → retry with a fresh proxy session
- Dedupe by Indeed `jobkey` (optional across queries)
- Mosaic JSON parse first; DOM selectors as fallback
- Default **residential proxies** + low concurrency (1–2)
- Run **fails** if zero jobs are returned (so you are not left with a silent empty success)

We do **not** promise 100% success — Indeed rate-limits and challenges aggressive traffic. If a run fails, lower concurrency to 1 and retry.

### Limitations (honest)

- **Public pages only.** No login, no Indeed employer/applicant private data.
- **Residential proxies required** for reliable results. Datacenter IPs are almost always blocked.
- Cloudflare / captcha interstitials can still interrupt runs; the actor retries and fails those requests rather than bypassing challenges with ToS-evasive tooling.
- Browser runs cost more compute than HTTP scrapers — price reflects delivered jobs (PPE), not compute.
- Layout changes on Indeed can break parsers — report issues; we prioritize selector stability.
- Full descriptions require one extra page per job (`parseFullDescription: true`).
- Results reflect what Indeed shows publicly for the given domain/country at scrape time.

### How to run

#### On Apify

1. Open this Actor in Console or Store
2. Paste queries + location
3. Keep residential proxy on
4. Start → download dataset (JSON / CSV / Excel)

#### Local

```bash
## from monorepo root
npm install
cd actors/indeed-jobs
## edit storage/key_value_stores/default/INPUT.json
npm run dry-run
```

#### Publish

```bash
cd actors/indeed-jobs
npm run sync-shared
npx apify login
npx apify push
```

Then set PPE events in Console and publish to Store.

### Related actors (catalog)

Same publisher profile (cross-discovery): LinkedIn Jobs, Facebook Marketplace, G2 Reviews, Trustpilot Reviews, Google Trends, company lead-gen wedge — shipping in wave 1.

# Actor input Schema

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

Job keywords to search on Indeed (e.g. "software engineer", "nurse").

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

City, state, zip, or "Remote". Leave empty for nationwide (US default domain).

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

Hostname of the Indeed site to scrape (public search pages only).

## `maxItemsPerQuery` (type: `integer`):

Maximum number of job listings to return for each search query.

## `datePosted` (type: `string`):

Indeed fromage filter: last 24 hours, 3 days, 7 days, or 14 days.

## `parseFullDescription` (type: `boolean`):

If true, open each job detail page for the full description (slower, more reliable text). If false, use the snippet from search results only.

## `dedupeAcrossQueries` (type: `boolean`):

Skip jobs already returned for a previous query in this run (by Indeed job key).

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

Parallel browser tabs. Keep at 1–2 with residential proxies for Indeed stability.

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

Residential proxies are strongly recommended — Indeed often blocks datacenter IPs.

## Actor input object example

```json
{
  "queries": [
    "software engineer"
  ],
  "location": "Remote",
  "country": "www.indeed.com",
  "maxItemsPerQuery": 50,
  "datePosted": "",
  "parseFullDescription": true,
  "dedupeAcrossQueries": true,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `jobs` (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 = {
    "queries": [
        "software engineer"
    ],
    "location": "Remote",
    "maxItemsPerQuery": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("smorgi_apps/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": ["software engineer"],
    "location": "Remote",
    "maxItemsPerQuery": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("smorgi_apps/indeed-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "software engineer"
  ],
  "location": "Remote",
  "maxItemsPerQuery": 50
}' |
apify call smorgi_apps/indeed-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=smorgi_apps/indeed-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/VD3Vn6WrUjnYQylvQ/builds/cDIYy0g5nUl6jE33S/openapi.json
