# Indeed Jobs Scraper: 62 Countries, Full Descriptions & Salary (`quarra/indeed-jobs-scraper`) Actor

Scrape job postings from Indeed in 62 countries: search by keyword, location and radius, or paste search and job links. Full description, salary, job type, remote, company rating, size, revenue and website, dates. Reads every job of a search, newest first. Only new jobs mode for daily runs.

- **URL**: https://apify.com/quarra/indeed-jobs-scraper.md
- **Developed by:** [Quarra Labs](https://apify.com/quarra) (community)
- **Categories:** Jobs, Lead generation
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.06 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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: 62 Countries, Full Descriptions & Salary

Get job postings from **Indeed** in 62 countries, by keyword, location and radius, or by pasting the search pages and job
links you already use in your browser, filters included. Each job comes with its full description, salary when the
employer posts it, job types, remote or hybrid, the company's rating, reviews, size, revenue, industry, website and
headquarters, the exact location with coordinates, and the posting dates. Export as JSON, CSV or Excel, or read it through
the Apify API.

**$0.09 per 1,000 jobs** on the free plan, less on paid plans. Duplicates, jobs already delivered to your watch and failed
searches are not charged.

### Why this one

- **Every job of a search, not the first pages.** A search is read to its last job, newest first. On 8 November 2026,
  "nurse" in the United States gave 3,999 distinct jobs, all posted in the 41 hours before the run.
- **The full job description, not the snippet.** On those 3,999 jobs, every record had its full description (median
  3,659 characters), 89% the company's rating and review count, 79% its size, 69% its About text, 92% an apply link, 99%
  coordinates. 65% had a salary posted by the employer.
- **62 countries.** The United States, the United Kingdom, Canada, Australia, India, Germany, France, Spain, Mexico,
  Brazil, Japan and 51 more: pick one in **Country**, or paste search links from several country sites in one run.
- **Many searches in one run.** Every keyword is searched in every location; a job found by two searches is delivered
  and charged once, by its Indeed job key.
- **Only new jobs.** Schedule the same searches every day: each run delivers only the jobs it has not delivered before.
  Jobs already delivered are never charged again.
- **No personal data.** Recruiter contact lines are removed from the text fields (`description`, `companyDescription`):
  a phone number, a personal e-mail address, or a recruiter's name next to them or in a signature is replaced by
  `[removed]`. A company's service address (`careers@…`, `jobs@…`) is replaced alone; a contact line or a signature goes
  whole, with the job title or company name written on it. We measure this step on jobs it has never seen, read raw from
  Indeed. Last check, 8 November 2026, on 3,116 new jobs from 32 country sites: in the languages it was tuned on (English,
  German, Dutch, French, Spanish, Portuguese, Italian, Polish), 5 of 1,916 jobs still had a recruiter's name (0.3%); on the
  Danish, Norwegian, Swedish, Finnish, Czech, Hungarian, Greek, Turkish, Japanese, Korean and Chinese sites, 20 of 1,200
  still had a name or a phone number (1.7%, Denmark 6%). We then fixed the patterns behind them, all but three. It is not
  perfect: see Limits.
- **Never a silent empty run.** A search that finds nothing, a link that is not an Indeed page, a job that is closed:
  each gets a free error record or a status that says why, and the run summary lists every search with its count.

### Quick start

1. Type one or more **Keywords** (`registered nurse`, `data analyst`, `forklift driver`) and, if you want,
   **Locations** (`Austin, TX`, `London`, `75001`, `Ontario`).
2. Pick the **Country** of the Indeed site to search (United States by default) and add filters if you need them: posted
   within, job type, remote or hybrid, easy apply.
3. Click **Start** and read the jobs in the run's **Output** tab.

Like any Apify Actor, it can also be run and read through the Apify API, scheduled, and connected to webhooks, Make,
Zapier, n8n or Apify's MCP server for AI agents.

### Inputs

| Field | What it does |
|---|---|
| **Keywords** | One job title, skill or company per line, as you would type it in Indeed's search box. Each keyword is searched in each location. Empty = every job of the locations. Both empty = every job of the country, with at least one filter set (Posted within, Job type, Work mode or Easy apply only). |
| **Locations** | Optional, one per line: a city, a state, a region or a postal code, as Indeed writes it (`Austin, TX`, `London`, `75001`, `Ontario`). Empty = the whole country. |
| **Country** | The Indeed site to search, one of 62. For several countries, paste search links of each country site. |
| **Radius** | Distance around each location: miles in the United States and the United Kingdom, kilometers elsewhere, as on Indeed. Default 25. |
| **Search or job links** | An Indeed search page as shown in your browser (`https://www.indeed.com/jobs?q=nurse&l=Austin%2C+TX&fromage=7`), with its keyword, location, radius, date, job type and remote filters, from any Indeed country site; a job page (`https://uk.indeed.com/viewjob?jk=…`); or a job key alone (16 characters). |
| **Posted within** | 24 hours, 3, 7, 14 or 30 days, by the date the job appeared on Indeed. |
| **Job type** | Full-time, part-time, contract, temporary, internship, permanent, per diem, volunteer: one or more (a job of any of them is kept). |
| **Work mode** | Remote keeps fully remote jobs, Hybrid keeps hybrid jobs, both keep either. Empty = all jobs, on-site included. |
| **Easy apply only** | Keeps the jobs you can apply to on Indeed directly (`easyApply`). |
| **Only new jobs** + **Watch name** | Deliver only the jobs this watch has not delivered before. Watch names are case-sensitive (`Nurse Jobs` and `nurse jobs` are two watches); extra spaces are ignored. |
| **Max jobs per search** | Empty = every job of each search. |
| **Max results** | Total number of jobs of the run, all searches together, counted exactly. |

### Output

One record per job (texts shortened here):

```json
{
  "type": "job",
  "status": "ok",
  "jobId": "cf232431a1efd6bb",
  "title": "RN",
  "normalizedTitle": "registered nurse",
  "company": "Catholic Health",
  "companyId": "07d69832051b1446",
  "companyUrl": "https://www.indeed.com/cmp/Catholic-Health-4",
  "companyLogoUrl": "https://d2q79iu7y748jz.cloudfront.net/s/_squarelogo/256x256/8b5e260d6ccf0c6fac24a2bcb08fda83",
  "companyRating": 3.7,
  "companyReviewsCount": 593,
  "companyIndustry": "Health Care",
  "companySize": "10,000+",
  "companyRevenue": "$1B to $5B (USD)",
  "companyHeadquarters": "992 N Village Ave, Rockville Centre, NY 11570",
  "companyWebsite": "https://jobs.chsli.org/",
  "companyDescription": "As a member of the CH team, you will enjoy a career that is rewarding and challenging…",
  "location": "Roslyn, NY 11576",
  "city": "Roslyn",
  "state": "NY",
  "postalCode": "11576",
  "streetAddress": "100 Port Washington Boulevard",
  "country": "United States",
  "countryCode": "US",
  "latitude": 40.804802,
  "longitude": -73.66869,
  "workplaceType": null,
  "jobTypes": null,
  "schedule": null,
  "salaryMin": 56.39,
  "salaryMax": 83.99,
  "salaryCurrency": "USD",
  "salaryPeriod": "hour",
  "salaryText": "$56.39 - $83.99 an hour",
  "salaryIsEstimated": false,
  "attributes": ["Hourly pay", "Entry level"],
  "occupations": ["Healthcare Occupations", "Patient Care Nursing Occupations", "Nursing Occupations", "Registered Nurses"],
  "description": "Posted Salary Range:\n\nUSD $56.39 - USD $83.99 /Hr.\n\n…",
  "postedAt": "2026-11-07T16:48:06Z",
  "originallyPostedAt": "2026-10-21T05:00:00Z",
  "expiresAt": null,
  "isExpired": false,
  "easyApply": false,
  "applyUrl": "https://jobs.chsli.org/jobs/74197/job?…",
  "source": "Catholic Health",
  "language": "en",
  "url": "https://www.indeed.com/viewjob?jk=cf232431a1efd6bb",
  "input": "nurse",
  "position": 410,
  "scrapedAt": "2026-11-08T10:59:27Z"
}
```

- `salaryMin` and `salaryMax` are in `salaryCurrency` per `salaryPeriod` (`hour`, `day`, `week`, `month`, `year`), as
  the employer posted them. When the employer posts none and Indeed shows its own estimate, the estimate is given with
  `salaryIsEstimated: true`; with neither, the salary fields are `null`.
- `postedAt` is the date the job appeared on Indeed; `originallyPostedAt` the date the employer first published it, when
  Indeed knows it.
- `workplaceType` is `remote` or `hybrid` when Indeed files the job so, `null` otherwise.
- `attributes` are Indeed's tags for the job (pay type, experience level, skills, licenses, benefits); `occupations`
  Indeed's job categories.
- `description` is plain text with one paragraph or list item per line.
- With **Only new jobs**, each job also has `"isNew": true`.

Error records (free) have `type: "error"`, an `errorCode`, a clear `error` message and `retryable`. The run summary
(OUTPUT record) gives, per search, the jobs delivered and a note, and lists every input that was not understood
(`invalidInputs`; the dataset has an error record for the first 20 and one more that counts the rest).

### Pricing

Pay per event:

| Event | Free plan | Bronze | Silver | Gold and above |
|---|---|---|---|---|
| Job | $0.09 per 1,000 | $0.08 per 1,000 | $0.07 per 1,000 | $0.06 per 1,000 |
| Run start (per GB of memory) | $0.0009 | $0.0008 | $0.0007 | $0.0006 |

The Actor runs with 256 MB of memory, so a run starts at one start event. Never charged: a job found by more than one
search, jobs already delivered to your watch, jobs closed between the search and the reading of their page, error
records. Set **Maximum cost per run** in the run options and the run stops before going over it.

### What we measured

On 8 November 2026, on Apify, with 256 MB of memory:

- **Speed**: the default input (registered nurse in Austin, TX, 50 jobs) in 6 seconds; 4,000 jobs with full details
  in 11 minutes 25 seconds.
- **Whole searches**: "nurse" in the United States gave 3,999 jobs, every job key distinct, the newest posted within the
  hour before the run. 37 jobs listed twice by Indeed within the search were delivered and charged once.
- **Search links from two countries**: a London "data analyst" link with `fromage=3` and a Berlin "Pflegefachkraft" link with
  `radius=10`, in one run: 60 United Kingdom jobs, all posted in the last 3 days (Indeed lists 60 for that search), and 340
  German jobs, all in Berlin, with German text and salaries in EUR. A link to another site got a free error record.
- **Filters**: "software engineer" in Canada, posted within 3 days, Remote, Full-time: 23 jobs, all remote, all full-time,
  all in Canada, the same 23 Indeed returns when searched directly.
- **Only new jobs**: three runs of the same watch on "forklift driver" in Houston, TX delivered 150, then 957, then 0 jobs.
  Not one job was delivered twice.

### Send results to Slack, Notion or Discord

Pick one of your Apify MCP connectors in "Send results to your app" (Notion connects in one click), or paste a Slack, Discord, Make, Zapier or n8n webhook URL. After each successful run, a summary lands there: the number of results, the first 25 with their links, and a link to the full dataset. Schedule the Actor with "Only new jobs" turned on and new results reach your team every day without opening Apify.

### Limits

- Up to 100 keywords and 100 locations per run, and 500 searches (keywords × locations, plus links) in all; up to 20
  countries per run, links included.
- Indeed lists most remote jobs without a city. Remote with a location keeps only the remote jobs filed in that
  location: for every remote job, use Work mode Remote and leave Locations empty.
- Recruiter names are recognised from lists of first names, from contact words and from the shape of a signature or a
  contact line. A name with no contact word near it, a name written before the contact words ("Anna Berg will answer your
  questions"), or a Korean name outside a "담당자:" line can stay. The removal was tuned on English, German, Dutch and French job texts, then on
  Spanish, Portuguese, Italian and Polish ones, then on Danish, Norwegian, Swedish, Finnish, Czech, Japanese and Chinese
  ones; in other languages, a contact written in an unusual way is more likely to stay. A company's own switchboard number
  printed under its postal address can stay.
- Our leak counts come from an automatic scan (phone numbers, e-mail addresses, names near contact words) and a reading
  by hand of every hit: a name far from any contact word can escape the scan as well.
- A short sentence that carries a recruiter's contact is removed whole, with anything else it says.
- More memory than 256 MB brings nothing: the Actor is limited to 256 MB.

### FAQ

**Do I need an Indeed account?** No. The Actor reads the public job postings any visitor sees.

**How does "Only new jobs" work?** The watch remembers every job it delivered, by its Indeed job key. Use the same
**Watch name** in each scheduled run (without a name, the memory belongs to that exact list of searches and filters).
The first run delivers every matching job; the next ones only the jobs not delivered before, including jobs Indeed adds
up to two days late to a date already read. A run that stops early (maxItems, cost limits) is continued by the next run of the watch.
One run of a watch at a time: a run that was stopped abruptly keeps its watch busy for up to 15 minutes.

**Is anything different on Apify's free plan?** No. The same searches, fields and limits apply on every plan; only the
price per job changes, as in the table above.

**Why is the start charged per GB?** Apify counts a run's start by its memory. At 256 MB, a run pays one start event.

**What if the run is restarted by the platform (migration or reboot)?** It resumes where it was: jobs already in the
dataset are not delivered or charged again.

**What if Indeed changes its pages?** The run says so in its status and a free error record, instead of reporting
"no jobs", and nothing is charged but the start.

**Is it legal?** It collects public job postings published by employers to be read by anyone. Check the rules that apply
to your use of the data.

**Does the Actor send anything to Quarra?** Only when a run fails or runs out of time: the Actor, its build, the error
type, the line of our code where it happened, and the memory and time the run was given, so we can fix it fast. Never
your input, your results, your account or the ID of your run.

# Actor input Schema

## `keywords` (type: `array`):

One job title, skill or company per line (registered nurse, data analyst, forklift driver), as you would type it in Indeed's search box. Leave empty to list every job of the locations. With no keyword and no location, every job of the country is listed, if at least one filter is set (Posted within, Job type, Work mode or Easy apply only).

## `locations` (type: `array`):

Optional, one per line: a city, a state, a region or a postal code, as Indeed writes it (Austin, TX; London; 75001; Ontario). Leave empty to search the whole country. Remote jobs mostly have no city on Indeed: search them with Work mode Remote and no location.

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

Indeed site to search (Indeed has a separate site per country). For several countries, run once per country or paste search links of each country.

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

Distance around each location: miles in the United States and the United Kingdom, kilometers elsewhere, as on Indeed. Default 25.

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

One per line: an Indeed search page as shown in your browser (https://www.indeed.com/jobs?q=nurse\&l=Austin%2C+TX\&fromage=7), with its keyword, location, radius, date, job type and remote filters, from any Indeed country site; a job page (https://uk.indeed.com/viewjob?jk=…); or a job key alone (16 characters). Job links are read in batches of 100.

## `postedWithin` (type: `string`):

Date the job appeared on Indeed.

## `jobType` (type: `array`):

Optional, one or more (a job of any of them is kept). Leave empty for all.

## `workplace` (type: `array`):

Optional. Remote keeps fully remote jobs, Hybrid keeps hybrid jobs, both keep either. Leave empty for all jobs, on-site included.

## `easyApplyOnly` (type: `boolean`):

Keep only the jobs you can apply to on Indeed directly (easyApply).

## `onlyNew` (type: `boolean`):

Deliver only the jobs this watch has not delivered before. The first run delivers every matching job; the next runs with the same watch name deliver only the jobs not delivered before. Made for scheduled runs: jobs already delivered are never charged again. A run that stops early is continued by the next one.

## `watchName` (type: `string`):

Name of the watch that remembers the jobs already delivered (used with 'Only new jobs'). Optional: without a name, the memory belongs to this exact list of searches and filters. Names are case-sensitive: 'Nurse Jobs' and 'nurse jobs' are two different watches, and two different names never share a memory. Extra spaces are ignored.

## `maxJobsPerSearch` (type: `integer`):

Leave empty for every job of each search.

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

Total number of jobs delivered by the run, all searches together, counted exactly.

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

Connection. Keep the default (automatic). Costs are included in the price.

## `deliveryConnector` (type: `string`):

Pick one of your Apify MCP connectors: at the end of each run, a summary of the results (count, the first 25 with their links, a link to the full dataset) is posted there. With a schedule and 'Only new', you get each day's new results where your team works. Nothing is sent when a run finds nothing. Notion connects in one click; Slack and Google need your own OAuth app in Apify, or use the webhook field below.

## `deliveryTarget` (type: `string`):

Slack channel ID (C0123…), Notion page ID, Google Sheet ID… Leave empty if the app needs no target (a new Notion page is then created at the top of your workspace).

## `deliveryWebhookUrl` (type: `string`):

No connector needed. A Slack Incoming Webhook (hooks.slack.com/…) gets a message, a Discord channel webhook gets a message, any other URL receives the summary as JSON (title, text, count, datasetUrl, items).

## `deliveryTool` (type: `string`):

Name of the connector's tool to call. Leave empty: the best tool that posts a message, creates a page or appends rows is picked, and the run log lists every tool the connector offers.

## `deliveryArguments` (type: `object`):

Extra arguments for the tool, merged last, for example {"channel": "#indeed-jobs"} or {"parent": {"database_id": "…"}}.

## Actor input object example

```json
{
  "keywords": [
    "registered nurse"
  ],
  "locations": [
    "Austin, TX"
  ],
  "country": "US",
  "postedWithin": "any",
  "easyApplyOnly": false,
  "onlyNew": false,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Every job with all its fields, and free error records.

## `overview` (type: `string`):

A table with one row per job.

## `summary` (type: `string`):

Jobs per search, notes, why the run stopped, and errors.

# 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 = {
    "keywords": [
        "registered nurse"
    ],
    "locations": [
        "Austin, TX"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("quarra/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 = {
    "keywords": ["registered nurse"],
    "locations": ["Austin, TX"],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("quarra/indeed-jobs-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 '{
  "keywords": [
    "registered nurse"
  ],
  "locations": [
    "Austin, TX"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call quarra/indeed-jobs-scraper --silent --output-dataset

```

## MCP server setup

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