DEV Community

Cover image for How to Scrape Indeed Jobs in 2026 (Python + a No-Code Shortcut)
Factden
Factden

Posted on

How to Scrape Indeed Jobs in 2026 (Python + a No-Code Shortcut)

Scraping Indeed sounds simple until you try it. There is no public API anymore, the site sits behind Cloudflare, and the salary you actually want arrives as a messy string like "$120,000 - $160,000 a year". This guide covers what you can pull from an Indeed job, why the DIY route is harder than it looks, working Python, a no-code shortcut, and a straight comparison so you can pick a lane. If you want the deeper reference, there is a full guide to scraping Indeed jobs too.

What you can pull from an Indeed job

Per listing you can get:

  • Title, company, and location (plus city, state, country code, and lat/long)
  • Salary, parsed into numbers: salaryMin, salaryMax, salaryPeriod, currency, not just the raw string
  • Job type, remote/hybrid flag, and the full description text
  • Benefits, date posted, easy-apply and urgent-hire flags
  • Company data on demand: rating, review count, industry, size, revenue, founded, website, and socials

Parsed salary and company enrichment are the two things people actually come for, and the two things a naive scrape gets wrong.

Why scraping Indeed is hard

Three reasons DIY is more work than it looks:

  1. There is no official API. Indeed retired its public job-search API to new developers years ago, so there is no supported programmatic route. Scraping is the only option left.
  2. Cloudflare and rate limits. A plain request to a search results page tends to return a 403 or a challenge. Hammer it and you get blocked fast.
  3. Messy salary strings. Indeed shows salary as free text. Turning "$120,000 - $160,000 a year" into clean salaryMin/salaryMax/period reliably, across currencies and 40 countries, is fiddly.

So the work is not the parsing of one page. It is staying unblocked, normalizing salary, and pulling company data from separate pages, on repeat.

Three ways to get Indeed job data

DIY Python Indeed Jobs Scraper (actor) Indeed Official API
Setup time Hours to days ~30 seconds Not available (retired)
Anti-bot handled You (Cloudflare, blocks) Built in n/a
Salary as numbers You parse the string Yes: salaryMin / salaryMax n/a
Company data Separate scrape Free, one toggle n/a
Countries You handle localization 40+ n/a
Cost Proxies + eng time Pay-per-result n/a
Best for One-off search Scheduled, at scale Not an option

The official-API column is the real story: since Indeed closed its API, a scraper (yours or a ready-made one) is the only way to get this data programmatically.

Option A: DIY in Python

See the wall first:

import httpx

url = "https://www.indeed.com/jobs?q=software+engineer&l=New+York"
r = httpx.get(url, headers={"User-Agent": "Mozilla/5.0"})
print(r.status_code)   # often 403 / Cloudflare challenge
Enter fullscreen mode Exit fullscreen mode

If you do get HTML back, the job cards parse roughly like this (selectors change often, so re-check against the live page):

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, "html.parser")
for card in soup.select("div.job_seen_beacon"):
    title = card.select_one("h2.jobTitle")
    comp  = card.select_one("[data-testid='company-name']")
    sal   = card.select_one("[data-testid='attribute_snippet_testid']")
    print(
        title.get_text(strip=True) if title else None,
        comp.get_text(strip=True) if comp else None,
        sal.get_text(strip=True) if sal else None,   # raw string, still needs parsing
    )
Enter fullscreen mode Exit fullscreen mode

Then you still have to normalize that salary string into numbers, follow each job to its full description, and scrape the company page separately. For one search that is fine. For a pipeline, the upkeep adds up.

Option B: the no-code / API shortcut

When you just want clean rows, the Indeed Jobs Scraper on Apify talks to Indeed's structured endpoints (no fragile HTML path), handles the blocking, and returns parsed JSON. No login, no proxy setup.

From Python:

from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("factden/indeed-jobs-scraper").call(run_input={
    "query": "software engineer",
    "location": "New York, NY",
    "country": "US",
    "maxItems": 200,
    "salaryMin": 120000,     # native salary-range filter
    "scrapeCompany": True,   # attach company profiles for free
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["company"], job["salaryMin"], job["salaryMax"])
Enter fullscreen mode Exit fullscreen mode

Set country to any of 40+ codes (US, GB, IN, DE, SG, ...), filter by remote, datePosted, jobType, or experienceLevel, or pass startUrls / jobKeys to fetch specific listings.

What comes back: 26 structured fields per job

Group Fields
Core title, company, location, city, state, countryCode, url, jobKey
Salary salary (raw), salaryMin, salaryMax, salaryPeriod, currency
Job detail jobType, remote, occupations, benefits, description, datePosted, isUrgentHire, easyApply
Geo latitude, longitude
Company (with scrapeCompany) companyRating, companyReviewCount, companyPageUrl + a full company profile (industry, size, revenue, founded, website, socials)

A trimmed sample row:

{
  "title": "Senior Software Engineer",
  "company": "Plaid",
  "location": "New York, NY",
  "salary": "$120,000 - $160,000 a year",
  "salaryMin": 120000,
  "salaryMax": 160000,
  "salaryPeriod": "year",
  "currency": "USD",
  "jobType": ["Full-time"],
  "remote": "remote",
  "benefits": ["Health insurance", "401(k)"],
  "datePosted": "2026-06-10",
  "companyRating": 4.2,
  "url": "https://www.indeed.com/viewjob?jk=6d50b3ebeb3fb122",
  "jobKey": "6d50b3ebeb3fb122"
}
Enter fullscreen mode Exit fullscreen mode

The numeric salary fields and the on-demand company profile are what make this usable for labor-market analysis without a cleanup pass. Full field list and snippets are in the GitHub repo.

Grab a free sample dataset

Want to see the data first? There is a free Indeed jobs sample (CSV/JSON) here: factden.com/sample-indeed. Drop it into pandas and the parsed salary columns are ready to plot.

FAQ

Is scraping Indeed legal? The listings are publicly visible. As with any scraping, check Indeed's Terms of Service and your local rules (especially around personal data), and use the data responsibly.

Does Indeed have an API? Not a usable one. Indeed closed its public job-search API to new developers, which is exactly why people scrape the public pages now.

How do I stop getting blocked? Residential proxies, real headers, and slow pacing, or a tool that talks to Indeed's structured endpoints instead of scraping HTML. Plain requests to the search pages will get challenged.

Can I get salary as numbers? Yes. salaryMin, salaryMax, salaryPeriod, and currency are parsed from the raw string, so you can filter and aggregate directly.

Can I get company data too? Yes. Turn on scrapeCompany and each job carries the company's rating, size, industry, revenue, and profile links, no second scrape needed.

Which countries are supported? 40+, including US, UK, Canada, India, Germany, Singapore, Australia, and more, via the country code.

Related

Questions, or a field you wish it extracted? Drop a comment.

Top comments (0)