# Indeed Company Reviews Scraper — Employee Reviews (`kestrel/indeed-company-reviews`) Actor

Every Indeed employee review of any company: the 1-5 rating with five sub-ratings (work-life balance, pay, job security, management, culture), full text, pros, cons, job title, location, dates and employer replies. Company slugs or /cmp/ URLs, 44 country domains. No key, no login. Pay per review.

- **URL**: https://apify.com/kestrel/indeed-company-reviews.md
- **Developed by:** [Tedj MEABIOU](https://apify.com/kestrel) (community)
- **Categories:** Lead generation, AI, Jobs
- **Stats:** 9 total users, 8 monthly users, 95.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 review rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Indeed Company Reviews Scraper — every employee review of any company

This Indeed company reviews scraper turns any company page on Indeed into a clean dataset of employee reviews: the 1-5 star rating, the five sub-ratings, the headline and the full text, pros and cons, the reviewer's job title and location, whether they still work there, the date, the helpful votes and the employer's public reply. Give it company slugs or `/cmp/` URLs and it walks every page for you. It is a plain HTTP scraper — no API key, no login, no browser — so a run of company reviews costs a fraction of what a headless-browser scraper costs, and the same job runs the same way whether you want employer reviews for one company or for a thousand.

Last verified working: 2026-08-29.

### Indeed company reviews at a glance

| | |
|---|---|
| **What you give it** | Company slugs (`Google`, `Home-Depot`) or company URLs (`https://www.indeed.com/cmp/Starbucks/reviews`) |
| **What you get** | One row per employee review + a free company row + a free status row per company and country |
| **Reviews per page** | 20, walked automatically until the cap or the end |
| **Country domains** | 44, plus `all` — nearly every review of a company in a single walk |
| **Price** | $0.002 per review. Company rows, status rows, empty companies and filtered reviews are free |
| **Speed** | ~1 page per second per session, 20 reviews per page |
| **Needs a browser?** | No. No API key, no cookie, no login |

### What does the Indeed Company Reviews Scraper do?

Indeed publishes employee reviews on a company page at `indeed.com/cmp/<Company>/reviews`. Each review carries far more structure than a star rating: the reviewer grades work-life balance, compensation and benefits, job security and advancement, management and culture separately, writes a headline and a body, may fill in a Pros and a Cons field, and is tagged with a job title, a location and whether they are a current or former employee. Employers can reply publicly, and other readers vote reviews helpful or unhelpful.

This scraper reads all of that, one company at a time, and writes it to a dataset you can export as JSON, CSV, Excel or XML, or read straight from the API. It also collects the aggregate picture Indeed shows in the sidebar — the overall score, the 1-5 star histogram, the five category averages, the Work Happiness score, the topic breakdown and the pros and cons Indeed extracts from the whole corpus — and puts it in one free company row, so you get the company ratings and the individual reviews in the same run.

Typical uses:

- **Employer brand tracking.** Watch what current and former staff say about you and about the companies you compete with for the same talent.
- **Employee feedback analysis.** Feed the text into a topic model or an LLM and find out which of the five categories is actually dragging the score down.
- **Recruitment marketing.** Quote real strengths, and fix the objections candidates read before they apply.
- **Due diligence and market research.** Culture and management scores across an industry, an acquisition target, or a franchise network location by location.
- **Review monitoring.** Run it on a schedule with `sinceDate` and get only what is new since yesterday — employer reputation monitoring without a vendor contract.
- **Indeed negative reviews only.** Lowest-rated first with a rating ceiling gives a complaints feed you can route to whoever owns the fix.

### How do I run the Indeed reviews scraper?

Open the actor, paste one or more companies into **Indeed companies**, and hit Start. Everything else has a working default. The three inputs that matter most are `companies`, `countries` and `maxReviewsPerCompany`.

The slug is the part of the URL after `/cmp/`. Both of these are the same company, and you can mix them freely:

```json
{
  "companies": ["Google", "https://www.indeed.com/cmp/Starbucks/reviews"],
  "countries": ["us"],
  "maxReviewsPerCompany": 200,
  "sort": "newest",
  "includeCompanyRow": true
}
```

From Python, with the Apify client:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("kestrel/indeed-company-reviews").call(run_input={
    "companies": ["Google", "Starbucks"],
    "countries": ["us"],
    "maxReviewsPerCompany": 500,
    "sort": "rating_asc",
    "maxRating": 2,
    "requireText": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["type"] == "review":
        print(row["rating"], row["job_title"], "|", row["title"])
```

From JavaScript / Node:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('kestrel/indeed-company-reviews').call({
    companies: ['Google'],
    countries: ['all'],
    maxReviewsPerCompany: 1000,
    sinceDate: '90 days',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.type === 'review').length, 'employee reviews');
```

And from curl, if you just want to download Indeed reviews as CSV in one command:

```bash
curl -X POST "https://api.apify.com/v2/acts/kestrel~indeed-company-reviews/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>&format=csv" \
  -H 'Content-Type: application/json' \
  -d '{"companies":["Google"],"countries":["us"],"maxReviewsPerCompany":100}' \
  -o indeed-reviews.csv
```

### Input reference

Every field below is optional except `companies`, and every one of them has a sensible default.

**Which companies**

- `companies` — Indeed company slugs or `/cmp/` URLs. A URL that names a country domain (`https://ca.indeed.com/cmp/Google`) is read on that domain only; a bare slug uses the `countries` list. Duplicates are recognised and billed once.
- `countries` — which Indeed domains to read each company on. Default `["us"]`. See the section below.

**Which reviews**

- `maxReviewsPerCompany` — `0` takes every review the chosen domains list; `N` takes the first `N` in the chosen order, counted across all countries. Default 100. This is the main cost control.
- `sort` — `newest` (default), `helpfulness`, `rating_desc` (highest first) or `rating_asc` (lowest first). Indeed silently ignores any other value and serves newest first, which is why this is a fixed list rather than free text.
- `minRating` / `maxRating` — keep only reviews at or above / at or below a 1-5 star rating. `0` means no bound.
- `requireText` — drop rating-only reviews.
- `jobTitleContains` — case-insensitive substring of the reviewer's job title, e.g. `engineer`, `nurse`, `driver`.
- `locationContains` — case-insensitive substring of the review's location, e.g. `Mountain View`, `TX`.
- `sinceDate` — `YYYY-MM-DD` or a relative string such as `30 days`, `2 weeks`, `6 months`, so a scheduled run never goes stale.
- `includeCompanyRow` — emit the free company row (default on). This costs one extra free request per company, to the company overview page, which is where industry, size, headquarters, website, founded year, revenue band and CEO live.

**Performance**

- `sessions` — how many proxy sessions (egress IPs) run in parallel. Default 2.
- `perIp` — requests per second per session. Default 1, which was measured clean over ten consecutive pages.
- `proxyConfiguration` — Apify Proxy with the datacenter group by default. Residential works and costs much more; keep the default.

Two notes on where the filters run. `minRating`, `maxRating`, `requireText`, `jobTitleContains`, `locationContains` and `sinceDate` are applied inside the actor, before billing, so a review a filter drops is never charged. `sort` is applied by Indeed itself. The combination is what makes a complaints feed cheap: `sort: "rating_asc"` with `maxRating: 2` puts the one- and two-star reviews on the first page and stops the walk as soon as a whole page is above the ceiling.

### Review rows: every field this Indeed scraper returns

Three row types share one dataset and are told apart by `type`.

**`type: "review"` — charged, $0.002 each**

| Field | What it is |
|---|---|
| `review_id` | Indeed's stable encrypted review id, also the id in the review URL |
| `company` | The company slug, the part after `/cmp/` |
| `company_name` | Company name as Indeed displays it |
| `country` | Which domain the row was read on: `us`, `all`, `ca`, `de`, … |
| `rating` | Overall rating, 1-5 stars |
| `work_life_balance` | The reviewer's 1-5 rating for work/life balance, or null if they skipped it |
| `compensation_benefits` | Their 1-5 rating for pay and benefits, or null |
| `job_security_advancement` | Their 1-5 rating for job security and advancement, or null |
| `management` | Their 1-5 rating for management, or null |
| `culture_values` | Their 1-5 rating for culture, or null |
| `title` | The headline the employee wrote |
| `text` | The full review body, untruncated |
| `pros` | The Pros field, when the review was submitted with the pros/cons form |
| `cons` | The Cons field, likewise |
| `job_title` | The reviewer's job title |
| `location` | Where they worked, e.g. `Mountain View, CA` |
| `review_country` | ISO country code Indeed files the review under |
| `employment_status` | `current` or `former` |
| `review_date` | Publication date as `YYYY-MM-DD` |
| `review_date_text` | The date exactly as Indeed printed it, in that domain's language |
| `helpful_count` | How many readers voted it helpful |
| `unhelpful_count` | How many voted it not helpful |
| `employer_reply` | The employer's official public response, if any |
| `employer_reply_date` | Date of that response |
| `url` | Direct link to the review |

**`type: "company"` — free, one per company**

`review_count` (all reviews Indeed holds worldwide), `found_review_count` (what the domain you read actually lists), `rating`, `histogram` (how many gave 1, 2, 3, 4 and 5 stars), `ratings_breakdown` (the company averages for the same five categories), `happiness_score` and `happiness_grade` (Indeed's Work Happiness measure), `top_pros` and `top_cons` (what Indeed extracts from the corpus), `topics` (name, rating and count per theme), `industry`, `company_size`, `headquarters`, `website`, `founded`, `revenue`, `ceo`, `reviews_fetched` and `company_url`.

**`type: "status"` — free, one per company and country**

`target`, `company`, `company_name`, `country`, `status` (`ok`, `no_reviews`, `not_found`, `duplicate` or `error`), `reviews` delivered and charged, `filtered` dropped before billing, `pages` read, `total` reviews Indeed holds worldwide, `found_review_count`, `duplicates` and `error`. This row is the contract: if a company could not be read, you get `status: "error"` with the reason, never a silent empty result that looks like a company with no reviews. The run also writes a `SUMMARY` record to the key-value store with the same counts for the whole run.

The dataset ships with five views in the Output tab: **Overview**, **Reviews**, **Complaints** (rating, cons, management and work-life-balance scores, and the employer reply side by side), **Companies** and **Status**.

### Company reviews across 44 Indeed country domains

This is the part people usually get wrong. Indeed does not serve one global review list. `www.indeed.com` shows the reviews visible in the United States — 4,044 of Google's 6,258 on the day this was verified — while `ca.indeed.com` shows 186, `uk.indeed.com` 215 and `de.indeed.com` 13, each in that country's language. The subsets barely overlap.

So `countries` is a multiplier, and it has one special value:

- `"us"` — `www.indeed.com`, the US-visible subset. The default.
- `"all"` — `www.indeed.com` with Indeed's own worldwide filter. For Google that is 6,257 of 6,258 reviews in a single walk. **If you want everything for a company, this is the cheapest way to get it.**
- Any of `ca`, `uk`, `ie`, `au`, `nz`, `in`, `sg`, `ph`, `za`, `ae`, `hk`, `id`, `th`, `vn`, `lu`, `ch`, `be`, `de`, `at`, `fr`, `nl`, `es`, `it`, `pt`, `br`, `mx`, `ar`, `cl`, `co`, `pe`, `pl`, `se`, `dk`, `no`, `fi`, `tr`, `gr`, `hu`, `cz`, `ro`, `ua`, `jp`, `tw` — that country's own subset, in that country's language.

List several and they are walked in order until the cap is met. A review that appears on two domains is delivered and charged **once**: the run keeps one set of review ids per company. Dates are converted to `YYYY-MM-DD` whatever language they arrive in — `3. September 2025`, `2026, augusztus 25.` and `2026年2月27日` all resolve — and the original string is kept in `review_date_text` so nothing is lost.

```json
{
  "companies": ["Google"],
  "countries": ["all"],
  "maxReviewsPerCompany": 0,
  "sort": "newest"
}
```

### Employee reviews for employer brand and HR analytics

The five sub-ratings are what make this dataset useful rather than merely large. An overall score of 3.8 says nothing actionable; `management: 2` against `compensation_benefits: 4` says exactly where the problem is, and `job_title` plus `location` says for whom and where.

A few patterns that work well:

- **Category deltas over time.** Group by month and average each sub-rating. A management score sliding while pay holds steady is a leadership problem, not a budget one.
- **Role-level segmentation.** `jobTitleContains: "nurse"` or `"driver"` isolates the population you actually recruit, instead of averaging it with head office.
- **Site-level segmentation.** `locationContains` does the same for one plant, store or region — the level at which employee feedback usually becomes actionable.
- **Competitive employer brand.** Run the same input across five competitors and compare histograms rather than headline scores; a 4.0 built from mostly 5s and a few 1s is a very different workplace from a flat 4.0.
- **Response coverage.** `employer_reply` is empty on most reviews at most companies. The share of negative reviews you have answered is a cheap, honest employer-brand metric.
- **Employee sentiment analysis.** `text`, `pros` and `cons` are full length and untruncated, which is what a topic model or an LLM needs.

### Why is this a Glassdoor alternative?

Because Glassdoor is, in practice, unreadable without an account. Its review pages answer an interactive Cloudflare challenge to every ordinary client, and its paging URLs redirect to a login wall for anonymous visitors. Any tool that promises bulk Glassdoor data is either logging in as somebody, paying a challenge-solving vendor, or quietly returning very little.

Indeed publishes the same kind of workplace review data openly: the same five categories, the same current/former split, the same employer responses, at a far larger scale for hourly and frontline roles in particular. For most employer-brand, recruitment and market-research questions, Indeed company data is the better source and it is the one you can actually collect at volume. If you need consumer-side reputation as well, pair this with the [Trustpilot Reviews Scraper](https://apify.com/kestrel/trustpilot-reviews-scraper); if your product is an app, the [App Store Reviews Scraper](https://apify.com/kestrel/app-store-reviews-scraper) covers the other side of the same story.

### How much does it cost?

$0.002 per review row, and nothing else. There is no monthly rental and no per-run fee.

| You want | Input | Reviews | Cost |
|---|---|---|---|
| A quick look at one company | `maxReviewsPerCompany: 100` | 100 | $0.20 |
| One company, everything the US domain lists | `countries: ["us"], maxReviewsPerCompany: 0` | ~4,000 | ~$8.00 |
| One company, everything worldwide | `countries: ["all"], maxReviewsPerCompany: 0` | ~6,250 | ~$12.50 |
| Daily monitoring of 20 employers | `sinceDate: "1 day"` | ~40 | $0.08 |
| A complaints-only feed | `sort: "rating_asc", maxRating: 2, maxReviewsPerCompany: 200` | 200 | $0.40 |

Free, always: the company row, the status rows, a company that has no reviews, an unknown company, and every review a filter dropped before billing. The run bills for exactly the review rows it delivers — that invariant is asserted in the test suite across every input mode and every spending limit.

### Integrations: n8n, Make, MCP and AI agents

- **n8n** — use the Apify node, pick this actor, map the JSON input above, then filter on `type == "review"` in a following node.
- **Make** — the Apify app's *Run an Actor* module followed by *Get Dataset Items*; set the input to the same JSON.
- **MCP / AI agents** — Apify's MCP server exposes this actor as a tool, so an AI agent can ask for "the last 50 reviews of Starbucks by former employees" and get structured rows back. The `SUMMARY` record and the status rows give the agent an honest signal about what it actually got.
- **Zapier, Webhooks, scheduling** — standard Apify plumbing. A daily schedule with `sinceDate: "1 day"` reads one page per company and costs cents.
- **Straight to a warehouse** — the dataset API serves CSV, JSON, XML and Excel; the CSV column set is stable because every row of a type carries every field.

### Is scraping Indeed reviews legal?

Short answer: the data is public and collecting it is generally lawful in the EU and the US, but it is personal data about identifiable people, and how you use it is where the legal risk lives. Nothing here is legal advice — take your own.

What we can say plainly:

- **This actor reads only what any visitor can read.** No login, no account, no paywall, no private endpoint. It does not collect anything Indeed hides from an anonymous reader.
- **Employee reviews are personal opinions written by real people.** A review carries a job title, a location, a date and an employment status. At a small employer, or for an unusual role, that combination can identify an individual even though no name is published. Treat every row as personal data under the GDPR and equivalent laws.
- **Do not try to re-identify reviewers.** Do not join these rows against your HR system, your rota, your leaver list or LinkedIn to work out who wrote what. That is the single most likely way to turn a legitimate analysis into an unlawful one — and, at many employers, a retaliation problem as well.
- **Have a lawful basis and minimise.** If you are relying on legitimate interests, aggregate analysis of your employer brand is a much easier case to make than storing individual reviews indefinitely. Keep what you need, for as long as you need it, and no longer.
- **Publishing is a separate question.** Reproducing review text verbatim raises copyright and database-right questions on top of privacy ones. Aggregates, scores and short quotes with attribution are far safer than republishing corpora.
- **Respect Indeed's terms and be polite.** The defaults here are deliberately gentle — one request per second per session — and there is no reason to raise them.

### Limits and known traps

- **A page past the end silently repeats page one.** Indeed answers `?start=` beyond the last page with HTTP 200 and the first twenty reviews again, never an error. A naive scraper pages forever and bills you for the same rows over and over. This actor bounds the walk three ways — by the review count Indeed declares, by the page number Indeed reports, and by review ids it has already seen — so it stops on the first repeated page and charges you for nothing extra.
- **Roughly one fresh session in three is refused.** Indeed puts a Cloudflare check in front of some connections. The actor rotates the proxy session and retries; a session that is served once keeps being served. If every retry is refused, the company gets `status: "error"` with the reason — never a fake empty result.
- **A sub-rating of `0` means "not rated", not zero stars.** Indeed writes `0` when a reviewer skipped a category. Those become `null` here, so an average is not silently dragged to the floor.
- **Counts differ by domain.** `review_count` is what Indeed holds worldwide; `found_review_count` is what the domain you read actually lists. They are supposed to differ.
- **A handful of Indeed hosts are not country domains.** `my.indeed.com` is the account subdomain and serves a sign-in page, so Malaysia is not in the list; a few other hosts have no company section at all. Only verified domains are offered.
- **Dates in a language we have not met.** Every domain in the list was checked, and the raw string is always kept in `review_date_text`; if a format ever changes, `review_date` becomes null rather than wrong, and `sinceDate` keeps such a review rather than silently dropping it.
- **Reviews are moderated by Indeed.** Only approved reviews appear on the page, so this is Indeed's published corpus, not every review ever submitted.

### FAQ

#### How do I find a company's Indeed slug?

Search the company on Indeed, open its page, and copy the part of the URL after `/cmp/` — `https://www.indeed.com/cmp/Home-Depot` gives `Home-Depot`. You can also paste the whole URL; the actor extracts the slug for you. That slug is how you ask for Indeed reviews by company rather than by keyword.

#### Can I get all Indeed reviews for a company, not just the US ones?

Yes: set `countries` to `["all"]` and `maxReviewsPerCompany` to `0`. That reads `www.indeed.com` with Indeed's worldwide filter and returns essentially the complete corpus in one walk.

#### How do I export Indeed reviews to CSV?

Run the actor, open the run's Storage tab and choose CSV, or add `&format=csv` to the dataset API call as in the curl example above. Every review row carries the same fields, so the Indeed reviews CSV has stable columns and can be loaded straight into a spreadsheet or a warehouse.

#### Can I get only the negative reviews?

Set `sort` to `rating_asc` and `maxRating` to `2`. The lowest-rated reviews arrive first and the walk stops at the first page above the ceiling, so you pay only for the complaints.

#### Does it return the employer's replies?

Yes — `employer_reply` and `employer_reply_date`, when the company has responded. Indeed employer replies are missing from most reviews at most companies, which is itself a useful metric: the share of one- and two-star reviews you have answered.

#### How do I monitor new reviews every day?

Schedule the actor with `sinceDate: "1 day"` and the default newest-first order. The walk stops at the first page older than the cut, so each company costs one page.

#### Is there an Indeed employee reviews API?

Not a public one. This actor is the practical substitute, and it reads Indeed reviews without an API key of any kind: a stable JSON contract over the public company pages, with paging, retries and the wrap-around trap handled for you.

#### What happens if a company has no reviews?

You get a `status` row with `no_reviews` and `found_review_count: 0`, plus the free company row, and you are charged nothing.

#### Do I need proxies or my own API key?

No key. Proxies come from Apify Proxy and the datacenter group is the default and is enough — this needs no residential traffic and no browser.

#### How fast is it?

About one page — twenty reviews — per second per session, so roughly 1,200 reviews per minute at the default two sessions. Raise `sessions` for bulk company reviews across many employers.

#### Can I scrape Indeed reviews for many companies at once?

Yes. Put every slug in `companies`; they are processed in parallel across your sessions, duplicates are recognised, and the per-company cap applies to each one independently.

### Related scrapers

Indeed is the employee's view of a company. These read the customer's, with the same row discipline and the same pay-per-delivered-row billing:

- [Trustpilot Reviews Scraper](https://apify.com/kestrel/trustpilot-reviews-scraper) — the same company as its customers see it: reviews and TrustScore from Trustpilot, past the 200-review wall an anonymous reader normally hits.
- [App Store Reviews Scraper](https://apify.com/kestrel/app-store-reviews-scraper) — Apple App Store reviews of the company's apps across every country storefront in one run, with rating filters that run before billing.
- [Google Play Reviews Scraper](https://apify.com/kestrel/google-play-reviews-scraper) — the Android half: Play Store reviews per language and country, matching columns.
- [Amazon Reviews Scraper](https://apify.com/kestrel/amazon-reviews-scraper) — customer reviews and ratings of the company's products by ASIN, when it sells on Amazon.
- [TripAdvisor Reviews Scraper](https://apify.com/kestrel/tripadvisor-reviews-scraper) — guest reviews with six sub-ratings and the management response, when the employer is a hotel or a chain and its customers talk there instead.

All of them bill per delivered row, never charge for rows a filter or a spending limit removed, and write an Apify dataset you can export to CSV, Excel or JSON.

# Changelog

This Actor's version history is a separate document: https://apify.com/kestrel/indeed-company-reviews/changelog.md

# Actor input Schema

## `companies` (type: `array`):

Indeed company slugs or company URLs, e.g. Google, Home-Depot, https://www.indeed.com/cmp/Starbucks/reviews or https://ca.indeed.com/cmp/Google. The slug is the part after /cmp/ on any Indeed company page. A URL that names a country domain (ca.indeed.com, uk.indeed.com) is read on that domain only; a bare slug uses the countries below. At least one.

## `countries` (type: `array`):

Which Indeed domain to read each company on. "us" is www.indeed.com, which shows only the US-visible reviews (4,044 of Google's 6,258). "all" is www.indeed.com with Indeed's own fcountry=ALL filter and returns nearly every review in one walk (6,257 of 6,258) — the cheapest way to get everything. Per-country codes read that domain's own subset in that country's language: ca, uk, ie, au, nz, in, sg, ph, za, ae, hk, id, th, vn, lu, ch, be, de, at, fr, nl, es, it, pt, br, mx, ar, cl, co, pe, pl, se, dk, no, fi, tr, gr, hu, cz, ro, ua, jp, tw. Several domains together multiply the catalogue; reviews served by more than one domain are delivered and charged once.

## `maxReviewsPerCompany` (type: `integer`):

0 = every review the chosen domains list (Indeed pages them 20 at a time; a large employer runs to tens of thousands). N = the first N in the order below, counted across all the countries you asked for. The main cost control.

## `sort` (type: `string`):

The order Indeed returns reviews in. newest = most recent first (Indeed's default). helpfulness = the reviews other people voted most helpful. rating\_desc = highest rated first. rating\_asc = lowest rated first, which puts the complaints on page one. These four are the only values Indeed honours — every other string is silently ignored and served as newest first, so this is an enum.

## `minRating` (type: `integer`):

Indeed rates each review 1-5 stars. 0 = no floor, 4 keeps only the positive ones. Combine with sort = highest rated first and the walk stops as soon as a whole page falls below the floor. Filtered reviews are never charged.

## `maxRating` (type: `integer`):

The other end of the same 1-5 star scale: 0 = no ceiling, 2 gives a complaints feed. Combine with sort = lowest rated first so the worst reviews arrive on page one and the walk stops once a whole page is above the ceiling. Filtered reviews are never charged.

## `requireText` (type: `boolean`):

Drop rating-only reviews before billing. Indeed reviews almost always carry a paragraph, so this rarely removes much.

## `jobTitleContains` (type: `string`):

Case-insensitive substring of the reviewer's job title, e.g. "engineer", "nurse", "driver". Empty = every job title. Indeed's own fjobtitle filter needs an exact normalised title, so this one runs in the actor: the pages are read either way and the reviews it drops are simply never charged.

## `locationContains` (type: `string`):

Case-insensitive substring of the review's location, e.g. "Mountain View", "TX", "London". Empty = every location. Like the job-title filter this runs in the actor, before billing.

## `sinceDate` (type: `string`):

YYYY-MM-DD, or relative so schedules never go stale: "30 days", "2 weeks", "6 months". With the default newest-first order the walk stops once a whole page predates the date, so a daily schedule reads one page per company. Empty = no date limit.

## `includeCompanyRow` (type: `boolean`):

Also emit one free row per company with Indeed's own overall rating, the total review count, the 1-5 star histogram, the five category averages, the happiness score, the topic breakdown, the pros and cons Indeed extracts, and — from the company overview page, one extra free request — industry, size, headquarters, website, founded year, revenue band and CEO. Never charged.

## `sessions` (type: `integer`):

How many proxy sessions (egress IPs) run in parallel. More is faster; each is paced separately. Indeed refuses roughly one in three fresh sessions with a Cloudflare check, so the actor rotates and retries — a few sessions ride that out comfortably.

## `perIp` (type: `number`):

Pace for each session. Indeed answered 10 of 10 consecutive review pages at 1 req/s from one datacenter IP with no throttling; 1 is comfortable.

## `proxyConfiguration` (type: `object`):

Apify Proxy with the datacenter group is enough and is what this actor was measured on — 7 of 9 fresh datacenter sessions were served, and a session that answers once keeps answering. Residential works too and costs far more. Keep the default.

## Actor input object example

```json
{
  "companies": [
    "https://www.indeed.com/cmp/Google/reviews"
  ],
  "countries": [
    "us"
  ],
  "maxReviewsPerCompany": 100,
  "sort": "newest",
  "minRating": 0,
  "maxRating": 0,
  "requireText": false,
  "jobTitleContains": "",
  "locationContains": "",
  "sinceDate": "",
  "includeCompanyRow": true,
  "sessions": 2,
  "perIp": 1,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

One row per employee review, plus per-company context and status rows. Charged rows are billed as delivered; company and status rows are always free.

## `summary` (type: `string`):

One JSON record with the counts this run delivered and charged, its error and duplicate tallies, and its HTTP stats.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "https://www.indeed.com/cmp/Google/reviews"
    ],
    "countries": [
        "us"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kestrel/indeed-company-reviews").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "companies": ["https://www.indeed.com/cmp/Google/reviews"],
    "countries": ["us"],
}

# Run the Actor and wait for it to finish
run = client.actor("kestrel/indeed-company-reviews").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "https://www.indeed.com/cmp/Google/reviews"
  ],
  "countries": [
    "us"
  ]
}' |
apify call kestrel/indeed-company-reviews --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kestrel/indeed-company-reviews"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/u6HIMeqjQb0JV9nMc/builds/F3wmwMD1sEit9Cqlv/openapi.json
