# Indeed Jobs Scraper - Most Comprehensive (`kaix/indeed-scraper`) Actor

🔥 ~$0.05/1K jobs 🔥 Extract accurate, structured job data from Indeed. Get ALL page results, not just the first page. 60+ fields per job with pre-parsed salary, verified company profiles, GPS coordinates, and hiring signals. 54 countries. Fast, low cost

- **URL**: https://apify.com/kaix/indeed-scraper.md
- **Developed by:** [Kai](https://apify.com/kaix) (community)
- **Categories:** Automation, Jobs
- **Features:** Limited permissions
- **Stats:** 8,825 total users, 1,423 monthly users, 100.0% runs succeeded, 39 bookmarks
- **User rating**: 4.34 out of 5 stars

## Pricing

from $0.04 / 1,000 jobs

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 - Most Comprehensive

Scrape Indeed job listings from 62 countries, with up to ~190 fields per job:
full descriptions, parsed salaries, skills and certifications as structured
tags, complete company profiles, and apply links. Rich mode adds hiring
signals that other Indeed scrapers do not collect: reposts, employer
responsiveness, hires needed, required and preferred skills, and sponsored
placements.

Search Indeed by keyword and location, or look up known jobs by job key.
Starting at $0.04 per 1,000 jobs.

### Why this scraper?

| | This scraper | Other Indeed scrapers |
|---|---|---|
| Price per 1,000 jobs | $0.04 | $0.07-6 |
| Hiring signals: employer responsiveness, hires needed, required or preferred requirements, resume type (`rich`) | Yes | Only a few return any of them |
| Skill and attribute codes as key and label pairs | Yes | A few, without the hiring signals |
| Company profile: CEO, revenue, size, industry, and rating | Yes | Most |
| Working hours as minimum and maximum hours (`rich`) | Yes | None |
| Employer branding reasons (`rich`) | Yes | None |
| Indeed search expressions: `title:`, `company:`, and exclusions | Documented and tested | Not documented |
| Sponsored placements, with every position where Indeed showed each job (`rich`) | Yes | A few return a sponsored flag |
| The sponsoring employer's ID, also when a sponsored job appears as an organic result | Yes | None |
| Date, job type, and remote filters together (`rich`) | Yes | Some |
| Direct lookup | By job key, for active and expired jobs | A few, by job URL |

### Use cases

#### Recruiting and staffing leads

Find companies that hire now, with their size, revenue, website, and hiring
needs.

```json
{
  "keyword": "title:(\"registered nurse\")",
  "location": "New York, NY",
  "country": "US",
  "sort": "date",
  "fromDays": "3",
  "maxItems": 100,
  "searchMode": "rich"
}
```

Use `company.name`, `company.size`, `company.revenue`, `company.urls.website`,
`company.socialLinks`, `signals.numHires`, and `apply.url`.

#### Job market research

Compare salaries, skills, benefits, and requirements by role and region.

```json
{
  "keyword": "title:(\"data analyst\")",
  "location": "New York, NY",
  "country": "US",
  "maxItems": 500
}
```

Use `salary.min`, `salary.max`, `salary.period`, `classification.skills`,
`benefits`, `requirements.educationLevel`, and
`requirements.experienceLevel`.

#### Hiring and labor market analytics

Track who hires, how fast they respond, which roles they repost, and how many
people they need. Run the same input on an Apify schedule, and compare the
results over time.

```json
{
  "keyword": "title:(\"software engineer\") -intern",
  "location": "Seattle, WA",
  "country": "US",
  "sort": "date",
  "fromDays": "7",
  "jobType": "fulltime",
  "maxItems": 100,
  "searchMode": "rich"
}
```

Use `signals.isRepost`, `signals.isLatestPost`, `signals.numHires`,
`signals.employerResponsive`, `signals.hiringInsights`, and `dates.onIndeed`.
Rich results include sponsored jobs. To count only organic jobs, see
[How rich mode works](#how-rich-mode-works).

#### Recruitment advertising intelligence

See which employers pay to promote jobs, for which searches, at which result
positions, and how often.

```json
{
  "keyword": "nurse",
  "location": "New York, NY",
  "country": "US",
  "maxItems": 100,
  "searchMode": "rich"
}
```

Keep jobs where `signals.isSponsored` is `true`. Use
`signals.sponsoredEmployerKey`, `meta.scrapingInfo.page`,
`meta.scrapingInfo.index`, and `company.brandingReasons`. The
[placements record](#placements-record) lists every card that Indeed showed,
also repeated placements of the same job.

#### Job boards and aggregators

Publish fresh listings with full descriptions, parsed salaries, addresses, and
coordinates.

```json
{
  "keyword": "software engineer",
  "location": "United States",
  "country": "US",
  "sort": "date",
  "fromDays": "1",
  "maxItems": 0
}
```

Use `title.text`, `description.html`, `salary.text`, `location`, `urls.apply`,
and `dates.onIndeed`.

#### Job monitoring

Check whether known jobs are still open, with a
[lookup by job key](#look-up-known-jobs). Use `signals.isExpired`.

### Choose how to find jobs

| Starting point | Input | Use it for |
|---|---|---|
| A job title, skill, or company, and a place | `keyword` and `location` | Find jobs in an area |
| Exact titles or companies | `keyword` with `title:`, `company:`, `or`, and `-` | Match only the jobs you mean |
| Known Indeed jobs | `jobKeys` | Get full data for active and expired jobs |

If you provide `jobKeys`, the Actor looks up those jobs. It then ignores the
search fields, the filters, and `maxItems`.

### Choose a data depth

| Mode | Fields | Results per search | Best for |
|---|---:|---|---|
| `basic` (default) | ~165 | Up to 1,000 or more | Large searches, fastest |
| `detailed` | ~170 | Up to 1,000 or more | Hiring insights at full search size |
| `rich` | ~190 | Up to about 600, about half of them sponsored | The most data per job, and sponsored placements |

Rich mode returns jobs in the order that Indeed shows them, with the sponsored
placements. See
[How rich mode works](#how-rich-mode-works).

**Every job includes (basic):**

- Job: title, normalized title, full description as text and HTML, snippet, reference number
- Links: Indeed job URL, employer job URL, apply URL
- Classification: job types, occupations, primary occupation, skills, languages, and all Indeed attributes as key and label pairs
- Salary: salary text, parsed minimum, maximum, or exact amount, currency, period, and extras such as bonuses
- Benefits: benefit labels, such as health insurance, 401(k), and paid time off
- Work arrangement: remote flag, shifts, schedules, travel
- Location: full address, city, state, county, postal code, country, latitude, and longitude
- Company: name, industry, size, revenue, descriptions, website, logos, ratings and review counts, CEO, social links, and response rate
- Apply: Easy Apply flag, apply scopes
- Dates: posted date, date on Indeed, expiry date, age text
- Signals: expired, urgent hire, and high-volume hiring flags, and the sponsoring employer's ID
- Requirements: experience level, education level, certifications, and other labeled requirements
- Metadata: job source, language, locale, search keyword, search location, result page and position

**Detailed adds, when Indeed supplies them:**

- Hiring insights: candidates needed and hiring-event flag
- Employer-provided attributes and occupations
- Required documents, remote work type, and job photos

**Rich adds everything in detailed, plus:**

- Hiring signals: repost and newest-post flags, employer responsiveness, days since the employer last reviewed applications, hires needed, new-job flag, and hiring tags such as fair-chance hiring
- Requirements: skills and qualifications, each marked required or preferred, and physical requirements
- Working hours: minimum and maximum hours for each period
- Apply: whether Indeed Apply needs a resume
- Salary: Indeed's own salary parse and salary text
- Company: employer branding reasons, featured-employer flag, and parent company
- Locations: number of locations for the same posting
- Search placement: sponsored flag, and a [placements record](#placements-record) with every card that Indeed showed
- More benefits, job types, shifts, and schedules

### Search for jobs

Start with a keyword and a location:

```json
{
  "keyword": "registered nurse",
  "location": "New York, NY"
}
```

The Actor searches the US site and saves up to 20 jobs. Set `maxItems` to set
an upper limit. Indeed can return fewer jobs. Use `0` to remove the Actor
limit. Set `searchMode` to `detailed` or `rich` for more fields. See
[Choose a data depth](#choose-a-data-depth).

#### Match titles and companies

Plain keywords use broad matching and can include related roles. Use Indeed
search expressions when title or company matching is important.

| Expression | Meaning |
|---|---|
| `"data engineer"` | Exact phrase in the posting. |
| `title:(data engineer)` | Both words in the title. |
| `title:("data engineer")` | Exact phrase in the title. |
| `title:("data engineer" or "data scientist")` | Either phrase in the title. |
| `nurse -travel` | Include `nurse` and exclude `travel`. |
| `company:Google` | Jobs for the specified company expression. |

Indeed supports `and`, `or`, `not`, exclusions, quotes, and parentheses. You
can combine them:

```json
{
  "keyword": "title:(\"data engineer\" or \"data scientist\") -intern",
  "location": "United States"
}
```

#### Filter by date, job type, and remote work

```json
{
  "keyword": "software engineer",
  "location": "Seattle, WA",
  "fromDays": "7",
  "jobType": "fulltime",
  "remote": "hybrid",
  "searchMode": "rich"
}
```

`fromDays` keeps the jobs that reached Indeed in the last 1, 3, 7, or 14 days.
It filters on `dates.onIndeed`.

In basic and detailed mode, `fromDays` replaces `jobType` and `remote`. Rich
mode applies all three filters.

A `hybrid` search can also return fully remote jobs, because Indeed can give
one job both labels. Indeed's matching is broad, so a job can also be missing
the requested job type or remote label. When the exact value matters, check
`classification.jobType`, `workArrangement.isRemote`, and
`workArrangement.locationType`.

#### Sort by date

Set `sort` to `date` to get the newest jobs first in basic and detailed mode.
In rich mode, the results keep Indeed's card order, and sponsored jobs keep
their places.

#### Search within a radius

```json
{
  "keyword": "software engineer",
  "location": "10001",
  "radius": "25",
  "radiusUnit": "miles",
  "maxItems": 50
}
```

The default radius is 35 miles. Set `radiusUnit` to `km` for kilometers.

#### Search another country

```json
{
  "keyword": "Buchhalter",
  "location": "Berlin",
  "country": "DE",
  "radius": "50",
  "radiusUnit": "km"
}
```

`country` selects the Indeed site. The code for the United Kingdom is `UK`.
See the [input reference](#input-reference) for all codes.

### Look up known jobs

Use the job key (the `jk` value in an Indeed job URL), or the whole job URL:

```json
{
  "jobKeys": ["5e5dafc2a80c214d"],
  "country": "US"
}
```

- Lookups return full job data for active and expired jobs.
  `signals.isExpired` is `true` when Indeed has closed the listing.
- Use the `country` of the Indeed site that shows the job.
- A lookup ignores the search fields, the filters, and `maxItems`. It returns
  a repeated key once and skips unknown keys.
- `basic` returns the basic fields. `detailed` and `rich` add the detailed
  fields. A lookup cannot return the other rich fields. Use a rich search to
  get them.

### How rich mode works

Rich mode returns the jobs in the order that Indeed shows them in its search
results. `meta.scrapingInfo.page` and `meta.scrapingInfo.index` give the
position of each job.

**Sponsored placements.** Indeed selects them. They can fall outside the
keyword, the title expression, the location, and the filters. They can be more
than half of the results, and a search that matches no jobs can still return
them. They count toward `maxItems`. Only a rich search reports sponsored
placements: use `signals.isSponsored` from rich searches only.

**Sponsoring employer.** `signals.sponsoredEmployerKey` is Indeed's ID for the
employer that sponsors the job. It stays on the job in every search and in
lookups, also when the job appears as an organic result.

**Repeated jobs.** Indeed often shows the same job on several pages, for
example sponsored on page 1 and organic on page 8. The dataset keeps the job
once, at its first card, and `signals.isSponsored` describes that card. The
[placements record](#placements-record) lists every card.

**Organic jobs only.** Keep the jobs where `signals.isSponsored` is `false`.
This filter also removes the few jobs that Indeed showed first as sponsored and
later as organic. For the exact organic set, keep the jobs that have a
placements row with `sponsored` set to `false`.

**Result range.** Indeed limits how many search results it shows, and it
repeats jobs across them. A broad rich search therefore gives about 600 unique
jobs, and about half of them are sponsored.

**No rich results.** When a rich search finds no jobs, the Actor returns
basic-mode jobs for the same search and logs a warning. These jobs have no
rich fields, and the placements record has no rows.

### Input

A search uses `keyword`, `location`, or both. A lookup uses `jobKeys`.

<details>
<summary>Complete input example</summary>

This example uses every search field:

```json
{
  "keyword": "title:(\"registered nurse\") -travel",
  "location": "New York, NY",
  "country": "US",
  "maxItems": 100,
  "searchMode": "rich",
  "sort": "date",
  "fromDays": "3",
  "jobType": "fulltime",
  "remote": "",
  "radius": "25",
  "radiusUnit": "miles",
  "proxyConfig": { "useApifyProxy": true }
}
```

</details>

#### Input reference

| Parameter | Type | Default | Effect |
|---|---|---:|---|
| **keyword** | string | empty | Job title, skill, company, or search expression. See [Match titles and companies](#match-titles-and-companies). |
| **location** | string | empty | City, state, postal code, or other location text. |
| **country** | country code | `US` | Indeed country site. See the codes below. |
| **maxItems** | integer, 0 or more | `20` | Upper limit on saved jobs. Indeed can return fewer. `0` removes the Actor limit. |
| **searchMode** | `basic`, `detailed`, or `rich` | `basic` | Data depth. See [Choose a data depth](#choose-a-data-depth). |
| **sort** | `relevance` or `date` | `relevance` | Result order. Rich mode keeps Indeed's card order. |
| **fromDays** | `"1"`, `"3"`, `"7"`, or `"14"` | any time | Keeps jobs that reached Indeed in the last N days. In basic and detailed mode, it replaces `jobType` and `remote`. |
| **jobType** | `fulltime`, `parttime`, `contract`, `temporary`, or `internship` | any type | Employment type. |
| **remote** | `remote` or `hybrid` | any | Work arrangement. `hybrid` can also return fully remote jobs. |
| **radius** | string with a number | `"35"` | Search distance from `location`. |
| **radiusUnit** | `miles` or `km` | `miles` | Unit for `radius`. |
| **jobKeys** | string\[] | `[]` | Indeed job keys to look up. A lookup ignores the search fields, the filters, and `maxItems`. |
| **proxyConfig** | object | `{"useApifyProxy":true}` | Connection settings for the run. Keep the default. Without a proxy, most runs fail or return no jobs. |

Allowed country codes:

`US`, `UK`, `CA`, `AU`, `IN`, `DE`, `FR`, `JP`, `BR`, `MX`, `IT`, `ES`, `NL`, `BE`, `CH`, `AT`, `SG`, `HK`, `IE`, `NZ`, `AR`, `BH`, `CL`, `CN`, `CO`, `CZ`, `DK`, `FI`, `GR`, `HU`, `ID`, `IL`, `KW`, `LU`, `MY`, `MA`, `NO`, `OM`, `PE`, `PH`, `PL`, `PT`, `QA`, `RO`, `SA`, `ZA`, `KR`, `SE`, `TW`, `TR`, `UA`, `AE`, `VE`, `VN`, `CR`, `EC`, `EG`, `NG`, `PA`, `PK`, `TH`, `UY`.

### Output

Each Dataset item is one job. Every documented field is present in every job.
When Indeed does not supply a value, the field is `null`, `[]`, or `{}`. A rich
search also saves a [placements record](#placements-record).

#### Sample rich job

This redacted rich-mode job is from Visa in Bellevue, WA. Long arrays and maps
keep a few items. Square brackets mark values removed from the documentation.
It is not a saved Dataset item.

<details>
<summary>Open the job JSON</summary>

```json
{
  "id": "29a452d465e71ecc",
  "refNum": "JOB_POSTING-3-14946",
  "title": {
    "text": "Software Engineer - Sr. Consultant level",
    "normalized": "software consultant"
  },
  "urls": {
    "indeed": "https://www.indeed.com/viewjob?jk=29a452d465e71ecc",
    "external": "https://visa.wd5.myworkdayjobs.com/Visa/job/US---Bellevue-WA/Software-Engineer---Sr-Consultant-level_REF085157W",
    "apply": "https://visa.wd5.myworkdayjobs.com/Visa/job/US---Bellevue-WA/Software-Engineer---Sr-Consultant-level_REF085157W",
    "clickTracking": "[tracking URL removed]"
  },
  "description": {
    "text": "[job description text removed]",
    "html": "[job description HTML removed]"
  },
  "snippet": "[snippet text removed]",
  "classification": {
    "jobType": [
      "Full-time"
    ],
    "occupations": {
      "5NN53": "Software Development Occupations",
      "EHPW9": "Technology Occupations",
      "HJSX6": "Software Development & Architecture Occupations"
    },
    "primaryOccupation": {
      "key": "5NN53",
      "label": "Software Development Occupations"
    },
    "occupationMostLikelySuid": null,
    "skills": [
      {
        "key": "2EWTB",
        "label": "Roadmap creation (System development task)"
      },
      {
        "key": "4R4AM",
        "label": "Software engineering"
      },
      {
        "key": "5GR9R",
        "label": "UI development"
      }
    ],
    "languages": [],
    "attributes": {
      "all": {
        "6ETQT": "Go",
        "EVPJU": "Java",
        "FADZP": "Microservices",
        "EY33Q": "Health insurance",
        "FVKX2": "401(k)",
        "9PQEB": "5 years",
        "VBXYJ": "Bachelor's degree in computer science",
        "UB7SC": "Senior level",
        "Q5R8A": "Fair chance",
        "DN85V": "Office"
      },
      "employerProvided": [
        {
          "key": "CF3CP",
          "label": "Full-time"
        }
      ]
    },
    "employerProvidedOccupations": null
  },
  "workArrangement": {
    "isRemote": false,
    "locationType": null,
    "remoteWorkType": null,
    "remoteAttributes": [],
    "shift": [],
    "schedule": [],
    "workSchedule": null,
    "workingHours": null,
    "workingSystem": [],
    "travel": [
      "Travel"
    ]
  },
  "salary": {
    "text": "$152,200 - $243,700 a year",
    "min": 152200,
    "max": 243700,
    "exact": null,
    "minCents": "15220000",
    "maxCents": "24370000",
    "exactCents": null,
    "currency": "USD",
    "period": "yearly",
    "source": "EXTRACTION",
    "estimated": false,
    "detailed": null,
    "extracted": {
      "min": 152200,
      "max": 243700,
      "type": "YEARLY"
    },
    "snippet": {
      "currency": "USD",
      "source": "EXTRACTION",
      "text": "$152,200 - $243,700 a year"
    },
    "extras": [
      "Bonus opportunities"
    ]
  },
  "benefits": [
    "Wellness program",
    "Health savings account",
    "Health insurance",
    "Dental insurance"
  ],
  "socialInsurance": {
    "EY33Q": "Health insurance"
  },
  "apply": {
    "url": "https://visa.wd5.myworkdayjobs.com/Visa/job/US---Bellevue-WA/Software-Engineer---Sr-Consultant-level_REF085157W",
    "isEasyApply": true,
    "indeedApplyKey": "[apply key removed]",
    "scopes": [
      "DESKTOP",
      "MOBILE"
    ],
    "resumeType": "required",
    "organicApplyStarts": 0
  },
  "location": {
    "formatted": "Bellevue, WA 98004",
    "formattedShort": "Bellevue, WA",
    "fullAddress": "929 108th Avenue NE, Bellevue, WA 98004",
    "city": "Bellevue",
    "state": "WA",
    "stateName": "Washington State",
    "admin2Code": "033",
    "admin2Name": "King County",
    "admin3Code": null,
    "admin3Name": null,
    "admin4Code": null,
    "admin4Name": null,
    "postalCode": "98004",
    "streetAddress": "929 108th Avenue NE",
    "latitude": 47.618294,
    "longitude": -122.19712,
    "country": "US",
    "countryName": "United States"
  },
  "locationCount": 1,
  "company": {
    "name": "Visa Technology and Operations LLC",
    "key": "ba979d6fb0c7a936",
    "sourceName": "Visa Technology and Operations LLC",
    "tier": "FREE",
    "industry": null,
    "sectors": [],
    "size": "10,000+",
    "revenue": "more than $10B (USD)",
    "briefDescription": "Our Purpose is to... Uplift everyone, everywhere by being the best way to pay and be paid.",
    "fullDescription": "[company description removed]",
    "brandColor": "#ffffff",
    "customContents": [
      "Visa: a purpose-driven industry leader!"
    ],
    "subsidiaryOptOut": false,
    "featuredEmployer": false,
    "brandingReasons": [
      "PAID_BRANDING"
    ],
    "urls": {
      "website": "http://www.visa.com",
      "indeed": "https://www.indeed.com/cmp/Visa"
    },
    "logos": {
      "square": "[logo URL removed]",
      "squareSizes": {
        "url64": "[logo URL removed]",
        "url96": "[logo URL removed]",
        "url128": "[logo URL removed]",
        "url256": "[logo URL removed]"
      },
      "rectangular": null,
      "header": "[logo URL removed]",
      "header1960x400": "[logo URL removed]",
      "headerAltText": null
    },
    "ratings": {
      "overall": 3.9,
      "count": 1204,
      "reviewCount": 1204
    },
    "ceo": {
      "name": "Ryan McInerney",
      "photoUrl": "[photo URL removed]"
    },
    "stockSymbol": null,
    "addresses": [],
    "phone": null,
    "socialLinks": {
      "facebook": "https://www.facebook.com/Visa",
      "twitter": "https://twitter.com/Visa",
      "instagram": "https://www.instagram.com/visa"
    },
    "responsiveness": {
      "averageResponseTimeDays": 4,
      "responseRate": 0.74,
      "isActivelyReviewed": false,
      "lastActivityTimeInDays": null
    },
    "parentEmployer": null
  },
  "photos": null,
  "dates": {
    "posted": "2026-09-23",
    "onIndeed": "2026-09-23T22:38:42.917Z",
    "validThrough": null,
    "age": "4 days ago",
    "postedToday": false
  },
  "signals": {
    "isExpired": false,
    "sponsoredEmployerKey": null,
    "isSponsored": false,
    "isBrandedJob": null,
    "isUrgentHire": false,
    "isHighVolumeHiring": false,
    "isRepost": true,
    "isLatestPost": true,
    "isPlacement": null,
    "isNew": true,
    "employerResponsive": true,
    "applyCount": null,
    "numHires": null,
    "matchScores": [],
    "hiringTags": [
      "Fair chance"
    ],
    "hiringInsights": {
      "numOfCandidates": null,
      "employerLastReviewed": "4",
      "recurringHireText": null,
      "isHiringEvent": false
    },
    "jobPageExists": true
  },
  "requirements": {
    "certifications": [],
    "qualifications": [],
    "experienceLevel": "5 years",
    "educationLevel": "Bachelor's degree in engineering",
    "attributes": null,
    "physicalRequirements": [],
    "eligibility": [],
    "ageRequirement": [],
    "experienceDuration": []
  },
  "requiredDocuments": null,
  "meta": {
    "source": "Visa Inc.",
    "feed": {
      "isDradis": false,
      "sourceType": "EMPLOYER"
    },
    "language": "en",
    "locale": "en_US",
    "scrapedAt": "2026-09-27T21:52:47.544Z",
    "search": {
      "keyword": "title:(\"software engineer\") -intern",
      "location": "Seattle, WA"
    },
    "scrapingInfo": {
      "page": 1,
      "index": 10
    },
    "workSetting": [
      "Office"
    ]
  }
}
```

</details>

#### Field reference

| Field | Type and contents |
|---|---|
| `id` | string. Indeed job key. |
| `refNum` | string or `null`. The job's reference number. |
| `title` | object. `text` is a string; `normalized` is a string or `null`. |
| `urls` | object. `indeed` is a string. `external`, `apply`, and `clickTracking` are strings or `null`. |
| `description` | object. `text` and `html` are strings or `null`. |
| `snippet` | string or `null`. |
| `classification` | object. Contains the classification fields in the rows below. |
| `classification.jobType` | string\[]. |
| `classification.occupations` | object with dynamic string keys and string labels. |
| `classification.primaryOccupation` | `{key: string, label: string}` or `null`. |
| `classification.occupationMostLikelySuid` | string or `null`. |
| `classification.skills`, `classification.languages` | Array of `{key: string, label: string}` objects. |
| `classification.attributes` | object. `all` is a dynamic string-to-string map. `employerProvided` is an array of `{key: string, label: string}` or `null`. |
| `classification.employerProvidedOccupations` | Array of `{key: string, label: string}` objects or `null`. |
| `workArrangement` | object. `isRemote` is boolean. `locationType`, `remoteWorkType`, and `workSchedule` are strings or `null`. `shift`, `schedule`, and `travel` are string arrays. `remoteAttributes` and `workingSystem` are arrays of `{key: string, label: string}`. |
| `workArrangement.workingHours` | object or `null`. `displayType`, `period`, and `source` are strings; `minimumHours` and `maximumHours` are numbers. |
| `salary` | object. `text`, `minCents`, `maxCents`, `exactCents`, `currency`, `period`, `source`, and `detailed` are strings or `null`. `min`, `max`, and `exact` are numbers or `null`. `estimated` is boolean. `extras` is string\[]. |
| `salary.extracted` | `{min: number, max: number, type: string}` or `null`. |
| `salary.snippet` | `{currency: string, source: string, text: string}` or `null`. |
| `benefits` | string\[]. |
| `socialInsurance` | object with dynamic string keys and string labels. |
| `apply` | object. `url`, `indeedApplyKey`, and `resumeType` are strings or `null`; `isEasyApply` is boolean; `scopes` is string\[]; `organicApplyStarts` is a number or `null`. |
| `location` | object. `formatted`, `formattedShort`, `fullAddress`, `city`, `state`, `stateName`, `admin2Code`, `admin2Name`, `admin3Code`, `admin3Name`, `admin4Code`, `admin4Name`, `postalCode`, `streetAddress`, `country`, and `countryName` are strings or `null`. `latitude` and `longitude` are numbers or `null`. |
| `locationCount` | number or `null`. |
| `company` | object. Contains the company fields in the rows below. |
| `company` text and list fields | `name`, `key`, `sourceName`, `tier`, `industry`, `size`, `revenue`, `briefDescription`, `fullDescription`, `brandColor`, `stockSymbol`, and `phone` are strings or `null`. `sectors`, `customContents`, and `addresses` are string arrays. `brandingReasons` is string\[] or `null`. |
| `company` flags | `subsidiaryOptOut` and `featuredEmployer` are booleans or `null`. |
| `company.urls` | object. `website` and `indeed` are strings or `null`. |
| `company.logos` | object. `square`, `rectangular`, `header`, `header1960x400`, and `headerAltText` are strings or `null`. `squareSizes` is `{url64: string, url96: string, url128: string, url256: string}` or `null`. |
| `company.ratings` | object. `overall`, `count`, and `reviewCount` are numbers or `null`. `count` is the number of star ratings; `reviewCount` is the number of written reviews. They often differ. |
| `company.ceo` | `{name: string or null, photoUrl: string or null}` or `null`. |
| `company.socialLinks` | object. `facebook`, `twitter`, and `instagram` are strings or `null`. |
| `company.responsiveness` | object or `null`. `averageResponseTimeDays`, `responseRate`, and `lastActivityTimeInDays` are numbers or `null`; `isActivelyReviewed` is boolean or `null`. |
| `company.parentEmployer` | object or `null`. `name` and `key` are strings; `indeedUrl` is a string or `null`; `subsidiaryOptOut` is boolean or `null`. |
| `photos` | string\[] or `null`. Job-level image URLs. |
| `dates` | object. `posted`, `onIndeed`, `validThrough`, and `age` are strings or `null`; `postedToday` is boolean. |
| `signals` | object. `isExpired`, `isUrgentHire`, and `isHighVolumeHiring` are booleans. `sponsoredEmployerKey` is a string or `null`. `isSponsored`, `isBrandedJob`, `isRepost`, `isLatestPost`, `isPlacement`, `isNew`, `employerResponsive`, and `jobPageExists` are booleans or `null`. `applyCount` and `numHires` are numbers or `null`. `hiringTags` is string\[]. |
| `signals.matchScores` | Array of `{key: string, value: string}` objects. |
| `signals.hiringInsights` | object or `null`. `numOfCandidates` is a number or `null`; `employerLastReviewed` and `recurringHireText` are strings or `null`; `isHiringEvent` is boolean. |
| `requirements` | object. `certifications`, `qualifications`, `physicalRequirements`, `eligibility`, `ageRequirement`, and `experienceDuration` are string arrays. `experienceLevel` and `educationLevel` are strings or `null`. |
| `requirements.attributes` | Array of `{key: string, label: string, provenance: string, requirementStrength: string}` objects or `null`. |
| `requiredDocuments` | Array of `{key: string, label: string}` objects or `null`. |
| `meta` | object. `source` is a string or `null`; `language`, `locale`, and `scrapedAt` are strings; `workSetting` is string\[]. |
| `meta.feed` | `{isDradis: boolean, sourceType: string or null}`. |
| `meta.search` | object. `keyword` and `location` are strings or `null`. |
| `meta.scrapingInfo` | `{page: number, index: number}`. |

#### Placements record

A rich search saves the record `PLACEMENTS` in the run's default key-value
store. The run's Output tab links to it. The record lists every card that
Indeed showed for the saved jobs, in page order. A job has one row for each
card, so a job that Indeed showed three times has three rows.

```json
{
  "placements": [
    { "jobKey": "5e5dafc2a80c214d", "page": 1, "index": 0, "sponsored": true },
    { "jobKey": "5e5dafc2a80c214d", "page": 8, "index": 3, "sponsored": false }
  ]
}
```

| Field | Type and contents |
|---|---|
| `jobKey` | string. The `id` of a job in the dataset. |
| `page` | number. 1-based search result page. |
| `index` | number. 0-based position on the page, including sponsored placements. |
| `sponsored` | boolean. Whether this card was a paid placement. |

- The first row of a job matches its `meta.scrapingInfo` and `signals.isSponsored`.
- The rows end at the card that reached `maxItems`. A job that is not in the
  dataset has no rows.
- The record covers the search results that the run collected. A run that
  stops early keeps the rows of the jobs that it saved.
- Basic mode, detailed mode, and lookups do not save the record.

### Search and field limits

#### How many jobs can I collect?

`maxItems` is an upper limit, not a required result count. Indeed can return
fewer jobs. Set `maxItems` to `0` to remove the Actor limit. The run then ends
when Indeed has no more results. A basic or detailed search returns up to 1,000
or more jobs. A rich search returns up to about 600, about half of them
sponsored.

When you set a maximum cost per run, the run saves the jobs that this cost
pays for and then ends as succeeded. A lookup then checks only the first job
keys that the cost pays for. The run's status message tells you when this
happens.

#### Why are some fields empty?

Indeed does not show all fields on every job. Some rich jobs do not have every
rich field. In detailed mode, a job can have only the basic fields when extra
detail is unavailable.

#### Can a job disappear after I collect it?

Yes. Indeed can change or remove listings at any time. Use a
[lookup](#look-up-known-jobs) to check whether a job is still open.

# Actor input Schema

## `keyword` (type: `string`):

What job are you looking for? Enter a job title, skill, or company name. Supports the advanced search syntax above: combine <code>title:("...")</code>, <code>or</code>, <code>-exclusions</code>, and <code>company:</code> freely. Plain keywords use Indeed's broad matching, which includes related roles.

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

Where? Enter a city, state, or ZIP code.

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

Which Indeed country site to search. Supports 62 countries.

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

Maximum number of job listings to scrape. Set to 0 for no limit (all results).

## `radius` (type: `string`):

How far from the location to search.

## `radiusUnit` (type: `string`):

Unit for search radius.

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

How to order the results. In rich mode, sponsored jobs keep their places on Indeed's page, so a date order is not strict.

## `fromDays` (type: `string`):

Only return recently posted jobs. In basic and detailed mode, this filter replaces Job Type and Remote. Rich mode applies all three.

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

Filter by employment type. In rich mode, sponsored jobs can fall outside this filter.

## `remote` (type: `string`):

Filter for remote or hybrid positions. In rich mode, sponsored jobs can fall outside this filter.

## `jobKeys` (type: `array`):

Look up specific jobs by their Indeed job key (the ID from the job URL, e.g. "5e5dafc2a80c214d") or by the job URL. When provided, keyword/location search is skipped. Useful for checking if jobs are still active (expired field).

## `searchMode` (type: `string`):

Basic: fastest, up to 1000+ results with essential job data. Detailed: up to 1000+ results with additional hiring insights, benefits, and requirements per job (slower). Rich: up to about 600 results with extra fields like salary details, apply count, and hiring responsiveness. Rich also returns sponsored placements, in Indeed's order. In a broad search, about half of the results are sponsored.

## `proxyConfig` (type: `object`):

Proxy configuration. Disabling the proxy is not recommended: Indeed blocks most unproxied requests.

## Actor input object example

```json
{
  "keyword": "title:(\"Software Engineer\" or \"Software Developer\") -intern",
  "location": "San Francisco, CA",
  "country": "US",
  "maxItems": 20,
  "radius": "35",
  "radiusUnit": "miles",
  "sort": "relevance",
  "fromDays": "",
  "jobType": "",
  "remote": "",
  "jobKeys": [],
  "searchMode": "basic",
  "proxyConfig": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `placements` (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 = {
    "keyword": "title:(\"Software Engineer\" or \"Software Developer\") -intern",
    "location": "San Francisco, CA",
    "proxyConfig": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kaix/indeed-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 = {
    "keyword": "title:(\"Software Engineer\" or \"Software Developer\") -intern",
    "location": "San Francisco, CA",
    "proxyConfig": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("kaix/indeed-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 '{
  "keyword": "title:(\\"Software Engineer\\" or \\"Software Developer\\") -intern",
  "location": "San Francisco, CA",
  "proxyConfig": {
    "useApifyProxy": true
  }
}' |
apify call kaix/indeed-scraper --silent --output-dataset

```

## MCP server setup

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