Indeed Scraper - Job Search & Browse Jobs
Pricing
from $1.50 / 1,000 jobs
Indeed Scraper - Job Search & Browse Jobs
Collect Indeed job listings from over 60 configured country sites. Search by keyword or Browse Jobs category, with optional descriptions. Pay per delivered job row plus a start fee.
Pricing
from $1.50 / 1,000 jobs
Rating
0.0
(0)
Developer
kane liu
Maintained by CommunityActor stats
0
Bookmarked
6
Total users
2
Monthly active users
2 days ago
Last modified
Categories
Security
Limited permissionsShare
Indeed Scraper
Get Indeed job titles, employers, locations, salaries and optional descriptions from supported country sites as rows you can export.
- Search by job title, skill or company, with location and job filters.
- Discover jobs through Browse Jobs categories.
- Select one country site or up to 10 countries in one run.
- Keep job links, hashed job IDs and collection timestamps for comparison.
- Pay only for the rows you receive: $2.00 per 1,000 rows on the Free plan, plus a small start fee.
What does Indeed Scraper do?
Indeed Scraper collects job listings from Indeed country sites, including www.indeed.com, uk.indeed.com and ca.indeed.com. Each row represents one job. Use the rows for recruiting research, salary comparisons or tracking employers' advertised roles.
- Search: enter
keyword, optionally narrow it withlocation, and use the available filters. - Browse Jobs: set
scrapeModetobrowse, optionally choosingbrowseCategory. - Country selection: choose from more than 60 configured country sites. Availability and filter support vary by market; a configured country is not a guarantee of results.
- Optional details:
scrapeDetailsis off by default. Turn it on to request job descriptions and available employer information. These fields enrich the job row, rather than creating extra rows.
What data can you extract from Indeed?
Values depend on what Indeed publishes and whether details are requested. These are illustrative values, not a live sample.
| Field | Description | Example |
|---|---|---|
jobKey | Stable hashed job identity | 9f9f5111f7b27a781f1f1ddde5ebc2dd |
job_id | Same hashed identity as jobKey | 9f9f5111f7b27a781f1f1ddde5ebc2dd |
title | Job title as published | Pharmacist |
company | Employer name | Example Company |
location_text | Displayed job location | Phoenix, AZ |
city | City when available | Phoenix |
state | State or region when available | AZ |
country | Selected country code (uppercase ISO2) | US |
host | Indeed country domain | www.indeed.com |
salary_text | Published salary wording | $60 - $65 an hour |
salary_min | Lower bound of a published salary range, or null | 60000 |
salary_max | Upper bound of a published salary range, or null | 65000 |
salary_period | Salary pay period when published | YEARLY |
salary_currency | Salary currency code when published | USD |
job_types | Published employment types | ["Full-time"] |
remote_type | Remote or hybrid information when shown | remote |
benefits | Published benefit labels, or null | ["Health insurance"] |
description | Job description when details are available | Example job description. |
company_rating | Employer rating when shown | 3.9 |
company_review_count | Employer review count when shown | 120 |
posted_relative | Displayed age of the listing | 2 days ago |
posted_timestamp | Posting timestamp when available | null |
sponsored | Whether the listing is marked sponsored | false |
indeed_apply_enabled | Whether Indeed Apply is available | true |
browse_category | Category associated with a browsed job | Healthcare |
url | Public link to the listing | https://www.indeed.com/viewjob?jk=0123456789abcdef |
apply_url | External apply link when published | https://example-ats.example/apply/123 |
apply_redirect_url | Indeed apply redirect link when shown, or null | https://www.indeed.com/applystart?jk=0123456789abcdef |
company_key | Employer identifier used for dossier lookups | 1f9a6328e6e785f3 |
captured_at | Collection time | 2026-10-24T00:00:00+00:00 |
address | Employer headquarters, not the job location | {"locality": "Phoenix"} |
ldp_address | Job location address when published | null |
web | Available employer website and social links | {"website": "https://example.com", "socials": []} |
leadAbsences | Reasons that employer information is missing | {} |
jobKey, job_id and job_id_hash contain the same truncated SHA-256 identity. The public url still contains Indeed's original jk parameter, so hashing the ID fields does not anonymize the link.
How to scrape Indeed
- Open Indeed Scraper in Apify Console. A free Apify account is enough to try it.
- Enter a
keyword, such aspharmacist, and optionally alocation. - Set
maxResultsto5for a small first run. - Click Start and wait for completion. Check the status message for warnings.
- Download the dataset as JSON, CSV or Excel, or read it through the API.
An empty input starts the example search for pharmacist in Phoenix, AZ, with at most 3 rows. Example rows are billed at the same rate as other rows. Entering only keyword selects search mode and searches the whole selected country site. A category alone does not select browse mode: set scrapeMode explicitly.
Search jobs
Fill keyword with a title, skill or company. Use location for a city, region, postal code or Remote. Select the matching country; us is the default. For UK jobs use gb, which selects uk.indeed.com.
Browse Jobs
Set scrapeMode to browse. No keyword is needed. Use browseCategory, such as Healthcare, to narrow the categories, or leave it empty to explore up to maxCategories. location can narrow the job searches within those categories.
What to fill in
| Field | What to enter | Default |
|---|---|---|
keyword | Job title, skill or company for search mode | Empty; example prefill pharmacist |
location | City, region, postal code or Remote; empty means country-wide | Empty; example prefill Phoenix, AZ |
country | Two-letter code from the country selector | us |
countries | Up to 10 country codes; replaces country when populated | [] |
scrapeMode | search or browse | search |
maxResults | Maximum job rows for this search or browse input, from 1 to 1,000 | 70; form prefill 3 |
browseCategory | Category name for browse mode | Empty |
maxCategories | Maximum categories to follow, from 1 to 100 | 20 |
sort | relevance or date | relevance |
datePosted | 1, 3, 7 or 14 days; empty means any age | Empty |
jobType | Employment type, such as fulltime, parttime or contract | Empty |
experienceLevel | entry_level, mid_level or senior_level | Empty |
education | high_school, associate, bachelor, master or doctoral | Empty |
remoteType | remote or hybrid | Empty |
radius | Search radius: 0, 5, 10, 15, 25, 35, 50 or 100 | Empty |
encouragedToApply | fairchance, no_degree or military_encouraged | Empty |
indeedApplyOnly | Request listings with Indeed Apply | false |
scExtra | Advanced Indeed filter fragment, only if you know its value | Empty |
maxPages | Page limit for each search, from 1 to 100 | 1 |
scrapeDetails | Request job descriptions and available employer details | false |
detailConcurrency | Number of detail pages requested together, from 1 to 5 | 1 |
Search with details:
{"keyword": "pharmacist","location": "Phoenix, AZ","country": "us","maxResults": 5,"scrapeDetails": true}
Browse one category:
{"scrapeMode": "browse","country": "us","browseCategory": "Healthcare","maxCategories": 1,"maxResults": 5}
Search several countries with one shared row limit:
{"keyword": "nurse","countries": ["gb", "ie", "au"],"maxResults": 6}
maxItemsandlimitare aliases formaxResults.query,searchTermandjobTitleare aliases forkeyword;cityis an alias forlocation.- Unknown fields do not fail the run. Close misspellings can be corrected; other unknown fields are ignored with a note.
- Unsupported filter values are ignored with a warning. An unknown single
countryfalls back tous; invalid entries incountriesare skipped. - Invalid input stops before any job row is charged, with a message such as
INVALID_INPUT: maxPages: out of range. The start fee is separate. - The
INPUT_REPORTrecord in the run's key-value store records fields filled, corrected or ignored. It also identifies an example run.
Output example
This illustrative row shows a job with details available. Fields can be null or empty when the source does not provide them.
{"source": "indeed","jobKey": "9f9f5111f7b27a781f1f1ddde5ebc2dd","job_id": "9f9f5111f7b27a781f1f1ddde5ebc2dd","title": "Pharmacist","company": "Example Company","location_text": "Phoenix, AZ","country": "US","host": "www.indeed.com","salary_text": "$60 - $65 an hour","job_types": ["Full-time"],"remote_type": null,"benefits": ["Health insurance"],"description": "Example job description.","url": "https://www.indeed.com/viewjob?jk=0123456789abcdef","captured_at": "2026-10-24T00:00:00+00:00"}
You can export the dataset as JSON, CSV, Excel, XML, RSS or an HTML table. RUN_SUMMARY provides counts and warnings; INPUT_ECHO records the interpreted settings. Employer phone and email fields may be empty: the Actor does not invent contact details.
Why use this Indeed scraper?
- Pay per row. The row charge applies to jobs written to the dataset, not pages attempted. A start fee also applies.
- Usable partial rows. When job details cannot be fetched, available listing rows can still be delivered. Check the status message for missing descriptions. Rows already saved remain available after a stop; this does not guarantee delivery of unfinished work.
- Clear input feedback. Input errors name the field, while
INPUT_REPORTrecords corrections. - Source values stay recognizable. Missing salaries and benefits stay empty. Published titles are preserved, including occasional
Jobs for youtitles. - Multiple markets. Select several countries for the same keyword without preparing separate inputs.
- No proxy setup. You do not need to set up proxies or supply an Indeed account or API key.
How much does it cost to scrape Indeed?
The Actor uses pay-per-event pricing. The start event costs $0.005 per GB of Actor memory, with a minimum of one event. At the configured default of 512 MB, that is $0.005 per start, plus the row charges below.
| Apify plan | Price per row | Price per 1,000 rows |
|---|---|---|
| Free | $0.002 | $2.00 |
| Starter | $0.002 | $2.00 |
| Scale | $0.002 | $2.00 |
| Business | $0.0015 | $1.50 |
maxResultsapplies to the keyword/location or Browse Jobs input. Countries, categories and pages share that limit; it is not a separate allowance for each country.- The default is 70 rows. Larger requests are collected in parts of 70, subject to available jobs and other limits. The input allows up to 1,000.
- Free Apify plan users are limited to 200 rows per run and 10 runs of this Actor. These are limits set by the Actor developer. Paid plans remove the 10-run limit, not the input or spending limits.
- Set Maximum cost per run in the run options (
maxTotalChargeUsdin the API) to cap spending for the whole run.
Example: a Free-plan run delivering 150 rows at the default memory costs 150 × $0.002 + $0.005 = $0.305. Returning fewer rows costs less. A three-row example costs $0.011, including one start event.
What happens when the run timeout is too short
Some Indeed collections, such as several countries, a high maxPages or maxResults, or scrapeDetails: true, can take longer than the run timeout you chose. In that case the run does not fail. It ends early with the status message "Queued on the collection backend; this run will resume automatically when results are ready (about N s)." and shows as ABORTED for a while.
When the results are ready, the same run starts again by itself, reports "Resumed: delivering N rows.", writes the rows to the same dataset and finishes as SUCCEEDED. Rows that were already delivered are skipped, so no row is delivered or charged twice. You do not need to start another run.
- This can happen at most 3 times per run. To avoid it, keep the default timeout of 3600 seconds.
- The synchronous API endpoints (
run-sync,run-sync-get-dataset-items) wait at most 300 seconds and can return an empty dataset while the run is paused. For larger jobs, start the run asynchronously and read the dataset after the run reaches SUCCEEDED, or use a webhook on the "succeeded" event.
Use with AI agents and the API
Apify MCP server (Claude, ChatGPT, Cursor, VS Code)
Add this Actor as a tool in an MCP client that supports remote servers:
https://mcp.apify.com?tools=lentic_clockss/indeed-jobs-scraper
Sign in with Apify when asked using OAuth, or send Authorization: Bearer <YOUR_APIFY_TOKEN>. The tool starts a run and returns the run and dataset IDs. The agent then reads rows with get-dataset-items.
Clients without remote MCP support can run npx @apify/actors-mcp-server --tools lentic_clockss/indeed-jobs-scraper with the APIFY_TOKEN environment variable.
Example prompt: "Find up to five pharmacist jobs in Phoenix, AZ, on Indeed's US site. Return the title, company, salary and job link."
Apify API
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("lentic_clockss/indeed-jobs-scraper").call(run_input={"keyword": "pharmacist", "location": "Phoenix, AZ", "maxResults": 5})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item)
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('lentic_clockss/indeed-jobs-scraper').call({keyword: 'pharmacist', location: 'Phoenix, AZ', maxResults: 5});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Over HTTP, send POST https://api.apify.com/v2/acts/lentic_clockss~indeed-jobs-scraper/runs with the input JSON and an Authorization: Bearer <YOUR_APIFY_TOKEN> header. After the run finishes, read GET https://api.apify.com/v2/datasets/<datasetId>/items?format=json using its dataset ID.
Integrations
Use the Actor's Integrations tab to connect results to Google Sheets, Make, Zapier, n8n, Slack, Airtable or your own webhook. Use Apify Schedules for recurring runs.
FAQ
Is it legal to scrape Indeed?
Public access is not automatic permission for every use. You are responsible for complying with Indeed's terms and applicable data protection law. Processing personal data requires a lawful basis. Collect only what you need and assess your intended use before running the Actor.
Why did my run end as ABORTED?
The run stopped before normal completion. Read its status message and log for the reason; do not assume that all requested rows were delivered or that it will restart automatically. Check the dataset for saved rows and include the run ID when asking for help.
How many results can I get?
maxResults accepts 1 to 1,000 for one search or browse input. Matching listings, maxPages, spending limits and free-plan limits can reduce the delivered count. Selecting three countries does not triple the row allowance.
Why are some fields empty?
Indeed does not publish every field for every job. Descriptions generally need scrapeDetails: true, and a failed detail request can leave them empty. benefits stays null when no readable benefit labels are available. Employer headquarters in address is separate from the job location in ldp_address.
Can I scrape remote jobs only?
Use remoteType: "remote", or hybrid for hybrid roles, and optionally location: "Remote". Remote and education filters have their strongest support on us, ca, gb, au and ie; check the returned rows rather than assuming identical filtering in every country.
Does Browse Jobs require a keyword?
No. Set scrapeMode: "browse" and optionally browseCategory. The category and page limits still apply, and not every country site exposes the same categories.
Why does a row have the title Jobs for you?
Indeed sometimes publishes that text instead of a role name. The Actor keeps it rather than guessing. RUN_SUMMARY.placeholderTitleCount counts those rows so you can identify them when reviewing output.
Why did my free-plan run stop with a limit message?
The Actor allows Free-plan users 10 runs and at most 200 rows per run. Read the status message to see which limit applied. A paid Apify plan removes the developer's free-plan run restriction.
Limitations
- Search results change over time. This is not a complete archive of all Indeed jobs, and a requested row count is not a promise of that many matches.
- The default
maxPagesis 1. Increase it for broader searches, while keepingmaxResultsand the spending cap appropriate. - Country sites, categories and filters differ. A country listed in the form may be unavailable, and narrow filters can return no matches.
- Job details and employer information are optional and may be unavailable even when a listing row is returned. Phone numbers, emails and full addresses are not guaranteed.
- The public input supports keyword search and Browse Jobs, not a list of individual job URLs. It does not submit applications.
Related scrapers
More job board and freelance marketplace scrapers from the same publisher:
- LinkedIn Scraper
- Upwork Scraper
- Freelancer.com Scraper
- Glassdoor Scraper
- SEEK Scraper
- Bayt Scraper
- Fiverr Scraper
Browse all of our scrapers at apify.com/lentic_clockss.
Support
Found a problem or need another field? Open an issue in the Issues tab of this Actor's page and include the run ID and the input you used.