# Indeed Scraper — Jobs, Salary Filters & AI (US+JP) (`akagifreeez/indeed-pro-scraper`) Actor

Indeed scraper for US, Japan (求人) and more: normalized salaries (USD & JPY 万円), date/job-type/remote filters, dedup, full descriptions, optional AI skill & seniority enrichment. Pay per result.

- **URL**: https://apify.com/akagifreeez/indeed-pro-scraper.md
- **Developed by:** [koki yonai](https://apify.com/akagifreeez) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 job scrapeds

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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Scraper — Jobs, Salary Filters & AI (US+JP)

A reliable **Indeed scraper** that extracts job listings as clean, structured data: title, company,
location, **normalized salary** (USD, JPY 万円 formats and more), employment type, full description,
posting date and URL — with advanced filters, duplicate removal and optional AI enrichment.
No code needed: type a search query, click Start, export JSON / CSV / Excel. Works on Indeed US,
**Indeed Japan (求人)**, UK, Canada, Germany, Australia, India and other country domains.

Built for recruiters, job boards, HR-tech products and labor-market researchers who need
*consistent* Indeed data — not a scraper that silently returns half the results.

### What does this Indeed scraper do?

- **Collects job listings** from Indeed search results for any query + location, on any Indeed
  country domain (`www` = US, `jp` = Japan, `uk`, `ca`, `de`, `au`, `in`, `fr`, `nl` …).
- **Survives Indeed's anti-bot protection** with country-matched residential proxies, automatic
  retries and session rotation — so result counts stay predictable run after run.
- **Normalizes salaries** into structured `min / max / currency / period` — including Japanese
  formats like `年収450万円`, `月給25万円` and `時給1,200円`, and US ranges like `$80,000 - $110,000 a year`.
- **Classifies employment type** into a stable enum (`fulltime` / `parttime` / `contract` /
  `temporary` / `internship`) from any locale — `正社員` and `Full-time` both come out as
  `fulltime`, with the original text preserved in `employmentTypeRaw`.
- **Removes duplicates**: the same job re-appearing across pages, and sponsored/organic twins of
  the same posting (same title + company + location under a different id).
- **Filters at the source**: date posted, job type, **remote-only** (verified live on Indeed US and
  Japan), and minimum normalized salary.
- **Fetches the full job description** (optional): visits each job's page so you get the complete
  text instead of the truncated — often missing — snippet on the results page.
- **AI enrichment** (optional, bring your own Anthropic or OpenAI key): extracts skills, seniority
  level, job category, remote flag and a one-line summary per job.

### What job data can you extract from Indeed?

Every job comes out as one structured record:

| Field | Example |
|---|---|
| `id` | Indeed job key (stable, used for dedup) |
| `title` | `Senior React Developer` |
| `company` | `Acme Inc.` |
| `location` | `Remote in Chicago, IL` / `東京都 千代田区・フルリモート` |
| `salaryRaw` | `年収400万円~600万円` |
| `salaryNormalized` | `{ "min": 4000000, "max": 6000000, "currency": "JPY", "period": "year" }` |
| `employmentType` | `fulltime` / `parttime` / `contract` / `temporary` / `internship` |
| `employmentTypeRaw` | `正社員` / `Full-time` — the exact text Indeed showed |
| `description` | snippet, or the full text when detail scraping is on |
| `dateText` | posting-date text as shown by Indeed (e.g. `3 days ago`) |
| `url` | direct link to the job posting |
| `ai` *(optional)* | `{ "skills": [...], "seniority": "...", "category": "...", "remote": true, "summary": "..." }` |

Plus `source` (the Indeed domain scraped) and a `scrapedAt` ISO timestamp. A full record looks
like this:

```json
{
  "id": "a1b2c3d4e5f60708",
  "title": "Customer Service Representative",
  "company": "Acme Support Co.",
  "location": "Remote in Chicago, IL",
  "salaryRaw": "$18 - $22 an hour",
  "salaryNormalized": { "min": 18, "max": 22, "currency": "USD", "period": "hour" },
  "employmentType": "fulltime",
  "employmentTypeRaw": "Full-time",
  "description": "We are looking for a customer service representative to ...",
  "dateText": "3 days ago",
  "url": "https://www.indeed.com/viewjob?jk=a1b2c3d4e5f60708",
  "source": "www.indeed.com",
  "scrapedAt": "2026-06-10T12:34:56.000Z"
}
````

Export from the dataset as **JSON, CSV, Excel or XML**, or read it through the Apify API.

### How do I scrape Indeed jobs? (no code, 4 steps)

1. **Click "Try for free"** — an Apify account is free, no credit card required.
2. **Type your search**: query (e.g. `software engineer`), optional location, country domain.
3. **Click Start.** The default input is safe to run as-is and stops at your `maxItems` cap.
4. **Export your data** from the Storage tab (JSON / CSV / Excel), or pull it via API.

Optional switches: `scrapeJobDetails` for full descriptions, `filters` for date-posted / job type /
remote-only / minimum salary, `enableAiEnrichment` + your LLM API key for AI fields.

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

Pricing is **pay-per-result** — events are charged per job delivered, plus a fraction-of-a-cent
start fee per run:

| Event | Price | Per 1,000 jobs |
|---|---|---|
| Job scraped | $0.004 / job | $4 |
| Full job description — charged **instead of** "Job scraped" when full descriptions are on | $0.01 / job | $10 |
| AI enrichment — add-on, charged only for successfully enriched jobs | +$0.003 / job | +$3 |

Worked examples: 1,000 job cards = **$4**. 1,000 jobs with full descriptions = **$10** (billed as
the "Full job description" event instead of "Job scraped" — never both). Add AI enrichment on top:
+$3 per 1,000. Each run also bills a tiny actor-start fee ($0.00005 per GB of run memory — about
$0.0002 per run).

You can set a **maximum charge limit** on every run — the actor detects it mid-run and stops
cleanly instead of doing unpaid work.

**Proxies & plans (important):** Indeed aggressively 403s datacenter IPs, so this actor runs on
**residential proxies**. Your Apify run therefore needs **residential proxy access** — the **free
plan does not include it**, so a free run returns an empty dataset (repeated 403 / tunnel-connection
errors). A paid plan or the pay-as-you-go residential proxy add-on is required; residential traffic
is billed by Apify separately from this actor's per-result fees above. The actor's own fees are only
charged for jobs actually delivered.

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

Indeed's official APIs are gated: publisher/partner programs, employer products and ATS
integrations — there is no general-purpose public API for reading search results. If you've been
searching for an "Indeed API" for job data, a scraper like this one is the practical alternative —
this actor instantly becomes **your Indeed API**, callable from any language or no-code tool.

### How do I use the Indeed scraper API? (Python, CLI, no code)

#### How to scrape Indeed with Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("akagifreeez/indeed-pro-scraper").call(run_input={
    "searchQuery": "software engineer",
    "country": "www",
    "maxItems": 100,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["salaryNormalized"])
```

- **[API endpoints](https://apify.com/akagifreeez/indeed-pro-scraper/api)** — start runs and fetch
  results over HTTP from any language; webhooks fire when a run finishes.
- **[Python](https://apify.com/akagifreeez/indeed-pro-scraper/api/python)** / JavaScript clients,
  **[CLI](https://apify.com/akagifreeez/indeed-pro-scraper/api/cli)**.
- **[MCP](https://apify.com/akagifreeez/indeed-pro-scraper/api/mcp)** — connect the actor to Claude
  or other AI agents via the Model Context Protocol.
- **No code** — pipe results into Google Sheets, Make, Zapier, n8n and other Apify integrations.
- **Scheduling** — run it daily/hourly with Apify Schedules to build job-market time series.

### How do I scrape Indeed Japan (求人) listings?

This is where this actor stands apart: **Indeed Japan is a first-class citizen**, not an
afterthought.

```json
{
  "searchQuery": "エンジニア",
  "location": "東京都",
  "country": "jp",
  "maxItems": 100
}
```

- Japanese salary strings are **normalized to numbers**: `年収400万円〜600万円` →
  `min: 4000000, max: 6000000, currency: "JPY", period: "year"`; `月給25万円` and `時給1,200円`
  are recognized with their periods, so you can actually sort and filter by pay.
- Japanese employment types are **classified into the same enum** as English ones: `正社員` →
  `fulltime`, `アルバイト・パート` → `parttime`, `契約社員`/`業務委託` → `contract`, `派遣` →
  `temporary` — the original Japanese text stays in `employmentTypeRaw`.
- Requests use **Japan-based residential IPs and a Japanese locale** — the proxy country always
  matches the Indeed domain you target, which is what keeps block rates low on `jp.indeed.com`.
- The **remote-only filter works on Indeed Japan too** (returns フルリモート listings — verified live).

The same country-matching logic applies to every supported domain — scraping Indeed UK uses UK
IPs, Indeed Germany uses German IPs, and so on.

### Who uses this Indeed scraper?

**Recruiters and sourcing teams** track which companies are hiring for which roles, benchmark
offered salaries against the market (the normalized salary field makes this a sort, not a parsing
project), and spot newly posted roles daily with a scheduled run.

**Job boards and aggregators** refresh listings feeds with deduplicated, structured records —
employment type and salary come pre-classified, so ingestion is a column mapping, not a cleanup
pipeline.

**HR-tech and data products** build salary-benchmarking and labor-market features on top of the
structured output; the AI enrichment layer (skills, seniority, category) saves a round of LLM
post-processing.

**Researchers and analysts** collect labor-market time series (e.g. remote-work share by region,
posted-salary trends) by scheduling the same queries and diffing runs — run-to-run dedup keeps the
series clean.

### How is this different from basic Indeed scrapers?

| | Typical Indeed scrapers | **This actor** |
|---|---|---|
| Result counts | Inconsistent, silent gaps | Country-matched residential proxies + retries |
| Job description | All-or-nothing, or snippet-only | **Opt-in per run** — pay the detail rate only when you need full text |
| Filters | Keyword + location only | + salary min, date posted, job type, remote-only (US+JP verified) |
| Duplicates | Returned as-is | id dedup **+ sponsored/organic twin removal** (title+company+location) |
| Salary | Raw string only | **Normalized** min/max/currency/period — incl. 万円/月給/時給 |
| Employment type | Raw text mixed into other fields | **Classified enum** + raw text preserved |
| Japan support | Untested, salary unparsed | **First-class** (JP proxies, locale, JPY normalization) |
| AI analysis | ❌ | ✅ skills / seniority / category / summary (optional, your key) |
| Cost control | `maxItems` only; charge cap = abrupt stop | `maxItems` + detects your max charge limit mid-run and exits cleanly |

### Is it legal to scrape Indeed?

This actor reads **publicly available job listings only** — no login, no user accounts, no
paywalled or personal data. Scraping public data is generally lawful, but how you use the data is
your responsibility: review [Apify's guide on web-scraping legality](https://blog.apify.com/is-web-scraping-legal/)
and applicable local laws. This is not legal advice.

### FAQ

**Why do other Indeed scrapers return empty or partial results?**
Indeed's anti-bot system blocks datacenter IPs and mismatched geos aggressively (HTTP 403). This
actor uses residential IPs from the *same country* as the Indeed domain you target, rotates
sessions on blocks, and retries — that combination is what makes counts predictable.

**How many jobs can I scrape per search?**
Indeed serves at most ~1,000 results per query — an Indeed limit, not the scraper's. To go beyond
it, split the search into narrower runs (by city, date-posted window, or job type); dedup keeps
records unique within each run.

**Can I scrape Indeed without getting blocked?**
That's the core engineering of this actor: residential proxies geo-matched to the target domain,
browser fingerprinting left intact, automatic session rotation and retries on 403s. Blocks still
happen probabilistically — they're retried, not silently dropped.

**How do I export Indeed jobs to Excel or Google Sheets?**
Every run's dataset has one-click export to Excel/CSV/JSON in the Storage tab. For Google Sheets,
use Apify's Google Sheets integration to append each run's results automatically.

**How often should I schedule Indeed scraping?**
Daily is the sweet spot for tracking new postings (combine with `filters.datePosted: 1`); weekly
is enough for salary benchmarking. Use Apify Schedules — no code needed.

**Does it handle sponsored duplicates?**
Yes. Sponsored listings that re-appear as organic results (same title, company and location under
a different id) are collapsed into one record — while the same role legitimately posted in
different cities is kept.

**Can I cap my spend?**
Yes, twice over: `maxItems` stops the crawl after N unique jobs, and the platform's
**maximum charge limit** is respected mid-run — the actor stops charging and exits cleanly when
the cap is reached.

**Which fields are always returned, and which depend on the listing?**
Title, company, location, job id and URL come back for every job. Salary, employment type and
posting date are present only when Indeed itself shows them for that listing — many employers don't
publish a salary, and Indeed's current US results layout surfaces the posting date on the job's own
page rather than the results card. For the most complete salary, employment type and the full
description, turn on `scrapeJobDetails` (detail mode), which opens each job's page; AI enrichment can
also infer seniority and category when the structured fields are sparse.

**What does AI enrichment cost on the LLM side?**
You bring your own Anthropic or OpenAI API key, so LLM usage is billed to you directly at provider
rates; the actor only charges its enrichment fee for jobs that were successfully enriched.

**What happens when Indeed changes its layout?**
Selectors are actively maintained — reliability is the entire point of this actor. If you ever see
odd results, open an issue on the **Issues tab** and it will be fixed quickly; that response time
is public, so you can hold me to it.

**Which countries does it support?**
Any Indeed country domain: `www` (US), `jp` (Japan), `uk`, `ca`, `de`, `au`, `in`, `fr`, `nl` and
more — set the `country` input to the domain prefix.

# Actor input Schema

## `searchQuery` (type: `string`):

Job title or keywords (e.g. 'react developer').

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

City / region (leave empty for nationwide).

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

Indeed domain prefix: www (US), jp, uk, ca, de, au, in, fr, nl ...

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

Stop after this many unique jobs. Note: Indeed serves at most ~1,000 results per search query — to collect more, split the search by city, date window or job type.

## `filters` (type: `object`):

Optional result filters. datePosted = max posting age in days; jobType = fulltime | parttime | contract | temporary | internship; remoteOnly = remote jobs only (true/false); salaryMin = minimum normalized yearly salary.

## `scrapeJobDetails` (type: `boolean`):

Visit each job's page to capture the FULL description text (the search results page only shows a truncated, often-missing snippet). More reliable data, but adds one extra page request per job (higher cost).

## `enableAiEnrichment` (type: `boolean`):

Use an LLM to extract structured skills, seniority and a one-line summary from each posting. Requires your own API key below.

## `llmProvider` (type: `string`):

Which LLM to use for AI enrichment.

## `llmApiKey` (type: `string`):

Your API key for the chosen LLM provider. Used only when AI enrichment is enabled.

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

How many Indeed result pages to scrape in parallel.

## Actor input object example

```json
{
  "searchQuery": "software engineer",
  "country": "www",
  "maxItems": 100,
  "filters": {
    "datePosted": 7,
    "jobType": "",
    "remoteOnly": false,
    "salaryMin": 0
  },
  "scrapeJobDetails": false,
  "enableAiEnrichment": false,
  "llmProvider": "anthropic",
  "maxConcurrency": 5
}
```

# 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 = {
    "searchQuery": "software engineer",
    "location": "",
    "filters": {
        "datePosted": 7,
        "jobType": "",
        "remoteOnly": false,
        "salaryMin": 0
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("akagifreeez/indeed-pro-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 = {
    "searchQuery": "software engineer",
    "location": "",
    "filters": {
        "datePosted": 7,
        "jobType": "",
        "remoteOnly": False,
        "salaryMin": 0,
    },
}

# Run the Actor and wait for it to finish
run = client.actor("akagifreeez/indeed-pro-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 '{
  "searchQuery": "software engineer",
  "location": "",
  "filters": {
    "datePosted": 7,
    "jobType": "",
    "remoteOnly": false,
    "salaryMin": 0
  }
}' |
apify call akagifreeez/indeed-pro-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Indeed Scraper — Jobs, Salary Filters & AI (US+JP)",
        "description": "Indeed scraper for US, Japan (求人) and more: normalized salaries (USD & JPY 万円), date/job-type/remote filters, dedup, full descriptions, optional AI skill & seniority enrichment. Pay per result.",
        "version": "0.1",
        "x-build-id": "Qbn3qL8UBpOwEYE5D"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/akagifreeez~indeed-pro-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-akagifreeez-indeed-pro-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/akagifreeez~indeed-pro-scraper/runs": {
            "post": {
                "operationId": "runs-sync-akagifreeez-indeed-pro-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/akagifreeez~indeed-pro-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-akagifreeez-indeed-pro-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "searchQuery"
                ],
                "properties": {
                    "searchQuery": {
                        "title": "Search query",
                        "type": "string",
                        "description": "Job title or keywords (e.g. 'react developer')."
                    },
                    "location": {
                        "title": "Location",
                        "type": "string",
                        "description": "City / region (leave empty for nationwide)."
                    },
                    "country": {
                        "title": "Indeed country (domain prefix)",
                        "type": "string",
                        "description": "Indeed domain prefix: www (US), jp, uk, ca, de, au, in, fr, nl ...",
                        "default": "www"
                    },
                    "maxItems": {
                        "title": "Max jobs",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Stop after this many unique jobs. Note: Indeed serves at most ~1,000 results per search query — to collect more, split the search by city, date window or job type.",
                        "default": 100
                    },
                    "filters": {
                        "title": "Advanced filters",
                        "type": "object",
                        "description": "Optional result filters. datePosted = max posting age in days; jobType = fulltime | parttime | contract | temporary | internship; remoteOnly = remote jobs only (true/false); salaryMin = minimum normalized yearly salary."
                    },
                    "scrapeJobDetails": {
                        "title": "Scrape full job descriptions",
                        "type": "boolean",
                        "description": "Visit each job's page to capture the FULL description text (the search results page only shows a truncated, often-missing snippet). More reliable data, but adds one extra page request per job (higher cost).",
                        "default": false
                    },
                    "enableAiEnrichment": {
                        "title": "AI enrichment (skills / seniority / summary)",
                        "type": "boolean",
                        "description": "Use an LLM to extract structured skills, seniority and a one-line summary from each posting. Requires your own API key below.",
                        "default": false
                    },
                    "llmProvider": {
                        "title": "LLM provider",
                        "enum": [
                            "anthropic",
                            "openai"
                        ],
                        "type": "string",
                        "description": "Which LLM to use for AI enrichment.",
                        "default": "anthropic"
                    },
                    "llmApiKey": {
                        "title": "LLM API key (only if AI enrichment is on)",
                        "type": "string",
                        "description": "Your API key for the chosen LLM provider. Used only when AI enrichment is enabled."
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "How many Indeed result pages to scrape in parallel.",
                        "default": 5
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
