Indeed Jobs Scraper - Salaries, Remote & Company Ratings
Pricing
from $0.90 / 1,000 job scrapes
Indeed Jobs Scraper - Salaries, Remote & Company Ratings
Scrape Indeed job search results in 23 countries: parsed salary ranges as numbers, remote work model, employer rating and review count, posting date and full descriptions. No login, no API key. Tells you when Indeed quietly ignored your location.
Pricing
from $0.90 / 1,000 job scrapes
Rating
0.0
(0)
Developer
Eimantas V
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Indeed Jobs Scraper
Scrape Indeed search results across 23 countries — no login, no API key, no quota.
One row per job, plus a summary row per search that tells you exactly what was and was not collected.
Salary as numbers, not prose
Most job exports hand you "$85,000 - $145,000 a year" and leave you to parse it. This one gives you the range Indeed already parsed:
salaryMin / salaryMax | 85000 / 145000 |
| an open-ended range | "From $80,000 a year" gives salaryMin: 80000, salaryMax: **null** — Indeed's own payload says -1 there, and a -1 silently wrecks every average and threshold it touches |
salaryCurrency | USD |
salaryPeriod | yearly — so you never compare an hourly rate against an annual one |
salaryText | the original wording, kept |
salaryIsEstimate | true when the figures are Indeed's own estimate rather than pay the employer published |
That last field is the one that matters. Indeed estimates pay for postings that don't state any, and a salary dataset that silently mixes the two isn't a salary dataset. Filter on it, or report the two separately.
What else is on every job
| Employer | name, Indeed rating out of 5, and how many reviews it's based on — a 5.0 from 2 reviews and a 4.1 from 9,000 are different facts |
| Remote | a remote flag and Indeed's work model, so "remote" can mean fully remote rather than hybrid |
| Timing | UTC posting timestamp, plus Indeed's own "3 days ago" wording |
| Type | full-time, contract, internship and so on, where the employer set one |
| Links | the canonical posting URL — not Indeed's tracking redirect, which expires |
| Flags | urgently hiring, new, sponsored, expired, easy-apply |
| Text | Indeed's summary snippet, and optionally the complete posting |
A company with no rating comes back as null, not the 0 Indeed sends. Zero stars and no stars are different things.
The thing Indeed does that quietly ruins job datasets
Indeed does not reject a location it can't parse. Ask it for Bostn and it doesn't error — it searches a much wider area and hands you a full page of results that look perfectly fine. You get 45 jobs from across the country and no indication anything went wrong.
So every summary row carries locationUsed: the location Indeed actually searched, read back off the page. When it doesn't match what you asked for, the log says so. Check that one field and a whole class of silently-wrong data disappears.
The same applies to sponsored placements repeating across pages, and to two of your searches matching the same posting. Both are deduplicated run-wide by job key, so you're never charged twice for one job.
Indeed shows you adverts first
This is not a scraping quirk, it is how Indeed works, and it catches people out: the entire sponsored block sits above the organic results. Measured on a real run, the first 20 results for "software engineer" in Remote were 20 sponsored postings and no organic ones at all.
Sponsored jobs are real vacancies, so they are kept by default — but you are never left guessing:
- every row carries
isSponsored - Exclude sponsored adverts drops them, and filtered rows are never written or charged
- raising Max jobs per search past the advert block reaches the organic listings too
An empty result always tells you why
Every search gets a summary row carrying how many jobs Indeed itself reports exist, how many were examined, how many your filters dropped, how many pages were read, and why it stopped. When a search produced nothing, zeroReason says which:
zeroReason | What it means |
|---|---|
search-matched-nothing | Indeed returned a results page with no jobs on it |
all-jobs-filtered-out | Jobs were found; your salary or remote filter removed them |
run-job-limit-reached | Your own run cap stopped it |
run-timeout-reached | The run stopped itself before the platform could kill it |
Searches that couldn't be read at all get a typed error row instead, and error rows are never charged. A blocked page partway through a search reports stoppedOn: "upstreamFailed" rather than resultsExhausted — because "the results ran out" and "we were blocked at page 4" produce the same row count and mean opposite things.
How to collect a lot of jobs
Each search returns about 45 jobs for one request, and that is the ceiling per search. So volume comes from running many searches rather than paging through one, and the Actor is built for exactly that — searches run in parallel and every row says which one it came from.
Three ways to multiply, all of which give Indeed a genuinely different first page:
| Split by | Example |
|---|---|
| Keyword | registered nurse, ICU nurse, nurse practitioner, LPN |
| City | Boston, Worcester, Providence, Springfield — rather than one wide radius |
| Date window | re-run daily with Posted within: Last 24 hours and Sort by: Date posted |
That last one is the most efficient pattern by far: a daily run with a 24-hour window keeps a complete rolling picture of a market for one request per search per day, and nothing is charged twice because postings are deduplicated by job key across the whole run.
Four ways to narrow it
- Keywords + location + country — the ordinary path, and 23 Indeed sites are selectable because a UK search sent to the US site returns US jobs without complaining
- Indeed URLs — paste search pages straight in, used verbatim so any filter you set on Indeed itself survives. This is the way to use Indeed filters this Actor does not model, and each URL is its own first page
- Posted within / job type / radius / sort by date — Indeed's own filters
- Minimum salary, remote-only and exclude-sponsored — applied here, on the results, because Indeed treats its versions as advisory. Minimum salary compares against the top of the range, so a role at 80k–150k still matches a 100k threshold
Filtered jobs are never written and never charged.
Honest about limits
- One page per search, about 45 jobs. Indeed serves the first page of a search to an automated client and refuses the rest. That is measured rather than assumed — across five runs, page two came back HTTP 502 through the unblocking proxy every time, and HTTP 403 on a plain connection. Rather than ship a page setting that quietly returns one page, this Actor defaults to one and tells you: set it higher and you get page one's jobs plus a summary row reading
stoppedOn: "upstreamFailed"and an error row saying what happened. Depth comes from more searches, not deeper pages — see below. - Posting dates are the original date. Employers repost, so a role can carry an old date and still be live. Anything older than a month is
30+ days ago— that's all Indeed will say. - Full descriptions are slow. A search request hands over about 45 jobs at once; a description costs one request per job. That's roughly forty times the work for the same rows, which is why it's off by default and priced separately.
- Many postings state no pay at all. Any minimum-salary filter above 0 drops them.
- Not every search reports a total.
totalResultsReportedis taken from Indeed's own "Page 1 of N jobs" counter, and isnullwhen the page does not print one rather than being estimated.
Pricing
Pay per result. You're charged for rows that were actually written.
| Event | Price |
|---|---|
| Job scraped | $1.50 per 1,000 jobs |
| Full description fetched | $4.00 per 1,000, only when descriptions are on |
| Actor start | $0.00005 per run |
Prices fall on every paid Apify plan, to $0.90 per 1,000 jobs at the top tier.
Summary rows are free. Error rows are free. Filtered jobs are free. Duplicate postings are charged once. A request that came back blocked and was retried on a fresh IP is not charged.
Getting started
Put a job title in Search keywords, a city in Location, press Start. The defaults collect one page per search — about 45 jobs — with descriptions off, which is one request.
Then:
- Set Sort by to
Date postedand Posted within toLast 24 hoursfor a feed you can re-run on a schedule - Turn on Remote jobs only and set Minimum salary to profile a market
- Add several Search keywords and cities at once — they run in parallel, every row says which search it came from, and this is how you get volume
- Turn on full descriptions only when you need the text, and expect it to take far longer
Export to JSON, CSV, Excel or XML, or pull the dataset straight from the Apify API.