# TeamBlind Reviews scraper (`memo23/teamblind-scraper`) Actor

Scrape every public review for any company on TeamBlind. Returns rating, full pros & cons, job title, tenure, date, and reviewer location — plus a per-company summary with logo, HQ, employee size, average ratings, and reviewer city/country. No login required. Proxies included.

- **URL**: https://apify.com/memo23/teamblind-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Agents, Automation, Lead generation
- **Stats:** 3 total users, 2 monthly users, 84.6% runs succeeded, NaN bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $2.80 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## TeamBlind Reviews Scraper

**Scrape every review for any company on TeamBlind — full pros, cons, ratings, job titles, dates.** One row per review, one row per company. No login required, proxies included.

### How it works

![How TeamBlind Reviews Scraper Works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-teamblind.png)

### ✨ Why use this scraper?

Tired of TeamBlind scrapers that break every other week? Glassdoor wrappers that miss half the fields? Tools that truncate pros/cons at 200 chars?

- 📝 **Full pros and cons text.** No truncation, no "read more" cut-offs. Every review delivered with the same text the reviewer wrote.
- ⭐ **Six ratings per review.** Headline overall rating plus career, work-life balance, compensation, culture, and management — each on the 1–5 scale.
- 👤 **Reviewer context.** Job title (mapped from `jobgroup`), tenure years, location, country ISO code, current-vs-former employee flag.
- 🏢 **Per-company aggregates.** A second dataset row per company with logo, HQ, founded year, employee size, industry, average ratings, and reviewer city/country histogram.
- 🔁 **Monitoring mode.** Skip reviews already scraped in earlier runs. Useful for incremental tracking.
- ⚡ **Fast by default.** Built on the [`impit`](https://www.npmjs.com/package/impit) HTTP client with sliding-window concurrency and parallel pagination. ~3.6 s for 100 reviews of one company on the test machine.
- 🛡 **Login-wall bypass for pros/cons.** TeamBlind serves real review text only on page 1 to logged-out viewers and replaces page-2+ content with `Lorem ipsum…`. The scraper detects this automatically and recovers the real text from each review's permalink page. No auth needed. No flag to flip.
- 🚫 **No auth, no headless browser.** Pure HTTP + Cheerio. Public review pages only — no login walls, no paid features touched.

### 🎯 Use cases

| Team | What they build |
|---|---|
| **HR / Recruiting** | Employer-reputation dashboards; surface what current and former employees say about pay and management. |
| **Market research** | Company-vs-company sentiment benchmarks across industries. |
| **Competitive intel** | Track tone shifts at a competitor over time (combined with monitoring mode). |
| **Investors / analysts** | Workforce-sentiment signals as a leading indicator alongside financials. |
| **Journalists** | Source-rich workplace stories with verifiable, structured pros/cons text. |
| **Internal teams (anonymous read-back)** | Pull your own company's reviews into a BI tool without manual copy-paste. |

### ✅ Supported inputs

The scraper accepts two URL types and one shorthand:

| Input | Example | Result |
|---|---|---|
| Listing URL | `https://www.teamblind.com/company/Twilio/reviews` | All reviews for Twilio, paginated through every `?page=N`. |
| Single-review URL | `https://www.teamblind.com/company/Twilio/review/z-eM7ygC89` | Just that one review. |
| Company name shorthand | `["Twilio", "Stripe", "Meta"]` (via `companyNames`) | Built into listing URLs automatically. |

**Not supported** (intentionally — outside client scope or behind a login):

- ❌ Salary URLs (`/company/{co}/salaries`)
- ❌ Benefits URLs (`/company/{co}/benefits`)
- ❌ Article / channel URLs (`/article/{id}`, `/channels/{name}`)
- ❌ User profile URLs
- ❌ Anything requiring TeamBlind login (verified-employee discussion threads)

### 🔁 How the flow works

1. You provide one or more company review URLs (or just company names).
2. The scraper walks every page of reviews for each company until exhausted or `maxItems` is reached.
3. For each review, it captures rating, full pros/cons, job title, date, and ~25 supporting fields.
4. For each company, it writes one row to a separate `companies` dataset with logo, HQ, employee size, average ratings, and reviewer geography.
5. Optional `monitoringMode` skips reviews already collected in earlier runs.

#### Engine

The scraper uses the [`impit`](https://www.npmjs.com/package/impit) HTTP client (Firefox TLS fingerprint, HTTP/3 when no proxy) with a global sliding-window concurrency pattern. Page 1 is fetched first to learn `totalCount`, then pages 2..N are fanned out in parallel. ~3.6 s for 100 reviews on the test machine. No headless browser, no Crawlee request queue overhead.

### 📥 Input parameters

#### Start

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `startUrls` | array | * | — | TeamBlind URLs to scrape: listing URLs or single-review URLs. |
| `companyNames` | array | * | — | Company names (case-sensitive, exactly as in TeamBlind URLs). Each becomes `https://www.teamblind.com/company/{name}/reviews`. |

\* Either `startUrls` or `companyNames` is required.

#### Options

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `maxItems` | integer | No | 1000 | Hard cap on reviews scraped across all start URLs in this run. |
| `monitoringMode` | boolean | No | false | Skip reviews seen in earlier runs (per-user key-value store). |
| `fetchReviewDetails` | boolean | No | false | Make one extra HTTP call per review to its permalink. The listing already contains everything, so this is opt-in for redundancy. |
| `maxConcurrency` | integer | No | 10 | Maximum simultaneous page fetches. |
| `minConcurrency` | integer | No | 1 | Minimum simultaneous page fetches. |
| `maxRequestRetries` | integer | No | 5 | Retry attempts on failed requests. |
| `proxy` | object | No | Apify residential | Proxy configuration. Apify residential recommended. |

### 📊 Output overview

The actor writes to **two** datasets:

- **`default`** — one row per review (~30 fields). This is the main output.
- **`companies`** — one row per company crawled (~18 fields), pushed when page 1 of that company's reviews is processed.

Both formats export to JSON and CSV. Different start URLs for the same company produce a single deduped company row.

### 📊 Output samples

#### Review row (default dataset)

Real row from `https://www.teamblind.com/company/Twilio/reviews`:

```json
{
  "id": 436627,
  "urlAlias": "z-eM7ygC89",
  "rating": 3,
  "ratingsBreakdown": {
    "career": 3,
    "balance": 3,
    "compensation": 4,
    "culture": 3,
    "management": 3
  },
  "pros": "Used to be decent compensation\nOpportunity to work at scale\n\n",
  "cons": "Terrible product management\nMediocre management. Some of the most useless sr dirs and vp levels you will come across.\n\n",
  "reasonResign": null,
  "jobTitle": "Software Engineer",
  "memberJobgroupId": 7694,
  "jobFamilyId": 6,
  "reviewDate": "2026-04-29T02:32:02.000Z",
  "updatedAt": "2026-04-29T02:32:02.000Z",
  "approvedAt": "2026-05-06T02:19:18.308Z",
  "summary": "Decent pay, mediocre company",
  "helpfulCnt": 0,
  "companyResponse": null,
  "companyResponseAt": null,
  "memberLocation": "San Francisco, CA",
  "memberLocationCountryIsoCode": "US",
  "memberStart": 2020,
  "memberEnd": null,
  "isCurrentEmployee": true,
  "nickname": "u*****",
  "memberId": 2340694,
  "isPinned": "N",
  "isFeatured": null,
  "status": "A",
  "companyName": "Twilio",
  "companyPageId": 89,
  "companyChannelId": 100109,
  "sourceUrl": "https://www.teamblind.com/company/Twilio/review/z-eM7ygC89"
}
````

#### Company row (companies dataset)

```json
{
  "urlAlias": "Twilio",
  "companyId": 100109,
  "companyName": "Twilio",
  "logoUrl": "https://static.teamblind.com/img/channel/logo/us/3ee5273a649429.png",
  "webSiteUrl": "www.twilio.com",
  "founded": "2008",
  "employeeSize": "1,001 to 5,000 employees",
  "hqLocation": "San Francisco, CA",
  "industryName": "Internet",
  "rating": "3.5",
  "ratingsBreakdown": {
    "career": "3.2",
    "balance": "4.0",
    "compensation": "3.6",
    "culture": "3.4",
    "management": "2.9"
  },
  "reviewCount": 1249,
  "cityDistribution": [
    { "name": "San Francisco, CA", "count": 498 },
    { "name": "Remote, OR", "count": 99 }
  ],
  "countryDistribution": [
    { "isoCode": "US", "name": "United States", "count": 1004 },
    { "isoCode": "IN", "name": "India", "count": 87 }
  ],
  "sourceUrl": "https://www.teamblind.com/company/Twilio/reviews"
}
```

### 🗂️ Key output fields

#### Review identifiers

| Field | Type | Description |
|---|---|---|
| `id` | integer | TeamBlind's internal review ID. Stable across runs. |
| `urlAlias` | string | Short slug used in the review permalink (e.g. `z-eM7ygC89`). |
| `sourceUrl` | string | Direct permalink to the review on TeamBlind. |

#### Ratings

| Field | Type | Description |
|---|---|---|
| `rating` | integer (1–5) | Headline overall rating. |
| `ratingsBreakdown.career` | integer (1–5) | Career opportunities / growth. |
| `ratingsBreakdown.balance` | integer (1–5) | Work-life balance. |
| `ratingsBreakdown.compensation` | integer (1–5) | Pay and benefits. |
| `ratingsBreakdown.culture` | integer (1–5) | Company culture. |
| `ratingsBreakdown.management` | integer (1–5) | Quality of management. |

#### Review content

| Field | Type | Description |
|---|---|---|
| `pros` | string | Full "what's good" text. Newlines preserved. Never truncated. |
| `cons` | string | Full "what's bad" text. Never truncated. |
| `summary` | string | Reviewer-supplied one-line headline. |
| `reasonResign` | string | null | Why the reviewer left. Usually null for current employees. |

#### Reviewer / job info

| Field | Type | Description |
|---|---|---|
| `jobTitle` | string | Job title as shown on TeamBlind (mapped from `jobgroup` — TeamBlind's own `jobTitle` is always null). |
| `memberJobgroupId` | integer | Numeric job-group ID. Useful for grouping across companies. |
| `jobFamilyId` | integer | Higher-level job family ID (e.g. `6` = Engineering). |
| `memberLocation` | string | City+state or country (e.g. `San Francisco, CA`, `Ireland`). |
| `memberLocationCountryIsoCode` | string | ISO-3166 alpha-2 country code. |
| `memberStart` | integer | Year the reviewer started. |
| `memberEnd` | integer | null | Year they left. `null` for current employees. |
| `isCurrentEmployee` | boolean | Derived: `true` when `memberEnd` is null. |
| `nickname` | string | Anonymized nickname (e.g. `u*****`). TeamBlind masks all but the first character. |
| `memberId` | integer | TeamBlind's internal numeric ID for the reviewer. |

#### Timestamps

| Field | Type | Description |
|---|---|---|
| `reviewDate` | ISO 8601 | When the review was posted. |
| `updatedAt` | ISO 8601 | Last edit (equal to `reviewDate` when never edited). |
| `approvedAt` | ISO 8601 | Moderation approval timestamp. |

#### Engagement & moderation

| Field | Type | Description |
|---|---|---|
| `helpfulCnt` | integer | Number of "helpful" votes. |
| `companyResponse` | string | null | Official company reply text, when present. |
| `companyResponseAt` | ISO 8601 | null | Timestamp of the company reply. |
| `isPinned` | `Y` / `N` | Pinned at the top of the company list. |
| `isFeatured` | boolean | null | Featured in TeamBlind editorial. |
| `status` | string | Moderation status (`A` = active). |

#### Company references

| Field | Type | Description |
|---|---|---|
| `companyName` | string | Display name of the company. |
| `companyPageId` | integer | Internal numeric page ID. |
| `companyChannelId` | integer | Internal channel ID (different from `companyPageId`). |

#### Company-row fields (companies dataset)

| Field | Type | Description |
|---|---|---|
| `urlAlias`, `companyId`, `companyName` | id + display | Identifiers. |
| `logoUrl`, `bgImgUrl` | URL | Company logo and industry banner. |
| `webSiteUrl` | string | Homepage (no protocol, e.g. `www.twilio.com`). |
| `founded`, `employeeSize`, `hqLocation` | string | "2008", "1,001 to 5,000 employees", "San Francisco, CA". |
| `industryId`, `industryName` | id + name | E.g. `247`, `"Internet"`. |
| `description` | string | Company blurb. |
| `plan`, `isPremium` | string | TeamBlind subscription state. |
| `rating` | string | Headline overall rating (e.g. `"3.5"`). |
| `ratingsBreakdown` | object | Sub-rating averages, string values like `"3.2"`. |
| `reviewCount` | integer | Total reviews on TeamBlind for this company. |
| `cityDistribution` | array | `[{ name, count }, …]` reviewer city histogram, sorted by count. |
| `countryDistribution` | array | `[{ isoCode, name, count }, …]` country histogram. |
| `sourceUrl` | string | The listing URL we crawled. |

### 🚀 Examples

#### Scrape one company

```json
{
  "startUrls": ["https://www.teamblind.com/company/Twilio/reviews"],
  "maxItems": 500
}
```

#### Scrape several companies by name

```json
{
  "companyNames": ["Twilio", "Stripe", "Meta"],
  "maxItems": 1500
}
```

#### Pull a single review

```json
{
  "startUrls": ["https://www.teamblind.com/company/Twilio/review/z-eM7ygC89"]
}
```

#### Incremental monitoring run

```json
{
  "companyNames": ["Twilio"],
  "monitoringMode": true,
  "maxItems": 200
}
```

### 💻 Integrations

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("memo23/apify-teamblind-scraper").call(run_input={
    "companyNames": ["Twilio"],
    "maxItems": 100,
})

for review in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{review['rating']}/5 by {review['jobTitle']} ({review['memberLocation']})")
    print(f"  Pros: {review['pros'][:80]}...")
```

#### JavaScript

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('memo23/apify-teamblind-scraper').call({
    companyNames: ['Twilio'],
    maxItems: 100,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(r => {
    console.log(`${r.rating}/5 — ${r.jobTitle} (${r.memberLocation})`);
});
```

### 💡 Tips for best results

1. **Start with `maxItems: 30` to test.** That's roughly one page of reviews. Verify the output before running large jobs.
2. **Use `companyNames` for batches.** It's faster than typing every URL and dedupes the company-summary row automatically.
3. **Skip `fetchReviewDetails` unless you need it.** The listing payload already has every field. Enabling it doubles requests for no extra data.
4. **Use `monitoringMode` for daily/weekly tracking.** Combined with a scheduled run, it gives you only-new-reviews delivery.
5. **Pair the two datasets.** Join review rows on `companyName` to the company row to get rating context per review.

### ❓ FAQ

**Which TeamBlind URLs are supported?**
Listing URLs (`/company/{co}/reviews`) and single-review URLs (`/company/{co}/review/{alias}`). Plus the `companyNames` shorthand which is converted to listing URLs.

**Does this scrape salaries or benefits?**
No — only reviews. That matches the original client scope. Salary and benefits pages have different shapes and would need a separate scraper.

**Are pros and cons truncated?**
No. The full text is returned exactly as written. Newlines are preserved.

**Why was I getting "Lorem ipsum dolor sit amet…" as pros/cons in older runs?**
TeamBlind shows the first 30 reviews (page 1) with full content for unauthenticated viewers, then replaces every review's pros/cons with the standard `Lorem ipsum…` boilerplate from page 2 onwards to gate content behind a sign-in wall. Other fields (rating, job title, date, location) come back correct on every page. The scraper now detects this automatically and recovers the real pros/cons by fetching each gated review's detail page (`/company/{co}/review/{alias}`), which is **not** gated — no auth required. You'll see `[bypass] N/30 reviews on this page are Lorem-gated — fetching detail pages in parallel` in the logs. This adds one HTTP request per gated review, parallelized so wall-clock impact is small.

**Does it require a TeamBlind login?**
No. The actor only hits public review pages. No verified-employee discussion threads, no login wall content.

**Why are reviewer names masked like `u*****`?**
That's how TeamBlind anonymizes reviewers on the public page. We pass through what they show.

**Why is the actual `jobTitle` field always null in the raw payload?**
TeamBlind has both a `jobTitle` field (always null on public reviews) and a `jobgroup` field (populated, e.g. "Software Engineer"). The actor maps `jobgroup` → `jobTitle` so the output uses the field name you'd expect.

**What happens when TeamBlind changes their layout?**
The parser walks every script tag and finds review-shaped objects by structural matching, not by fragile component names. If the embedded payload disappears entirely, the actor logs a clear `"could not locate reviews payload — TeamBlind layout may have changed"` warning instead of silently producing empty rows.

**Can I scrape multiple companies in one run?**
Yes. Pass either multiple `startUrls` or multiple `companyNames`. Each company gets its own row in the `companies` dataset.

**What about rate limits and blocks?**
The actor uses Apify's session pool with proxy rotation. Apify residential proxy is recommended for production runs.

### 💻 Local development

```bash
git clone https://github.com/yourusername/apify-teamblind-cheerio.git
cd apify-teamblind-cheerio
npm install
npm run start:dev
```

Edit `storage/key_value_stores/default/INPUT.json` to change inputs. Outputs land in `storage/datasets/default/*.json` (reviews) and `storage/datasets/companies/*.json` (per-company aggregates), plus `data.csv` / `data.json` exports in the project root.

### 📬 Support

- For issues or feature requests, please use the Issues section of this actor on the Apify platform.
- Author's website: <https://muhamed-didovic.github.io/>
- Email: <muhamed.didovic@gmail.com>

Response time: usually under 24 hours.

### 🔧 Additional services

- **Custom modifications, whole-dataset exports, scheduled deliveries:** <muhamed.didovic@gmail.com>
- **Need something else scraped?** Email above.
- **API services for this scraper** (no Apify fee, just usage fee): contact <muhamed.didovic@gmail.com>

### 🔍 Explore more scrapers

If you found this useful, check out our other Apify actors at [memo23's Apify profile](https://apify.com/memo23) — including scrapers for Dice.com, LandSearch, Bayut, and more.

***

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Team Blind, Inc. or any of its subsidiaries. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available review pages — no authenticated endpoints, paid features, or content behind the TeamBlind login wall. Users are responsible for ensuring their use complies with TeamBlind's Terms of Service, applicable data-protection law (GDPR, CCPA, etc.), and any contractual obligations of their own organization.

***

### SEO Keywords

teamblind scraper, scrape teamblind, teamblind reviews scraper, teamblind API, employee reviews scraper, anonymous workplace reviews scraper, company reviews scraper, glassdoor alternative scraper, teamblind.com scraper, Apify teamblind, scrape company reviews, employer reputation data, workplace sentiment scraper, blind app scraper, tech company reviews scraper, employee feedback scraper, pros and cons scraper, employer ratings scraper, anonymous employee reviews, company culture data, teamblind data export

# Actor input Schema

## `startUrls` (type: `array`):

Each URL must be a TeamBlind company reviews page (e.g. `https://www.teamblind.com/company/Twilio/reviews`) or a single-review page (`https://www.teamblind.com/company/Twilio/review/{alias}`).

## `companyNames` (type: `array`):

Company names exactly as they appear in TeamBlind URLs (e.g. `Twilio`, `Stripe`). Case-sensitive.

## `maxItems` (type: `integer`):

Hard cap on rows pushed to the dataset across all start URLs in this run.

## `monitoringMode` (type: `boolean`):

When enabled, every review is looked up in a per-user key-value store; only reviews never seen before are pushed. Turn this OFF for a normal full scrape.

## `fetchReviewDetails` (type: `boolean`):

When enabled, the actor makes one extra HTTP call per review to `/company/{co}/review/{alias}`. The listing page already contains full pros/cons text, so this is only useful for redundancy or future-proofing — it does not add fields. Default off (faster, fewer requests).

## `maxConcurrency` (type: `integer`):

Maximum number of pages that can be processed at the same time.

## `minConcurrency` (type: `integer`):

Minimum number of pages that will be processed at the same time.

## `maxRequestRetries` (type: `integer`):

Number of times the crawler will retry a failed request before giving up.

## `proxy` (type: `object`):

Specifies proxy servers used by the scraper.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.teamblind.com/company/Twilio/reviews"
  ],
  "maxItems": 1000,
  "monitoringMode": false,
  "fetchReviewDetails": false,
  "maxConcurrency": 10,
  "minConcurrency": 1,
  "maxRequestRetries": 5,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "startUrls": [
        "https://www.teamblind.com/company/Twilio/reviews"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/teamblind-scraper").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 = {
    "startUrls": ["https://www.teamblind.com/company/Twilio/reviews"],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/teamblind-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.teamblind.com/company/Twilio/reviews"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call memo23/teamblind-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=memo23/teamblind-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "TeamBlind Reviews scraper",
        "description": "Scrape every public review for any company on TeamBlind. Returns rating, full pros & cons, job title, tenure, date, and reviewer location — plus a per-company summary with logo, HQ, employee size, average ratings, and reviewer city/country. No login required. Proxies included.",
        "version": "0.0",
        "x-build-id": "hiyIpmE8Undwyb6gl"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~teamblind-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-teamblind-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/memo23~teamblind-scraper/runs": {
            "post": {
                "operationId": "runs-sync-memo23-teamblind-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/memo23~teamblind-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-teamblind-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "startUrls": {
                        "title": "URLs of TeamBlind review pages",
                        "type": "array",
                        "description": "Each URL must be a TeamBlind company reviews page (e.g. `https://www.teamblind.com/company/Twilio/reviews`) or a single-review page (`https://www.teamblind.com/company/Twilio/review/{alias}`).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "companyNames": {
                        "title": "Company names",
                        "type": "array",
                        "description": "Company names exactly as they appear in TeamBlind URLs (e.g. `Twilio`, `Stripe`). Case-sensitive.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxItems": {
                        "title": "Maximum number of reviews to scrape",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Hard cap on rows pushed to the dataset across all start URLs in this run.",
                        "default": 1000
                    },
                    "monitoringMode": {
                        "title": "Monitoring mode (only new reviews vs. previous runs)",
                        "type": "boolean",
                        "description": "When enabled, every review is looked up in a per-user key-value store; only reviews never seen before are pushed. Turn this OFF for a normal full scrape.",
                        "default": false
                    },
                    "fetchReviewDetails": {
                        "title": "Fetch each review's detail page",
                        "type": "boolean",
                        "description": "When enabled, the actor makes one extra HTTP call per review to `/company/{co}/review/{alias}`. The listing page already contains full pros/cons text, so this is only useful for redundancy or future-proofing — it does not add fields. Default off (faster, fewer requests).",
                        "default": false
                    },
                    "maxConcurrency": {
                        "title": "Max Concurrency",
                        "type": "integer",
                        "description": "Maximum number of pages that can be processed at the same time.",
                        "default": 10
                    },
                    "minConcurrency": {
                        "title": "Min Concurrency",
                        "type": "integer",
                        "description": "Minimum number of pages that will be processed at the same time.",
                        "default": 1
                    },
                    "maxRequestRetries": {
                        "title": "Max Request Retries",
                        "type": "integer",
                        "description": "Number of times the crawler will retry a failed request before giving up.",
                        "default": 5
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Specifies proxy servers used by the scraper.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
