Indeed Scraper
Pricing
from $2.50 / 1,000 results
Indeed Scraper
Scrape Indeed jobs with full descriptions in text and HTML — the blanks other scrapers leave empty are re-fetched and filled. Adds company profile (website, industry, size, CEO), verified apply links, and salaries. Search by keyword, Indeed URL, or a specific company.
Pricing
from $2.50 / 1,000 results
Rating
0.0
(0)
Developer
Data Harbor
Maintained by CommunityActor stats
0
Bookmarked
6
Total users
4
Monthly active users
2 days ago
Last modified
Categories
Share
Indeed Scraper — Full Descriptions
Extract job listings from Indeed at scale: job title, full description (text and HTML), salary, location, employment type, verified apply link, and company profile. Search by keyword + location, paste Indeed search URLs, or scrape a specific company's jobs — then download as JSON, CSV, Excel, or feed it straight into your own tools via the API.
Built around one thing most Indeed scrapers get wrong: empty job descriptions. Indeed's bulk
API returns a blank description for a large share of sponsored and partner-ATS listings. This actor
detects those and re-fetches the real description from the job page, so your dataset comes back with
the descriptions actually filled in — and ships a descriptionEmpty flag so you can verify it.
What you can extract
- 🧑💼 Job — title, full description (plain text + HTML), employment type, remote flag, expired flag, posting date
- 💵 Salary — min, max, currency, and interval when Indeed publishes them
- 🔗 Links — the Indeed job URL and the resolved employer apply URL (the real link behind Indeed's redirect)
- 🏢 Company — website, description, industry, address, size, revenue, logo, and CEO name
- 📧 Emails — any contact emails found in the job description
Company fields depend on Indeed publishing a company profile for that employer. See Field coverage — an honest breakdown below for real numbers. Every job always includes title, description, location, posting date, and apply link.
How this scraper compares
| This actor | Typical Indeed scraper | |
|---|---|---|
| Job descriptions | Backfilled — empties re-fetched from the job page | Often left blank for ~half of sponsored/ATS listings |
| Description format | Plain text and HTML | Sometimes one or neither |
| Verified apply link | ✅ resolves the real employer URL behind Indeed's redirect | Sometimes |
| Company profile | website, description, industry, size, revenue, logo, CEO | Only behind an extra step, if at all |
| Search by URL | ✅ search URLs and company-jobs URLs | Sometimes |
| Filter out staffing agencies | ✅ flag or drop agency-posted jobs (no LLM) | ✗ |
| Multiple keywords per run | ✅ one per line, run in parallel | Sometimes |
| Drop-in migration | ✅ optional field names matching other Indeed scrapers | — |
| Dedup | ✅ unique listings | Sometimes |
| Pricing | Pay per result — billed only for jobs returned | Varies |
How to use it
- Create a free Apify account.
- Open this actor.
- Enter one or more job titles/keywords and a location — or paste Indeed Start URLs.
- Click Start and wait for the run to finish.
- Download your data as JSON, CSV, Excel, HTML, or XML, or pull it via the Apify API.
Input
You can drive the scraper three ways — by keyword, by Indeed search URL, or by company. Mix and match in a single run; each search is capped independently by Max job listings and the results are merged and de-duplicated.
| Field | Type | Default | Description |
|---|---|---|---|
position | string | accountant | Job title or keywords. Put one keyword per line to run several searches at once. Optional if you provide startUrls. |
startUrls | array | — | Indeed URLs to scrape: search-result URLs (e.g. https://www.indeed.com/jobs?q=nurse&l=Austin) and/or company-jobs URLs (e.g. https://www.indeed.com/cmp/Google/jobs). |
location | string | — | City, state, or region to narrow keyword searches. |
country | enum | USA | Indeed country domain (USA, UK, Canada, Australia, Ireland, India, Germany, France, Netherlands, Spain, Italy, Singapore, New Zealand, Mexico, Brazil). |
maxItems | integer | 100 | Max listings per search / per URL (hard cap 5000). |
maxAgeDays | integer | 7 | Only return jobs posted within this many days. |
scrapeCompanyDetails | boolean | true | Add the company profile block (website, description, industry, address, size, revenue, logo, employer key, CEO). |
detectStaffingAgencies | boolean | false | Add isStaffingAgency + staffingAgencyReason to each job — flags staffing/recruiting firms vs direct employers. |
excludeStaffingAgencies | boolean | false | Drop agency-posted jobs entirely (direct employers only). You aren't billed for excluded rows. |
uniqueOnly | boolean | true | Collapse duplicate listings (same job across searches). |
followApplyRedirect | boolean | true | Resolve the real employer apply URL behind Indeed's redirect and return it as applyUrl. |
compatibleFieldNames | boolean | false | Also emit alternate output keys that match the field names other Indeed scrapers commonly use, so you can switch to this actor without changing your code. See Migrating. |
proxyConfiguration | object | Apify Proxy (datacenter) | Proxy used for scraping. Required — see Proxy. |
Example — keyword search
{"position": "accountant","location": "New York","country": "USA","maxItems": 200,"maxAgeDays": 7}
Example — multiple keywords + a company's jobs
{"position": "accountant\nbookkeeper\ncontroller","startUrls": [{ "url": "https://www.indeed.com/jobs?q=financial+analyst&l=Chicago" },{ "url": "https://www.indeed.com/cmp/Deloitte/jobs" }],"maxItems": 150,"maxAgeDays": 14}
Output
One record per job. Here is a real, unedited record (description truncated for space):
{"title": "Budget Chief","company": "State of Florida","location": "Tallahassee, FL, US","jobUrl": "https://www.indeed.com/viewjob?jk=42ba7f5dfd73a7a0","applyUrl": "https://jobs.myflorida.com/job/TALLAHASSEE-Budget-Chief-FL-32399/1415668100/","datePosted": "2026-08-04","jobType": null,"isRemote": false,"isExpired": false,"salaryMin": null,"salaryMax": null,"currency": null,"interval": null,"description": "The Florida Legislature — Budget Committee … (full text)","descriptionHTML": "<div> … full HTML … </div>","descriptionEmpty": false,"emails": ["HouseAPD@FLHouse.gov"],"companyUrl": "https://www.indeed.com/cmp/State-of-Florida","companyWebsite": "https://www.myflorida.com/","companyIndustry": "Government","companyDescription": "Seeking an opportunity to start a new career or enhance your professional development? …","companyAddress": "Tallahassee, FL","companyNumEmployees": "201 to 500","companyRevenue": null,"companyLogo": "https://d2q79iu7y748jz.cloudfront.net/s/_squarelogo/256x256/15b41c73ae9b10833a18b747a07f3faf","employerKey": "c8ebc9c7f7d88fc0","ceoName": "Ron DeSantis"}
Field reference
Job fields — present on every job:
| Field | Type | Notes |
|---|---|---|
title | string | Job title |
company | string | Employer name |
location | string | Formatted location |
jobUrl | string | Indeed job page |
applyUrl | string | Resolved employer apply URL when followApplyRedirect is on; otherwise the Indeed URL |
datePosted | string | YYYY-MM-DD |
isRemote | boolean | Remote-work flag |
isExpired | boolean | Whether Indeed marks the listing expired |
description | string | Full description as text |
descriptionHTML | string | Full description as HTML |
descriptionEmpty | boolean | false means the description is present. Your built-in check that the backfill worked. |
jobType | array | e.g. ["fulltime"] — when Indeed tags it |
salaryMin / salaryMax / currency / interval | number/string | When Indeed publishes a salary |
emails | array | Emails found in the description, if any |
Company fields — added by scrapeCompanyDetails, populated when the employer has an Indeed profile:
| Field | Type | Notes |
|---|---|---|
companyUrl | string | Indeed company page (/cmp/…) |
companyWebsite | string | The employer's own website |
companyIndustry | string | e.g. Government, Accounting & Tax |
companyDescription | string | Short company blurb |
companyAddress | string | Headquarters/primary address |
companyNumEmployees | string | e.g. 201 to 500 |
companyRevenue | string | Revenue band, when available |
companyLogo | string | Logo image URL |
employerKey | string | Indeed's internal employer id |
ceoName | string | CEO name, when available |
Staffing-agency fields — added by detectStaffingAgencies:
| Field | Type | Notes |
|---|---|---|
isStaffingAgency | boolean | Whether the posting looks like a staffing/recruiting agency rather than a direct employer |
staffingAgencyReason | string | Which signals fired (company name, industry, description, or "our client" language) |
For recruiters & sales teams
A fresh job post is a hiring-intent signal — a company that needs to hire right now. This actor
gives you what you need to act on it: the company website/domain and CEO name to find and reach
the decision-maker, and a staffing-agency filter so you can screen out postings already handled by
recruiters and keep only direct employers. Turn on excludeStaffingAgencies for a clean list of
companies you can actually pitch or source for.
When a search finds nothing, the run finishes with a FOUND_NO_RESULTS status message and writes the
same signal to the run's key-value store — without pushing a dataset item, so an empty run is never
billed. Automations can still detect the empty result for free:
{ "error": "FOUND_NO_RESULTS", "errorDescription": "Scraper didn't find any jobs for the given input" }
Field coverage — an honest breakdown
Job fields (title, description, location, apply link, dates) are present on essentially every listing. The company fields come from Indeed's employer profile, which doesn't exist for every employer — sponsored and partner-ATS postings often have none. Typical coverage we observe:
| Field group | Typical coverage | Why it varies |
|---|---|---|
| Title, description, location, apply link | ~100% | Always available per listing |
| Company website / description / size / CEO / revenue | ~65–80% | From Indeed's job API — present when the employer has an Indeed profile |
| Company industry | ~10%+ | Indeed's job API returns it for only a minority of employers |
We don't fabricate missing values — if Indeed doesn't publish a field, it comes back null. Company
website, description, size, revenue, and CEO come straight from Indeed's job API, so they're the reliable
enrichment fields whenever the employer has an Indeed profile. Every job always has title, description,
location, and apply link.
Proxy (required)
Indeed refuses connections from datacenter/hosting IPs, so runs need a proxy. This actor defaults to Apify Proxy (datacenter), which the job scrape and description backfill both use — cheap and fast. Without any proxy, runs fail with a connection error.
Residential groups are selectable but rarely needed — they pull the same pages at many times the bandwidth. Try a re-run on datacenter first; blocks are usually transient.
Migrating from another Indeed scraper
Set compatibleFieldNames: true and the output also includes alternate keys that match the field
names other Indeed scrapers commonly use — positionName, url, id, externalApplyLink,
postedAt, scrapedAt, and salary — alongside this actor's own field names. That lets you point an
existing pipeline at this actor without rewriting your downstream code.
Integrations & API
Runs and datasets are available through the whole Apify platform: schedule runs, trigger
webhooks on finish, and connect to Make,
Zapier, Slack, Google Sheets, Google Drive, GitHub, Airbyte, and more. Everything is also reachable
programmatically via the Apify API and the apify-client packages
for Python and
JavaScript.
Pricing
Pay per result — you're billed only for the job listings the run returns. Company details are included in each result at no extra per-field charge. The best way to estimate your cost is to run a small test and multiply.
Is scraping Indeed legal?
This actor collects only publicly available job-posting data — the same information any visitor sees on Indeed. It does not access private accounts or bypass logins. Results can still contain personal data (e.g. a contact email in a description); you are responsible for handling any personal data lawfully and for your own use case. If you're unsure whether your use is permitted, consult a lawyer. See Apify's guides on ethical and legal web scraping.
FAQ
Why are some company fields empty? Because Indeed has no company profile for that employer. Job fields (title, description, apply link) are always present; company fields fill in when a profile exists — see coverage.
Do I really get full descriptions? That's the core feature: when Indeed's bulk response returns a
blank description, the actor re-fetches it from the job page. The descriptionEmpty flag on every
record lets you confirm it yourself — run the same query on any other scraper and compare.
Can I scrape a specific company's jobs? Yes — put its Indeed company-jobs URL
(https://www.indeed.com/cmp/<Company>/jobs) in startUrls.
How many results can I get? It varies by query, location, and country; Indeed itself limits how
deep any search goes. Set maxItems per search and run a test to see what your query returns.
How fresh are the jobs? Control it with maxAgeDays (default 7).
Feedback
Found a bug or want a field added? Open an issue on the actor's Issues tab in Apify Console — the scraper is actively maintained and tracks Indeed's changes.