Indeed Jobs API

An Indeed jobs API that returns live listings as flat JSON, one row per job, with no Indeed partner key. Search by keyword and location on any of 62 Indeed country sites and filter by job type, remote or hybrid, experience level, date posted, Easy Apply, radius and a yearly pay floor. Or pass Indeed search-results URLs with their filters intact, single job URLs, or a company's jobs page to list every open role there. Each row carries the pay range parsed into minimum, maximum, period and currency, with a flag for when the figure is Indeed's estimate rather than the employer's, plus benefits, the apply link, the sponsored and urgently hiring flags, and the full description as Markdown, plain text or HTML. Employer industry, size, revenue and headquarters are an optional add-on billed once per company. You pay per job returned, and rows that explain a failed input are free.

MEDIAN LAGon demand
FIELDS55
TOTAL USERS2
MONTHLY ACTIVE1
TOTAL RUNS47
SUCCESS (30D)100.0%
RATINGno ratings yet
LAST MODIFIED2026-10-04
PUBLISHED2026-08

Input parameters

PARAMETERTYPEREQDEFAULTDESCRIPTION
mode enum yes search What to run: search (keywords, a location and filters), url (job posting or search-results URLs you already hold) or company (every job on an Indeed company jobs page).
keywords string[] no — Job titles or keywords, each searched separately and in parallel, up to 5 per run. Indeed's own syntax works: quotes for a phrase, a leading minus to exclude a word, title:(...) to match titles only. Search mode.
location string no — A city, region, zip code or Remote, for example Austin, TX. Empty searches the whole country. Search mode.
country string no US Two-letter code of the Indeed country site to read, for example US, GB, CA, AU, IN, DE or FR. The matching host is picked automatically.
domain string no — Optional host override such as uk.indeed.com. Leave empty and the country code decides.
datePosted enum no — Only jobs posted within this window: Last 24 hours, Last 3 days, Last 7 days or Last 14 days. Empty means any time. Search mode.
jobType string[] no — Employment types: fulltime, parttime, contract, temporary, internship, permanent, new_grad or commission. Each type is searched separately for every keyword. Search mode.
remote enum no any Work arrangement: any, remote or hybrid. Search mode.
experienceLevel enum no — Only roles Indeed classifies as entry, mid or senior. Empty means any level. Search mode.
sortBy enum no relevance relevance for Indeed's best matches first, or date for the newest postings first. Search mode.
easyApplyOnly boolean no false Only postings that accept Indeed's one-click apply. Search mode.
minPay integer no — Yearly pay floor in the local currency. Hourly, daily, weekly and monthly pay is converted to a yearly figure first, and jobs that state no pay are left out when a floor is set. Search mode.
locationRadiusMiles integer no — Search radius around the location: 0, 5, 10, 15, 25, 35, 50 or 100 miles. Other values snap to the nearest. Search mode.
jobUrls string[] no — Indeed job posting URLs (one job each) or search-results URLs (filters kept), up to 100 per run. Country sites such as fr.indeed.com work. URL mode.
companyJobUrls string[] no — Indeed company jobs pages such as https://www.indeed.com/cmp//jobs, up to 10 per run. Company mode.
maxResultsPerInput integer no 50 Most jobs to return for each keyword, search URL or company page, 1 to 1,000. Single job URLs return one job each. — drives your bill
uniqueJobsOnly boolean no true Return and bill each job once per run, even when several keywords or URLs find it.
includeCompanyDetails boolean no false Add the employer's industry, size, revenue, headquarters and profile text to each job. Billed once per distinct employer on top of the per-job fee. — drives your bill
descriptionFormat enum no markdown markdown keeps headings and bullet lists, text strips formatting, html is the original, all returns the three on the same row.

Output schema

FIELDTYPEDESCRIPTIONNULLABLE
result_type string Row kind: job for a billed job row, or error for a free row that explains why an input returned nothing. no
jobId string Indeed's job key, the jk value in a viewjob URL, stable for the life of the posting. The dedupe key within a run. yes
jobTitle string The job title as posted. yes
companyName string The hiring company's name. yes
companyUrl string The employer's Indeed company page. yes
companyWebsite string The employer's own website, when the posting or company details list one. yes
companyRating number Employer rating out of 5, when rated. yes
companyReviewsCount integer Number of employee reviews behind that rating. yes
companyLogo string Company logo image URL. yes
companyIndustry string Employer's industry. Company details add-on. yes
companySize string Employer's headcount band. Company details add-on. yes
companyRevenue string Employer's revenue band. Company details add-on. yes
companyHeadquarters string Employer's headquarters location. Company details add-on. yes
companyDescription string Employer's own profile text. Company details add-on. yes
companyDetailsAdded boolean True when the company details add-on filled this row. yes
location string Location as shown on the listing. yes
jobLocation string Fuller location string, with the street address when the listing gives one. yes
city string City of the job. yes
state string State or region code. yes
postalCode string Postal code, when the listing gives one. yes
region string State or region code, the same value as state. yes
country string Two-letter country code of the Indeed site. yes
domain string The Indeed host the listing came from. yes
isRemote boolean True when the listing is marked remote. yes
workModel string Work arrangement as labelled, for example Remote or Hybrid work. yes
jobUrl string Canonical Indeed URL for the posting. yes
applyUrl string Direct apply link, when the posting exposes one. yes
datePosted string Posting date as an ISO 8601 timestamp. yes
datePostedText string Posting age as Indeed shows it, for example 30+ days ago. yes
jobType string Employment type, for example Full-time. Several types are joined with a comma. yes
salaryText string Pay exactly as written on the listing. yes
salaryMin number Lower bound of the pay range. yes
salaryMax number Upper bound of the pay range. yes
salaryPeriod string Pay period of the range: HOURLY, DAILY, WEEKLY, MONTHLY or YEARLY. yes
salaryCurrency string Currency code of the pay range. yes
salaryIsEstimated boolean True when the range is Indeed's estimate rather than the employer's own figure. yes
benefits array Benefits listed on the posting. yes
qualifications array Qualifications listed on the posting. yes
shiftSchedule array Shift and schedule requirements, for example Weekends as needed. yes
isExpired boolean True when the posting is no longer active. yes
isSponsored boolean True when the listing is a paid placement. yes
isEasyApply boolean True when the posting accepts Indeed's one-click apply. yes
isUrgentlyHiring boolean True when the employer flagged the role as urgently hiring. yes
isHiringMultiple boolean True when the employer is hiring more than one person for the role. yes
isNew boolean True when Indeed marks the posting as new. yes
isFeaturedEmployer boolean True when the employer is featured on the listing. yes
sourceName string The job board or applicant tracking system the posting came from. yes
descriptionMarkdown string Full description as Markdown with headings and lists kept. With descriptionFormat markdown (the default) or all. yes
descriptionText string Full description as plain text. With descriptionFormat text or all. yes
descriptionHtml string Full description as the original HTML. With descriptionFormat html or all. yes
searchKeyword string The keyword that found this job, in search mode. yes
searchLocation string The location that found this job, in search mode. yes
sourceInput string The keyword or URL from your input that produced this row. yes
summary string One plain-language line per job, for agents that read rows as prose. yes
error_message string Why one input returned nothing, on error rows. Error rows are never billed. yes

Worked examples

Remote Python jobs from the last week, newest first — the whole US site, sorted for a scheduled watch
{"mode": "search", "keywords": ["python developer"], "remote": "remote", "datePosted": "Last 7 days", "sortBy": "date", "maxResultsPerInput": 50}
Full-time nursing jobs in Dallas paying at least $80,000 a year — hourly pay is converted to a yearly figure; jobs with no stated pay are left out
{"mode": "search", "keywords": ["registered nurse"], "location": "Dallas, TX", "jobType": ["fulltime"], "minPay": 80000, "maxResultsPerInput": 100}
Data analyst jobs in London — the country code picks uk.indeed.com
{"mode": "search", "keywords": ["data analyst"], "location": "London", "country": "GB", "maxResultsPerInput": 50}
Every open role at one employer, with company details — industry, size, revenue and headquarters billed once for the employer
{"mode": "company", "companyJobUrls": ["https://www.indeed.com/cmp/Semrush/jobs"], "includeCompanyDetails": true, "maxResultsPerInput": 100}
Re-run a search URL you already built on Indeed — every filter in the URL is kept
{"mode": "url", "jobUrls": ["https://www.indeed.com/jobs?q=nurse&l=Dallas%2C+TX"], "maxResultsPerInput": 50}
POWER-USER TIP
Missing fields are left out, not null — A field the listing does not carry, such as pay, the apply link or a rating, is dropped from the row rather than sent as null. Read fields with a default, and treat nullable in the schema as may be absent.
POWER-USER TIP
Pay floor and Easy Apply are checked before billing — minPay converts hourly, daily, weekly and monthly pay to a yearly figure and compares the top of the range, and jobs with no stated pay are dropped once a floor is set. Easy Apply is checked on each row's own flag. A job filtered out here is never billed.
POWER-USER TIP
Separate stated pay from Indeed's estimates — salaryIsEstimated is true when the range is Indeed's estimate rather than the employer's figure. Filter on it before you benchmark pay, and keep salaryText for the wording the employer used.
POWER-USER TIP
Job types multiply the searches — Each selected job type is searched separately for every keyword, and a run takes the first 20 keyword and job type pairs. With uniqueJobsOnly on, a job that two searches find is returned and billed once.
POWER-USER TIP
Watch a search on a schedule — Set sortBy to date and datePosted to Last 24 hours, run it daily, and dedupe across runs by jobId. Large requests are trimmed to fit the run's time limit and the log says so; split big collections across several runs.

Coverage

62
Indeed country sites — US, GB, CA, AU, IN, DE, FR and 55 more, picked with the country code
1,000
jobs per keyword, search URL or company page, at most — maxResultsPerInput, 50 by default; a run too large for its time limit trims itself and logs it
5
keywords per run — each searched separately and in parallel
100
job or search URLs per run — URL mode; a job posting URL returns one job
10
company jobs pages per run — company mode

Code

Search in one call

curl -X POST "https://api.apify.com/v2/acts/johnvc~indeed-jobs-api/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "search", "keywords": ["data engineer"], "location": "Austin, TX", "datePosted": "Last 7 days", "maxResultsPerInput": 50}'

Python

from apify_client import ApifyClient

client = ApifyClient("APIFY_TOKEN")
run = client.actor("johnvc/indeed-jobs-api").call(
    run_input={"mode": "search", "keywords": ["data engineer"], "location": "Austin, TX", "datePosted": "Last 7 days", "maxResultsPerInput": 50}
)
for row in client.dataset(run.default_dataset_id).iterate_items():
    if row.get("result_type") == "error":
        print("skipped:", row.get("error_message"))
    else:
        print(row.get("jobTitle"), "|", row.get("companyName"), "|", row.get("salaryText"), "|", row.get("jobUrl"))

MCP

claude mcp add --transport http indeed-jobs-api \
  "https://mcp.apify.com/?tools=actors,docs,johnvc/indeed-jobs-api"

Sample job row (synthetic)

{
  "result_type": "job",
  "jobId": "0a1b2c3d4e5f6789",
  "jobTitle": "Senior Data Engineer",
  "companyName": "Example Corp",
  "companyUrl": "https://www.indeed.com/cmp/Example-Corp",
  "companyRating": 4.1,
  "companyReviewsCount": 120,
  "location": "Austin, TX",
  "city": "Austin",
  "state": "TX",
  "country": "US",
  "domain": "www.indeed.com",
  "isRemote": false,
  "workModel": "Hybrid work",
  "jobUrl": "https://www.indeed.com/viewjob?jk=0a1b2c3d4e5f6789",
  "applyUrl": "https://www.indeed.com/applystart?jk=0a1b2c3d4e5f6789",
  "datePosted": "2026-10-04T15:00:00.000Z",
  "datePostedText": "6 days ago",
  "jobType": "Full-time",
  "salaryText": "$140,000 - $165,000 a year",
  "salaryMin": 140000,
  "salaryMax": 165000,
  "salaryPeriod": "YEARLY",
  "salaryCurrency": "USD",
  "salaryIsEstimated": false,
  "benefits": [
    "401(k)",
    "Health insurance",
    "Paid time off"
  ],
  "isSponsored": false,
  "isEasyApply": true,
  "isUrgentlyHiring": false,
  "isHiringMultiple": false,
  "isNew": true,
  "descriptionMarkdown": "## About the role\n\nYou will build and run the batch pipelines behind our reporting.",
  "searchKeyword": "data engineer",
  "searchLocation": "Austin, TX",
  "sourceInput": "data engineer",
  "summary": "Senior Data Engineer at Example Corp in Austin, TX. Pay: $140,000 - $165,000 a year. Full-time. Posted 6 days ago."
}

What people use it for

  • Salary benchmarking by city from parsed Indeed pay ranges
  • Watching one employer's Indeed jobs page for new roles
  • Measuring the remote and hybrid share of postings by role
  • Sales prospecting on hiring signals
  • Enriching hiring employers with industry, size and revenue
  • Feeding an AI recruiting agent Markdown job descriptions

More sources for Hiring signals and talent intelligence, Lead sourcing and CRM enrichment, Grounding AI agents and MCP tools →

Alternatives