# Indeed Scraper (`jungle_synthesizer/indeed-scraper`) Actor

Scrape Indeed job listings by keyword and location. Extract job titles, companies, locations, salaries, job types, posting dates, and full descriptions. Perfect for market research, recruiting intelligence, and hiring trend analysis.

- **URL**: https://apify.com/jungle\_synthesizer/indeed-scraper.md
- **Developed by:** [BowTiedRaccoon](https://apify.com/jungle_synthesizer) (community)
- **Categories:** Jobs, Automation
- **Stats:** 2 total users, 0 monthly users, 95.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 Scraper

Scrape Indeed job listings by keyword and location. Returns structured job card data extracted directly from Indeed's internal page state — no secondary page loads required.

### What you get

Each record contains:

| Field | Description |
|---|---|
| `jobKey` | Indeed internal job ID |
| `jobUrl` | Direct link to the job posting |
| `title` | Job title |
| `company` | Hiring company name |
| `companyRating` | Company star rating on Indeed |
| `location` | City, state, or "Remote" |
| `salary` | Pay range if shown on the listing |
| `jobType` | Full-time, Part-time, Contract, etc. |
| `remoteWorkModel` | Remote / Hybrid / On-site label |
| `isSponsored` | Whether the listing is a sponsored ad |
| `postedAt` | Posting date or recency label |
| `query` | Search keyword used |
| `searchLocation` | Location filter used |
| `scrapedAt` | ISO timestamp of when the record was scraped |

> **Note:** Full job description text is not included. Indeed's listing page does not expose description content in its page state — only the job card metadata above is available without loading each individual job page.

### How it works

Indeed is Cloudflare-protected and renders its results in the browser, which is why most scrapers pointed at it come back empty. This one returns clean, fully typed job records on the first page load, without brittle selectors.

Pagination is handled automatically: the actor enqueues subsequent pages (`?start=10`, `?start=20`, ...) until `maxItems` is reached or results run out.

### Input

| Parameter | Type | Required | Description |
|---|---|---|---|
| `query` | string | Yes | Search keywords (e.g. `software engineer`, `registered nurse`) |
| `location` | string | Yes | Location (e.g. `New York, NY`, `Remote`, `London`) |
| `maxItems` | integer | Yes | Maximum number of job listings to return |

**Example:**

```json
{
  "query": "data analyst",
  "location": "San Francisco, CA",
  "maxItems": 50
}
```

### Limits and best practices

- Keep `maxItems` at 15 or below for test runs to stay within free-tier limits.
- Indeed shows approximately 15 listings per page; each page requires a fresh browser render.
- Sponsored listings are included and flagged with `isSponsored: true`.
- Results reflect Indeed's current live index — the same search run twice may return different ordering due to Indeed's personalization and freshness ranking.

### Use cases

- **Job market research** — track salary ranges and demand for specific roles across cities
- **Recruiting intelligence** — monitor competitor hiring activity
- **Hiring trend analysis** — compare job volume across industries and locations over time
- **Lead generation** — identify companies actively hiring in a given domain

# Actor input Schema

## `sp_intended_usage` (type: `string`):

What will this data feed? E.g. lead lists, KYB checks, price tracking.

## `sp_improvement_suggestions` (type: `string`):

Provide any feedback or suggestions for improvements.

## `sp_contact` (type: `string`):

We'll personally help with your use case. No spam.

## `resumeCursor` (type: `string`):

Leave empty for a fresh crawl. To CONTINUE a previous run where it stopped — without paying again for records you already received — paste the `resumeCursor` value from that run's Output (the run's OUTPUT key). Resume promptly: the previous run's data expires with your account's retention window (free tier: your ~10 most recent runs).

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

Keywords to search for (e.g. "software engineer", "nurse", "data analyst")

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

Location to search in (e.g. "New York, NY", "Remote", "London")

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

Maximum number of job listings to scrape. Keep at 15 or below for test runs.

## Actor input object example

```json
{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "query": "software engineer",
  "location": "New York, NY",
  "maxItems": 10
}
```

# Actor output Schema

## `results` (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 = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "query": "software engineer",
    "location": "New York, NY",
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("jungle_synthesizer/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 = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "query": "software engineer",
    "location": "New York, NY",
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("jungle_synthesizer/indeed-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 '{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "query": "software engineer",
  "location": "New York, NY",
  "maxItems": 10
}' |
apify call jungle_synthesizer/indeed-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/IKlo9HG2EzrKmofoJ/builds/lZ8QOFYsTGAo3MbD0/openapi.json
