How it will work: 3 steps
- Follow us on ApifyThe tool is built and waits in the queue for the Apify Store. Apify is the cloud platform where our tools run.
- Paste your input and press StartNo code needed: you fill in a form (the input). It already has a working example. For example:
[]in Skills to match. Each start is one run. - Download the resultsWhen the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.
This tool is an Apify Actor: a small program that runs on Apify. You can also run it on a schedule, for example every Monday. New to it? Read how it works, step by step and the 8 words you need first.
What it does
Indeed Jobs Scraper turns a job title and location, an Indeed search URL or a list of job IDs into a table of Indeed jobs with pay, skills and company data, in 62 countries. You need no login, API key or cookies.
- Search jobs: by keyword and location, by Indeed search URLs, or by a list of searches.
- Look up job IDs: read up to 100 known jobs.
- Monitor changes: compare each run with the last one and mark jobs as new, still open or closed.
Good for
- You want pay data by job title and city, with hourly pay also shown as a yearly number.
- You want a list of companies that are hiring, with their website, size and rating.
- You want to see new and closed jobs for one search every day.
- You want to rank jobs by your own skill list.
Who uses it
Salary researchers
See pay by job title and city, with hourly pay also as a yearly number.
Sales and recruiting teams
Build a list of hiring companies with website, size and rating.
Job market analysts
Watch new and closed jobs for one search every day.
Price
Prices will be shown after release.
Questions
Do I need an Indeed account, API key or cookies?
No. The tool reads public job data only. You need an Apify account.
Are the salaries exact?
The pay comes from Indeed. Check salaryEstimated to see if Indeed marks it as an estimate. Jobs without pay have null.
Do I get every job on Indeed?
No. You get what Indeed returns for your search, up to your limit. Treat it as a sample of the market.
Why does a small run cost more per job than a large one?
Each source page has its own charge. A page holds many jobs, so a run with 20 jobs pays for a full page, and a run with 1,000 jobs shares its pages across more rows.
How fresh is the data?
Each row is read at the time of the run, shown in fetchedAt. To follow changes, use monitor mode on a schedule.
Details
Step by step on Apify
- Open the Input tab and keep or change Country (box 1 in the picture).
- Keep or change Job search and Location (box 2). The form starts with
data analystandNew York. - Keep Maximum jobs at 20 for the first run (box 3).
- Click Start.
- Open the Output tab and check the Jobs view. Box 5 shows the title, company, location and salary columns. Yearly pay, skills, skill matches and monitor status are in the All job fields view.
Use cases
| Task | Input | You get | Key fields | Next step |
|---|---|---|---|---|
| Compare pay for one job in many cities | searches | Job rows and search summary | salaryYearlyMin, salaryYearlyMax, salaryCurrency, city | Export to CSV or Excel |
| Build a list of hiring companies | query, location, uniqueCompanies | Job rows and employer summary | company, companyWebsite, companyEmployees, companyIndustry | Export to CSV, or send to a CRM with the API |
| Watch one search for new and closed jobs | mode: monitor, stateName | Job rows with a status | changeStatus, jobKey, title, url | Summary in Slack or Notion |
| Find jobs that match your skills | resumeKeywords, strictMatch | Job rows with a match score | matchedKeywords, unmatchedKeywords, keywordMatchPercent | Sort in a spreadsheet |
| Refresh jobs you already know | mode: lookup, jobKeys | Job rows | jobKey, expired, salary, postedAt | API, or an AI agent with MCP |
Tips for better results
- One search usually ends near 250 jobs. Use searches or deepSearch to get more.
- Use monitor mode on a schedule. It marks jobs as new, still open or closed.
- For 1,000 jobs, set the run timeout to 10 minutes.
Limits and good to know
- Rows:
maxItemsis an upper limit of 20,000 per run, not a promised count. Indeed can return fewer jobs for a search. One search usually ends near 250 jobs, because Indeed returns no more: a nationwide search for nurses gave 245. UsesearchesordeepSearchfor more. The largest run we measured saved 19,000 rows withdeduplicateoff. It found 2,138 repost duplicates, so with the default on, the same run saves fewer rows or reads more pages - Time: the default run timeout of 300 seconds fits a normal search of up to about 250 jobs. A run with 1,000 jobs took 175 to 266 seconds, which is close to that limit, so set 10 minutes for it. The largest measured run took 35 minutes, so set 1 hour for runs of that size. A filtered run with slow source pages took 100 seconds for 30 jobs
- Requests: each request waits up to 45 seconds and is tried up to 3 times. If a page still fails, the run ends as
FAILEDand keeps the rows it saved. Any searches left are listed inunprocessedSearches. One run reads up to 500 requests or 300 MB, and one response can be up to 8 MB - Deep search:
deepSearchcovers up to 100 city searches. Acompletestatus means these searches finished, not that every job in the country was found - Search URLs: URLs with other filters, such as company, level, pay or language filters from the Indeed page, stop the run with
INVALID_INPUT. Use the input filters instead - Monitor: a job is closed only when Indeed marks it as expired. A job that Indeed no longer returns stays open as unresolved. Each run checks up to 100 older job IDs. Only saved rows enter the history, which keeps up to 10,000 jobs. Run one monitor per
stateNameat a time - Pay: no currency conversion. Yearly pay uses hourly × 2080 and daily × 260
- Skills and level:
skillsuses a fixed skill list, andseniorityis a simple check of the title
For developers
Sample result
One result from a real test run, in JSON. Real values change from run to run. In Excel or CSV each field is a column.
{
"jobKey": "dd40c18d153680c6",
"title": "Business Data Analyst",
"company": "Cathay Holdings",
"location": "Brooklyn, NY, US",
"salary": "144414 USD/year",
"salaryYearlyMin": 144414,
"salaryYearlyMax": null,
"salaryCurrency": "USD",
"jobType": "fulltime",
"remoteType": "hybrid",
"experienceLevel": "mid",
"requirements": "Python (required); SQL (required); AI models (required); Master's degree (required); Jira (required)",
"skills": "Python; SQL; Machine Learning",
"postedAt": "2026-10-16T18:45:11.857Z",
"companyRating": 4,
"companyReviewCount": 1,
"companyWebsite": null,
"url": "https://www.indeed.com/viewjob?jk=dd40c18d153680c6",
"applyUrl": null,
"changeStatus": null
}Data fields (40)
| Field | Type | Meaning |
|---|---|---|
searchQuery | string | Search terms for this row; null for direct lookups. |
searchLocation | string | Location used in this search; null for direct lookups. |
jobKey | string | Indeed job identifier. |
title | string | Job title. |
company | string | Employer name. |
location | string | City, region and country. |
city | string | Job city. |
region | string | State or region code. |
country | string | Two-letter country code. |
postalCode | string | Postal code. |
latitude | number | Job latitude. |
longitude | number | Job longitude. |
salary | string | Pay range in the original currency and period. |
salaryMin | number | Minimum pay in the original period. |
salaryMax | number | Maximum pay in the original period. |
salaryCurrency | string | Original salary currency code. |
salaryPeriod | string | Pay period: hour, day, week, month or year. |
salaryEstimated | boolean | True when Indeed labels this salary as estimated. |
salaryYearlyMin | number | Annualized minimum pay. Hourly pay assumes 2,080 hours; daily pay assumes 260 days. |
salaryYearlyMax | number | Annualized maximum pay using the same assumptions. |
jobType | string | Employment type labels. |
employmentType | array/string | Employment types; text in flat output. |
remote | boolean | True for remote or hybrid; null when unknown. |
remoteType | string | remote, hybrid, onsite, or null when not labeled. |
experienceLevel | string | Indeed experience level from explicit job attributes; null when not returned. |
seniority | string | Seniority inferred from title; null when unclear. |
isEasyApply | boolean | True when Indeed Apply scopes include DESKTOP; null when scopes are unavailable. |
isUrgentHire | boolean | Indeed urgent hiring flag. |
isHighVolumeHiring | boolean | Indeed high-volume hiring flag. |
isPlacement | boolean | Indeed placement or recruitment agency flag. |
postedAt | string | Posting date on Indeed in UTC. |
publishedAt | string | Original publication date in UTC. |
expiresAt | string | Expiry date in UTC. |
expired | boolean | Explicit expiry status from Indeed. |
isRepost | boolean | Indeed repost flag. |
isLatestPost | boolean | Indeed latest post flag. |
language | string | Job language code. |
reference | string | Employer reference. |
description | string | Job description as plain text. |
companyId | string | Indeed employer identifier. |
Input settings (25)
The main fields of the input form. With the API you send them as JSON.
| Setting | Name in the API | Type | Example value |
|---|---|---|---|
| Mode | mode | string | "search" |
| Country | country | string | "US" |
| Job search | query | string | "data analyst" |
| Location | location | string | "New York" |
| Maximum jobs | maxItems | integer | 20 |
| Search radius | radius | integer | 25 |
| Radius unit | radiusUnit | string | "miles" |
| Posted within days | postedWithinDays | integer | 0 |
| Job type | jobType | string | "" |
| Work location | remote | string | "all" |
| Sort order | sort | string | "relevance" |
| Indeed Apply only | easyApply | boolean | false |
| Minimum annual pay | salaryMin | number | |
| Maximum annual pay | salaryMax | number | |
| Include jobs without pay | includeNoSalaryJob | boolean | true |
| Experience level | experienceLevel | string | "all" |
| External application links only | onlyExternalJobs | boolean | false |
| One job per company | uniqueCompanies | boolean | false |
| Skills to match | resumeKeywords | array | [] |
| Require all skill terms | strictMatch | boolean | false |
| Remove repost duplicates | deduplicate | boolean | true |
| Maximum jobs per search | maxItemsPerSearch | integer | 20000 |
| Indeed search URLs | startUrls | array | [] |
| Multiple searches | searches | array | [] |
| Expand search by city | deepSearch | boolean | false |


