Indeed Job Listings Scraper with Salaries avatar

Indeed Job Listings Scraper with Salaries

Pricing

from $1.50 / 1,000 results

Go to Apify Store
Indeed Job Listings Scraper with Salaries

Indeed Job Listings Scraper with Salaries

Scrape Indeed job postings by search term and location across the US, UK, Canada, Australia and Germany. Every row carries the job title, company, location, the salary the employer stated in the posting, employer rating and review count, the posting date and a direct job URL.

Pricing

from $1.50 / 1,000 results

Rating

0.0

(0)

Developer

String

String

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Share

Turn an Indeed search into rows โ€” every job card on the page, with the salary the employer actually wrote and the company's rating beside it.

What can Indeed Job Scraper do?

Give it search terms, optionally a location, and a country, and it returns one row per posting.

๐Ÿ”Ž Search like a visitor, read like a machine. Each search is one results page read from Indeed's own JSON payload, so every card reaches the dataset โ€” not the subset a markup parse recovers.

๐Ÿ’ฐ The employer's own salary. salary is what the posting states, e.g. $150,000 - $185,000 a year, and null when it states none. Indeed's estimate is never substituted for it.

โญ Company rating and review count on every row, so you can filter by employer reputation without a second lookup.

๐ŸŒ Five countries from one field. us, uk, ca, au and de.

๐Ÿ“… A real timestamp. postedAt is ISO 8601, converted from Indeed's own pubDate.

๐Ÿ”‘ A stable jobKey. Indeed's own id, so a daily run de-duplicates cleanly.

๐Ÿšซ No login. No Indeed account, cookie or API key at any point.

Why scrape Indeed?

Compensation research is the common one. salary, location and title together give you employer-stated pay for a role across cities, with none of Indeed's own estimate mixed in, which is the difference between a benchmark you can defend and one you cannot.

The rest of what people do with it:

  • Watch a competitor's roles weekly and see which teams are growing. company and postedAt date the shift.
  • Fill a job board or an ATS with live postings, apply link already attached.
  • Sort employers by how their own staff rate them, using companyRating and companyReviewCount, before anyone on your side makes an approach.
  • Count postings per title per city over months to see where demand for a skill is moving.

How to use it

  1. Open the Actor on Apify Store and click Try for free.
  2. Put your search terms in Search queries. One term per line, up to 50. "software engineer", "registered nurse", "warehouse associate".
  3. Set Location if you want the search narrowed, e.g. "Austin, TX" or "London". Leave it empty for a nationwide search.
  4. Set Country to the Indeed domain you want: us, uk, ca, au or de. One run searches one country.
  1. Click Start and watch the log. Each search reports as it finishes.
  2. Open the Dataset tab when the run ends and export to JSON, CSV, Excel or the API. Failed searches, if any, are listed in the SUMMARY record in the key-value store.

To keep the data current, save the input as a task and put it on an Apify schedule. Join runs on jobKey and you get a clean history of when each posting appeared and disappeared.

Output

One row per job. This is the shape, with values chosen to illustrate it rather than captured from a particular run.

{
"jobKey": "0000aaaa1111bbbb",
"title": "Senior Software Engineer",
"company": "Northwind Logistics",
"location": "Austin, TX 78701",
"salary": "$150,000 - $185,000 a year",
"companyRating": 3.7,
"companyReviewCount": 1284,
"postedAt": "2026-08-14T00:00:00.000Z",
"jobUrl": "https://www.indeed.com/viewjob?jk=0000aaaa1111bbbb",
"query": "software engineer",
"country": "us",
"searchLocation": "Austin, TX",
"sourceUrl": "https://www.indeed.com/jobs?q=software+engineer&l=Austin%2C+TX",
"collectedAt": "2026-08-20T09:31:02.118Z"
}

Reliability

Measured across 30 distinct Indeed job searches in one run: 29 of 30 searches succeeded and 1,132 jobs were collected, with every schema field populated.

Because the rows come from Indeed's own payload, a field is either present and correct or null. There is no model in the path to paraphrase a job title or round a rating.

A search that cannot be read is recorded in the run's SUMMARY under failures with the URL and the error, and the rest of the run still returns its rows. A run in which every search failed exits with an error rather than finishing quietly with an empty dataset.

Limitations

One results page per search, so a run collects the first page for each term rather than paginating a whole market. That is roughly 39 jobs per search. Widen coverage by running several narrower queries, for example by title and city, instead of one broad one.

Full job descriptions, application counts and recruiter contact details are out of scope. Follow jobUrl for the description. One run covers one country.

How much does it cost?

A run that returns 1,000 rows costs $2.00 on a paid plan, or $2.25 with no subscription. You are charged per result row written to the dataset, so a run that returns nothing costs nothing, and maxItems is the budget dial.

PlanPer 1,000 rows
Free$2.25
Bronze$2.00
Silver$1.75
Gold$1.50
Platinum$1.00
Diamond$0.75

Apify bills its own platform usage for the run on top of this.

A search that fails writes no rows and therefore charges nothing for that search. A run capped by maxItems charges only for the rows it kept.

Runs started from an Apify free plan stop at 250 requests and 250 results, and the run reports that it reached the limit in its status message. Any paid plan runs the full input and whatever maxItems you set. The limit exists because this Actor fetches through our own anti-bot infrastructure, which Apify does not cover for free-plan runs. It binds on requests as well as rows so that a long input list cannot spend those fetches on rows the run will never return.

Using it with the Apify API

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('usestring/indeed-jobs').call({
queries: ['software engineer', 'data analyst'],
location: 'Austin, TX',
country: 'us',
maxItems: 500
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const withPay = items.filter((job) => job.salary !== null);
console.log(`${items.length} jobs, ${withPay.length} with an employer-stated salary`);

The same call works from the Python client, and from any HTTP client through the Apify REST API. The run's SUMMARY record, holding the item count and any failed searches, is in the run's default key-value store.

Pair the Indeed scraper with Glassdoor for the same role and you can compare employer-stated pay against Glassdoor's numeric ranges for the same companies.

FAQ

Do I need an Indeed account or API key? No. The Actor reads public Indeed search pages with no account, login, cookie or key.

How many jobs does one search return, and can I paginate? Around 39, which is what a single Indeed results page carries, and there is no pagination input. Ten search terms return roughly 390 jobs. To go deeper into a market, split the query: by seniority, by city, or by a more specific title.

Which countries are supported? Five, selected with country: the United States, United Kingdom, Canada, Australia and Germany. Each maps to Indeed's own domain for that country. A run searches one of them, so use one run per country.

Is the salary real or Indeed's estimate? Real. salary is the string from the posting itself and is null when the employer stated no pay. The estimated-salary panel Indeed renders beside the results is deliberately ignored, so an empty salary means the employer was silent rather than that the Actor guessed wrong.

How fresh are the results? Each run fetches live at the moment it starts. postedAt carries Indeed's publication date and collectedAt the run timestamp, so you can measure how old a posting was when you saw it.

What happens if Indeed blocks or a search fails? Requests go through our own anti-bot infrastructure, and a search that still cannot be read is recorded under failures in the run's SUMMARY with its URL and error. Other searches in the run are unaffected. If every search fails, the run ends in an error state so a schedule notices.

Can I get the full job description? No. This Actor reads the search results page and does not open each posting. jobUrl takes you there.

Feedback

Something wrong in the data, or a field you need that is not here? Open an issue on the Actor's Store page and we will read it. Bug reports that name the search term, country and date are the fastest to act on.