# Indeed Jobs Scraper (51 Countries, No Login) (`locaihost/indeed-jobs`) Actor

Scrape Indeed jobs and full descriptions from 51 countries with no login: title, company, location, yearly USD salary, job type, remote or hybrid, posting date and benefits. Every job is flagged with the employer's US H-1B/PERM record and UK sponsor licence. No duplicates. From $1 per 1,000 jobs.

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

## Pricing

from $0.55 / 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 (51 Countries, No Login)

Search Indeed in 51 countries by keyword and location and get one row per job with title, company, location, job type, remote flag, the stated salary converted to yearly US dollars, and the employer's real US H-1B/PERM filing record and UK sponsor licence. No login, no cookies.

- **Track who is hiring:** pull every new job for a role and city into a sheet each morning.
- **Research salaries:** compare stated pay in one currency and one period across cities and countries.
- **Find jobs that can sponsor a visa:** keep only employers that file H-1B or PERM applications or hold a UK sponsor licence.
- **Run a job board for international candidates:** tag every listing with sponsorship evidence.
- **Get a daily job alert:** schedule a saved search with `onlyNew` and receive only jobs you haven't seen.

### Quick start

Paste this into the **JSON** tab of the input and click **Start**:

```json
{"keywords": ["software engineer"], "locations": ["Austin, TX"], "country": "US", "maxResults": 20}
```

You get 20 jobs in about 30 seconds. `maxResults` is the cap for the whole run; each keyword is searched in every location, on the Indeed site of the `country` you pick (a London search needs `"country": "GB"`).

### What data can I get?

| Group | Fields |
|---|---|
| Job | `jobId`, `title`, `companyName`, `companyUrl`, `jobUrl`, `postedAt`, `postedAgo`, `descriptionSnippet`, `benefits` |
| Full description (opt-in) | `description`: the whole job description as plain text, with `includeDescription` on; `null` otherwise |
| Location and type | `location`, `city`, `state`, `postalCode`, `country`, `remote`, `workArrangement`, `jobTypes`, `jobTypesText` |
| Salary as stated | `salaryText`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` |
| Salary per year | `salaryYearlyMin`, `salaryYearlyMax`, `salaryYearlyMinUsd`, `salaryYearlyMaxUsd`, `salaryUsdRateDate` |
| Listing | `companyRating`, `companyReviewCount`, `sponsored`, `urgentlyHiring`, `easyApply` |
| US sponsorship | `sponsorSignal` (`strong`, `some`, `none`), `sponsorMatch`, `h1bEmployer`, `h1bCertifiedLatestFY`, `h1bCertifiedTotal`, `permCertifiedTotal`, `similarFiledTitle`, `similarTitleFilings`, `similarTitleMedianWage` + currency and period |
| UK sponsorship | `ukLicensed`, `ukSponsorName`, `ukRating`, `ukRoutes`, `ukMatchBasis`, `possibleMatches` |
| Plain English | `sponsorNote`: one sentence you can show a candidate |
| Run | `searchKeywords`, `searchLocation`, `searchCountry`, `searchVariant`, `scrapedAt` |

**How salaries are converted.** Yearly figures use 2,080 hours, 260 days, 52 weeks or 12 months, the same rule the US Department of Labor uses for H-1B wages, so they compare directly with `similarTitleMedianWage`. Exchange rates are the European Central Bank's reference rates of the day (`salaryUsdRateDate`). A currency without a published rate gets no USD figure rather than a guessed one.

**How the sponsorship flag works.** US evidence is the employer's certified H-1B (and H-1B1/E-3) Labor Condition Applications and PERM certifications from the US Department of Labor's public disclosure files, FY2024 to date; `similarFiledTitle` is the employer's filed title closest to this job, with its median filed wage. UK evidence is the Home Office register of licensed sponsors; `ukMatchBasis` is `exact`, `trading-name`, `brand-map` (a reviewed brand to legal-entity list) or `unconfirmed` (only similar names, listed in `possibleMatches` and never counted). When nothing is found the note says *"no filings found under this name"*, never "doesn't sponsor". The flag is evidence, not legal advice.

One real row (run on 2026-10-18, shortened):

```json
{
  "jobId": "a8cacb8086a3b132",
  "title": "Associate Software Engineer",
  "companyName": "Charles Schwab",
  "location": "Austin, TX",
  "remote": false,
  "workArrangement": "hybrid",
  "salaryText": "$44.23 - $45.19 an hour",
  "salaryMin": 44.23,
  "salaryMax": 45.19,
  "salaryCurrency": "USD",
  "salaryPeriod": "hour",
  "salaryYearlyMinUsd": 91998,
  "salaryYearlyMaxUsd": 93995,
  "salaryUsdRateDate": "2026-10-16",
  "benefits": ["Dental insurance", "401(k)", "401(k) matching", "Tuition reimbursement"],
  "postedAt": "2026-10-15T05:00:00.000Z",
  "companyRating": 3.9,
  "companyReviewCount": 2941,
  "sponsored": false,
  "jobUrl": "https://www.indeed.com/viewjob?jk=a8cacb8086a3b132",
  "sponsorSignal": "strong",
  "sponsorNote": "Charles Schwab & Company, Inc.: 352 certified H-1B/E-3 LCAs in FY2026 (year in progress), 1,399 in FY2024–FY2026, 399 certified PERM. Closest filed title: \"Associate - Software Development & Engineering\" (13 filings, median wage $91,105).",
  "h1bCertifiedLatestFY": 352,
  "permCertifiedTotal": 399,
  "similarTitleMedianWage": 91105,
  "ukLicensed": null
}
```

The dataset has three views (**Jobs**, **Visa sponsorship evidence**, **Salaries**) and exports to JSON, CSV, Excel or HTML. The run's `SUMMARY` record lists the searches run, jobs skipped and why, and the data dates.

### Full job description

Turn on `includeDescription` to get each job's whole description as plain text in `description` (lists become "- " lines). The run opens each job on Indeed's search page the way clicking a job card does (the search URL with `vjk=<jobId>`), which Indeed's robots.txt allows; it never opens `/viewjob`, which robots.txt asks automated visitors to avoid. That is one more page per job, so a run takes a few seconds longer per job (3 to 15 seconds in our tests), and it is a paid add-on (below). E-mail addresses, phone numbers and recruiter names after "contact" are removed. When a description can't be read, the job is still returned with `description: null` and the add-on isn't charged.

```json
{"keywords": ["registered nurse"], "locations": ["Austin, TX"], "includeDescription": true, "maxResults": 20}
```

### Only the country you asked for, no duplicates

Each Indeed country is its own site, and the run reads only the one you chose (`country`): a page Indeed sends to another country's site is not read, and a job Indeed files under another country is skipped. A job is returned once per run, keyed by Indeed's job key (`jobId`): when two of your searches, locations or the narrower versions of a search find the same job, it is returned and charged once. `onlyNew` extends that across runs.

### How much does it cost?

You pay per job returned, with salary conversion and sponsorship flags included. There is no charge for Apify platform usage on top.

| Row | Free and Starter | Scale | Business |
|---|---|---|---|
| Job | $1.00 per 1,000 | $0.75 per 1,000 | $0.55 per 1,000 |
| Job description, add-on with `includeDescription` ($) | $5.00 per 1,000 | $3.75 per 1,000 | $2.75 per 1,000 |

Plus $0.00005 per run start. **Apify's free $5 monthly credit covers about 5,000 jobs**, or about 830 jobs with full descriptions. The description add-on costs more because each description is one more Indeed page. Free-plan runs stop at 1,000 jobs each; any paid Apify plan removes the cap.

**What's free:** a job found by two of your searches (returned and charged once), jobs outside your date, job type or remote filters, jobs dropped by `visaSponsorship: only-with-evidence`, sponsored listings when `includeSponsored` is off, jobs skipped by `onlyNew`, jobs from another country's site, descriptions that couldn't be read, and runs that find nothing. To cap a run's spend, set **Maximum cost per run** in the run options.

### Limits, stated up front

- **One page per search.** Indeed shows a logged-out visitor only the first page of results (15 jobs, plus sponsored listings on US pages); the next page asks you to sign in, and the Actor never signs in. To return more, it also runs narrower versions of your search that any visitor can run (newest first, each job type, hybrid, remote, last 1 or 3 days), each showing a different first page. Expect about 100 to 200 different jobs per keyword and location; add cities or keywords for more.
- **The full description is opt-in.** By default you get the snippet Indeed shows in search results (`descriptionSnippet`) and `jobUrl`. With `includeDescription` on, you also get the full text (see above), read from the search page with the job selected, never from `/viewjob`, which robots.txt disallows.
- **No search radius.** Indeed's robots.txt disallows the radius setting, so Indeed's default distance around your location applies.
- **Sponsored listings** are real jobs employers pay to show. They are marked `sponsored: true` and checked against your filters (Indeed doesn't always apply filters to them). Turn `includeSponsored` off to drop them.
- **Salary** appears only when the employer stated one. Indeed's own estimates are not reported as numbers.
- **Countries.** The parser was checked on 15 country sites (US, UK, Canada, Australia, India, Singapore, Ireland, South Africa, UAE, Malaysia, Japan, Germany, France, the Netherlands, Brazil); the others run the same Indeed software. Search in the site's own language works.
- **Indeed may push back.** The Actor uses a real browser and changes the network route when a page is refused, and never solves CAPTCHAs. If Indeed keeps refusing, the run stops, keeps what it has and tells you.
- **Staffing agencies** are flagged with the agency's own filings, not those of the client they hire for. US filing data is refreshed quarterly; the latest fiscal year is partial.
- **Time limit:** if a run nears its timeout, it stops, keeps what it found and says so in the status message.

### Only new since last run, and schedules

Turn on `onlyNew` in a saved task and schedule it daily: each run returns only jobs no earlier run of the same search returned, so you get a clean job alert and never pay twice for the same job. Skipped jobs cost nothing. Set up a schedule under **Schedules** in Apify Console.

### Integrations: API, n8n, Make and AI agents

**API.** Run it and get the rows back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/locaihost~indeed-jobs/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["registered nurse"], "locations": ["Houston, TX"], "country": "US", "maxResults": 50}'
```

Apify's API clients for Python and JavaScript work the same way.

**n8n, Make, Zapier, Google Sheets, Slack, webhooks.** Apify's built-in integrations send each run's dataset wherever you need it.

**AI agents (MCP).** Add this Actor to Claude, Cursor or any MCP client with `https://mcp.apify.com/?tools=locaihost/indeed-jobs`, then ask something like *"What do data analyst jobs in Toronto pay this week, in US dollars a year?"*

### FAQ

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

$1 per 1,000 jobs on the Free and Starter plans, salary conversion and sponsorship flags included, and less on Scale and Business. Apify's free $5 monthly credit covers about 5,000 jobs.

#### Can I use it through the API or from Python?

Yes. Use the `run-sync-get-dataset-items` call above, or Apify's Python and JavaScript clients. Every run's data is also available as JSON, CSV or Excel from its dataset.

#### Can I use it from an AI agent?

Yes. Through the Apify MCP server (`https://mcp.apify.com/?tools=locaihost/indeed-jobs`) any MCP client can run a search and read the jobs back.

#### Is it legal to scrape Indeed jobs?

The Actor reads only what a logged-out visitor sees on Indeed's search pages, follows Indeed's robots.txt on every request, and never logs in or asks for your account. Indeed's own terms restrict automated access, so weigh that for your use. Rows describe jobs and employers only: email addresses and phone numbers in a snippet are removed, and the sponsor data never names a private individual (household employers are dropped). You are responsible for using the data lawfully, including Indeed's terms and any data-protection law that applies to you.

#### Which countries can I search?

51 Indeed country sites, picked with `country`: the US, UK, Canada, Australia, India, Singapore and 45 more across Europe, Asia, the Middle East, Africa and Latin America. Each site has its own jobs.

#### Why are some fields empty?

Salary appears only when the employer stated one, many cards don't list a job type or benefits, and sponsorship fields are `null` when no filing matched the employer's name.

### More from locaihost data

- [LinkedIn Jobs Scraper](https://apify.com/locaihost/linkedin-jobs): the same sponsorship flags on LinkedIn jobs, with full descriptions.
- [Google Jobs Scraper](https://apify.com/locaihost/google-jobs): jobs from many boards at once through Google's job search.
- [Glassdoor Jobs Scraper](https://apify.com/locaihost/glassdoor-jobs): Glassdoor listings with company ratings.
- [H1B and UK Visa Sponsor Lookup](https://apify.com/locaihost/visa-sponsors): check a list of employers' sponsorship records directly.

### Did it help?

If this saved you time, a quick rating on the Store helps other people find it.

### Support

Something not working, or a field you need? Open an issue on the **Issues** tab: we answer issues within 24 hours.

# Changelog

This Actor's version history is a separate document: https://apify.com/locaihost/indeed-jobs/changelog.md

# Actor input Schema

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

What you would type into Indeed's "What" box, e.g. "registered nurse", "data analyst". Each keyword is searched in every location.

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

City, state, region or postcode as you would type it into Indeed's "Where" box, e.g. "Austin, TX", "London", "Toronto, ON". Leave empty to search the whole country.

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

Which Indeed site to search. Each country is its own site with its own jobs, so a London search needs the United Kingdom.

## `maxResults` (type: `integer`):

For the whole run, across all keywords and locations. Leave empty for 100. Indeed shows a logged-out visitor one page per search, so expect about 100 to 200 jobs per keyword and location at most; add locations or keywords for more.

## `daysPosted` (type: `string`):

Only jobs posted in the last 1, 3, 7 or 14 days (Indeed's own choices).

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

Only jobs of this type.

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

Only jobs Indeed marks as remote, or as hybrid.

## `visaSponsorship` (type: `string`):

Every job is flagged with the employer's US H-1B/PERM filing record and UK sponsor licence. "Only jobs with evidence" keeps only jobs whose employer has filed for visas or holds a UK licence.

## `includeSponsored` (type: `boolean`):

Indeed shows paid listings next to the organic results (on US pages up to 30 next to 15). They are real jobs and are marked sponsored: true. Turn off to keep organic results only.

## `includeDescription` (type: `boolean`):

Adds each job's full description as plain text (field description). Paid add-on: $5 per 1,000 descriptions on the Free and Starter plans, less on higher plans, charged only when the description was read. Reads one more Indeed page per job, so a run takes a few seconds longer per job. Off by default: you get Indeed's short snippet (descriptionSnippet).

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

Remembers what this saved task already returned, so a daily schedule becomes a job alert and you never pay twice for the same job. Off by default so the first run returns everything.

## Actor input object example

```json
{
  "keywords": [
    "software engineer",
    "data analyst"
  ],
  "locations": [
    "Austin, TX",
    "Remote"
  ],
  "country": "US",
  "maxResults": 20,
  "daysPosted": "any",
  "jobType": "any",
  "remote": "any",
  "visaSponsorship": "any",
  "includeSponsored": true,
  "includeDescription": false,
  "onlyNew": false
}
```

# Actor output Schema

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

One record per job: title, company, location, salary, remote, job type, posting date and sponsorship evidence.

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

Searches run, jobs returned and skipped, block rate, field-drift check, data dates and measured cost per 1,000.

# 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": [
        "software engineer"
    ],
    "locations": [
        "Austin, TX"
    ],
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("locaihost/indeed-jobs").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": ["software engineer"],
    "locations": ["Austin, TX"],
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("locaihost/indeed-jobs").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": [
    "software engineer"
  ],
  "locations": [
    "Austin, TX"
  ],
  "maxResults": 20
}' |
apify call locaihost/indeed-jobs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,locaihost/indeed-jobs"
        }
    }
}
```

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/vPtNmMhChixd2wusI/builds/u8EeKcVvV5PQItMlN/openapi.json
