# GoodFirms B2B Companies & Software Scraper (`haketa/goodfirms-scraper`) Actor

GoodFirms scraper & API: find B2B agencies & software by service category and location — company name, rating & reviews, hourly rate, minimum budget, team size, founded year, location, services and website. B2B vendor research and agency lead generation — fast, no login.

- **URL**: https://apify.com/haketa/goodfirms-scraper.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Lead generation, Developer tools, Jobs
- **Features:** Limited permissions
- **Stats:** 34 total users, 5 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## GoodFirms Scraper — B2B Agencies, Software Products, Hourly Rates, Emails & Reviews

> **Turn GoodFirms' global B2B agency and SaaS directory into an enriched sales and market-intelligence pipeline.** Extract verified **B2B service companies** and **SaaS software products** from [GoodFirms.co](https://www.goodfirms.co) — including **company name, cleaned website URL, aggregate rating, verified review count, hourly rate bracket, employee headcount band, founded year, structured headquarters & office addresses, public business email & phone, social links (LinkedIn, X/Twitter, Facebook, Instagram), service-focus percentages, client-size split, AI tools used, and verified client reviews**.

Export to **JSON, CSV, Excel, or the Apify API** — no login, no manual copy-pasting.

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-blue)](https://apify.com/haketa/goodfirms-scraper)
[![Live Data](https://img.shields.io/badge/Data-Live%20at%20Run%20Time-orange)]()
[![Scale](https://img.shields.io/badge/Scale-1%2C000%2B%20Results%20Pagination-green)]()
[![Pricing](https://img.shields.io/badge/Pricing-Pay%20Per%20Result-yellow)]()
[![Leads](https://img.shields.io/badge/Includes-Emails%20%C2%B7%20Phones%20%C2%B7%20LinkedIn-success)]()
[![Coverage](https://img.shields.io/badge/Coverage-110K%2B%20B2B%20Agencies%20%26%20SaaS-purple)]()
[![No Auth](https://img.shields.io/badge/Authentication-None%20Required-brightgreen)]()
[![Export](https://img.shields.io/badge/Export-JSON%20%C2%B7%20CSV%20%C2%B7%20Excel-lightgrey)]()

***

### ⚡ At a glance

| Feature | Details |
|---|---|
| 🎯 **Target directory** | **[GoodFirms.co](https://www.goodfirms.co)** — Top global B2B IT services, agency & SaaS review directory |
| 🏢 **Collection modes** | **Companies (`companies`)** — 30+ B2B agency categories × 20+ country/state filters; **Software (`software`)** — 20+ SaaS verticals; **Auto (`auto`)** — detects from `startUrls` |
| 📞 **B2B Contact & Social** | UTM-stripped `websiteUrl` (100%), `contact.phone` (~99.5%), `contact.email` (~88%), and `socialLinks` (`linkedin` ~92%, `facebook`, `twitter`, `instagram`) |
| 💼 **Firmographic signals** | `hourlyRateRange` (e.g., `$25 - $49/hr`), `employeesRange` (e.g., `50 - 249`), `foundedYear`, `rating`, `reviewCount`, and structured `headquarters` + `offices` |
| 📊 **Service & Client Split** | `services` breakdown with `%` share (e.g., `Web Development: 20%`), `focusBreakdown` (Small / Medium / Large Business `%`), `aiTools`, and `whyChoose` bullets |
| ⭐ **Verified Client Reviews** | Optional `scrapeReviews: true` extracts individual client reviews (`rating`, `projectName`, `projectCost`, `projectDuration`, `reviewer`, `reviewerRole`, `reviewerCompany`, `summary`) |
| 🔁 **Pagination & Scale** | Unlocked **1,000+ results pagination** (`maxPagesPerCategory: 0` auto-paginates until `maxRecords` is reached) with 100% `slug` deduplication |
| 📦 **Bulk export** | Pre-built **Companies**, **Software**, and **Reviews** dataset views in JSON, CSV, Excel (XLSX), and REST API |

***

### 🔎 Why scrape GoodFirms?

**[GoodFirms](https://www.goodfirms.co)** is one of the Big Three global B2B service and software directories (alongside Clutch and G2/DesignRush). Over **110,000+ software development companies, digital marketing agencies, UI/UX studios, AI/blockchain consultancies, and SaaS vendors** maintain detailed profiles on GoodFirms because enterprise procurement teams and startup founders use it daily to shortlist vendors.

That makes GoodFirms one of the highest-intent B2B lead sources on the web — every agency profile combines **budget & pricing tier (`hourlyRateRange`)**, **headcount (`employeesRange`)**, **geographic footprint (`headquarters` + `offices`)**, **verified review velocity (`rating` + `reviewCount`)**, **service specialization (`services` `%`)**, and **direct contact channels (`websiteUrl`, `contact.email`, `contact.phone`, `socialLinks.linkedin`)**.

Collecting this manually is a bottleneck:

- **Deep multi-page directories:** Categories like Web Development, Mobile App Development, and Digital Marketing span hundreds of pages.
- **Split data between cards and profiles:** Listing cards show summary firmographics, while business emails, street addresses, multi-office locations, service-focus percentages, and social links live on individual `/company/{slug}` pages.
- **Cross-category overlap:** The same agency often ranks in 5–10 categories (e.g., Web Dev, Node.js, React, E-Commerce); scraping without global slug deduplication creates noisy duplicates.

This **GoodFirms scraper** automates discovery, multi-page traversal, profile enrichment, UTM cleanup, and `slug` deduplication in a single run.

#### Common reasons teams use this GoodFirms data extractor

- 🎯 **Outbound B2B Lead Generation** — Build hyper-targeted agency prospect lists filtered by hourly rate, employee count, country, and service line — with website, email, phone, and LinkedIn in the same row.
- 📈 **Account-Based Marketing (ABM) & Lookalike Audiences** — Segment mid-market IT and marketing agencies (`50 - 249` or `250 - 999` employees) for partnerships, white-label services, DevOps tooling, or SaaS sales.
- 🔍 **Competitive & Pricing Intelligence** — Benchmark hourly rates, review counts, client-size splits, and AI tool adoption (`aiTools`) across regions (US, UK, India, Ukraine, Poland, UAE, LATAM).
- 💻 **SaaS Market & Alternatives Research** — Extract software products (`mode: "software"`) with pricing models, starting prices, free-trial flags, feature checklists, and competitor alternatives.
- 🤝 **M\&A, Roll-up & PE Deal Sourcing** — Screen boutique and mid-sized IT service firms by founding year, headcount, hourly rate band, and verified review momentum.

***

### ✨ What this GoodFirms scraper does

- ✅ **Dual scraping modes (`companies` & `software`)** — Scrape B2B service agencies, SaaS software products, or let `mode: "auto"` infer the record type from any URL in `startUrls`.
- ✅ **Unlocked 1,000+ results pagination** — With `maxPagesPerCategory: 0` (the default), the scraper automatically walks page `1, 2, 3 …` across your selected categories and countries until your `maxRecords` target is reached or the directory ends.
- ✅ **Two speed/depth tiers (`scrapeProfileDetails`)**:
  - **Fast List Mode (`scrapeProfileDetails: false`):** Extracts rich listing-card data (`name`, `websiteUrl`, `logoUrl`, `tagline`, `rating`, `reviewCount`, `hourlyRateRange`, `employeesRange`, `foundedYear`, `headquarters`, `aiTools`, `topReview`, `whyChoose`) in seconds.
  - **Full Profile Mode (`scrapeProfileDetails: true`):** Visits each `/company/{slug}` page to add `contact.email` (~88% fill), `contact.phone` (~99.5% fill), `socialLinks` (LinkedIn ~92%), full `description`, `services` `%` breakdown, `focusBreakdown` `%`, and `offices`.
- ✅ **Server-side ICP filtering** — Apply `countrySlugs`, `employeesFilter`, `hourlyRateFilter`, and `minReviews` directly to GoodFirms discovery URLs so you only scrape companies matching your Ideal Customer Profile.
- ✅ **Automatic slug normalization** — If a bare category slug is passed (e.g., `web-development` instead of `web-development-agency`), the actor automatically retries the canonical `-agency` slug on page 1.
- ✅ **Opt-in verified client reviews (`scrapeReviews: true`)** — Pulls individual client reviews with project cost, project duration, reviewer name/title/company, and review summary.

***

### 🎯 Use cases

#### 1. Outbound SDR & Cold Email Teams (Apollo / Clay / Smartlead / Lemlist)

- **Ready-to-sequence agency lists:** Scrape `digital-marketing-agency`, `seo-agency`, and `ppc-agency` across `["us", "gb", "ca", "au"]` with `employeesFilter: "10-49"` and `scrapeProfileDetails: true`. Export directly to Clay or Smartlead with `websiteUrl`, `contact.email`, `contact.phone`, `socialLinks.linkedin`, and `topReview.quote` for personalized first lines.

#### 2. B2B SaaS & Developer Tool Vendors

- **AI & DevOps tool adoption targeting:** Filter agencies by the `aiTools` array reported on their cards (e.g., GitHub Copilot, Cursor, ChatGPT, Claude, Midjourney) and `topServices` to pitch developer productivity, cloud infrastructure, or QA automation platforms.

#### 3. White-Label & Staff Augmentation Partnerships

- **High-rate agency partnering:** Identify US/UK/EU agencies charging `$100 - $149/hr` or `$150 - $199/hr` (`hourlyRateFilter: "100-149"`) and pair them with nearshore/offshore delivery teams.

#### 4. M\&A Advisors, Private Equity & Search Funds

- **IT Services acquisition screening:** Filter for established firms (`foundedYear <= 2018`, `employeesFilter: "50-249"`, `minReviews: 15`) and analyze their `focusBreakdown` (Enterprise vs. Mid-Market vs. SMB share) and multi-country `offices`.

***

### 📥 Input parameters

Configure the actor in the Apify Console or pass JSON via the API. All fields are optional — launching with an empty input `{}` runs a curated multi-category sample of ~100 B2B agencies.

| Parameter | Type | Default | Prefill | Description |
|---|---|---|---|---|
| `mode` | `string` | `"auto"` | `"companies"` | `"companies"` (B2B agencies), `"software"` (SaaS products), or `"auto"` (detect from `startUrls`). |
| `serviceCategorySlugs` | `array<string>` | `[]` | `["web-development-agency"]` | One or more B2B agency categories to crawl (30 built-in options in the dropdown, or pass any GoodFirms category slug). |
| `countrySlugs` | `array<string>` | `[]` | `[]` | Optional country or US state filters (`us`, `gb`, `ca`, `au`, `in`, `de`, `fr`, `nl`, `ua`, `pl`, `ae`, `california`, `new-york`, `texas`, etc.). Empty = global. |
| `softwareCategorySlugs` | `array<string>` | `[]` | `[]` | SaaS categories to crawl when `mode` is `"software"` or `"auto"` (`crm-software`, `project-management-software`, `erp-software`, etc.). |
| `employeesFilter` | `string` | `""` | — | Filter agencies by headcount bracket: `""` (Any), `"2-9"`, `"10-49"`, `"50-249"`, `"250-999"`, `"1000-9999"`, `"10000+"`. |
| `hourlyRateFilter` | `string` | `""` | — | Filter agencies by USD hourly rate: `""` (Any), `"<25"`, `"25-49"`, `"50-99"`, `"100-149"`, `"150-199"`, `"200+"`. |
| `minReviews` | `integer` | `0` | — | Only include companies with at least this many verified reviews (`0` = no minimum). |
| `scrapeProfileDetails` | `boolean` | `true` | `false` | Visit each profile page for `contact.email`, `contact.phone`, `socialLinks`, `services` `%`, `focusBreakdown` `%`, and full `description`. Set `false` for fast list-card scraping. |
| `scrapeReviews` | `boolean` | `false` | `false` | Fetch verified client reviews per company/software profile. |
| `maxRecords` | `integer` | `0` | `20` | Maximum total records to output (`0` = unlimited). Set to `1000`+ for deep category sweeps. |
| `maxPagesPerCategory` | `integer` | `0` | — | Maximum listing pages to crawl per category/country combo. **`0` = unlimited (auto-governed by `maxRecords`)**. |
| `startUrls` | `array` | `[]` | `[]` | Advanced: Paste any GoodFirms category URL, country listing URL, `/company/{slug}` URL, or `/software/{slug}` URL. Category URLs in `startUrls` paginate automatically. |
| `companySlugs` | `array<string>` | `[]` | `[]` | Advanced: Direct company slugs (e.g., `["unified-infotech", "hyperlink-infosystem"]`). |
| `softwareSlugs` | `array<string>` | `[]` | `[]` | Advanced: Direct software slugs (e.g., `["hubspot-crm", "monday-com"]`). |
| `requestDelay` | `integer` | `1200` | — | Delay between requests in milliseconds. |
| `maxConcurrency` | `integer` | `3` | `3` | Parallel worker count (`1`–`10`). Keep at `2`–`3` for smooth execution. |
| `proxyConfiguration` | `object` | Apify Proxy | Apify Proxy | Proxy configuration (uses cost-effective datacenter IPs first and automatically escalates to residential if challenged). |

#### Sample Input Recipes

##### Recipe 1: Fast list-mode discovery of 1,000+ Web & Mobile Agencies

```json
{
  "mode": "companies",
  "serviceCategorySlugs": [
    "web-development-agency",
    "mobile-app-development-agency",
    "software-development-agency"
  ],
  "scrapeProfileDetails": false,
  "maxRecords": 1000,
  "maxPagesPerCategory": 0
}
```

##### Recipe 2: Full-detail ICP Lead Generation (US, UK & Canada Mid-Market Agencies with Emails & LinkedIn)

```json
{
  "mode": "companies",
  "serviceCategorySlugs": [
    "digital-marketing-agency",
    "seo-agency",
    "web-development-agency"
  ],
  "countrySlugs": ["us", "gb", "ca"],
  "employeesFilter": "10-49",
  "hourlyRateFilter": "50-99",
  "minReviews": 5,
  "scrapeProfileDetails": true,
  "scrapeReviews": false,
  "maxRecords": 500,
  "maxPagesPerCategory": 0
}
```

##### Recipe 3: SaaS Software Directory Extraction (`mode: "software"`)

```json
{
  "mode": "software",
  "softwareCategorySlugs": [
    "crm-software",
    "project-management-software",
    "helpdesk-software"
  ],
  "maxRecords": 300,
  "maxPagesPerCategory": 0
}
```

***

### 📤 Output schema & field reference

#### Example Output — B2B Company Record (`recordType: "company"`)

```json
{
  "recordType": "company",
  "slug": "example-agency",
  "profileUrl": "https://www.goodfirms.co/company/example-agency",
  "name": "Example Agency",
  "tagline": "Example Agency is a premier web and software development agency delivering scalable digital products for startups and enterprises.",
  "logoUrl": "https://assets.goodfirms.co/services/medium/example-agency.png",
  "websiteUrl": "https://exampleagency.com/",
  "description": "With 250+ engineers and designers across New York and London, Example Agency builds custom web applications, AI workflows, and enterprise e-commerce platforms...",
  "rating": 4.9,
  "reviewCount": 202,
  "foundedYear": 2015,
  "employeesRange": "250 - 999",
  "hourlyRateRange": "$25 - $49/hr",
  "minProjectSize": "$10,000+",
  "headquarters": {
    "city": "New York",
    "state": "New York",
    "country": "us",
    "address": "287 Park Ave S"
  },
  "offices": [
    { "city": "London", "country": "gb" },
    { "city": "Noida", "country": "in" }
  ],
  "topServices": [
    "Web Development",
    "Software Development",
    "E-commerce Development",
    "Web Design"
  ],
  "services": [
    { "name": "Web Development", "percent": 40 },
    { "name": "Software Development", "percent": 30 },
    { "name": "E-commerce Development", "percent": 20 },
    { "name": "Web Design", "percent": 10 }
  ],
  "focusBreakdown": [
    { "name": "Small Business", "percent": 30 },
    { "name": "Medium Business", "percent": 35 },
    { "name": "Large Business", "percent": 35 }
  ],
  "contact": {
    "email": "hello@exampleagency.com",
    "phone": "+1-555-123-4567"
  },
  "socialLinks": {
    "linkedin": "https://www.linkedin.com/company/example-agency",
    "twitter": "https://twitter.com/exampleagency",
    "facebook": "https://www.facebook.com/exampleagency",
    "instagram": null
  },
  "aiTools": ["GitHub Copilot", "Cursor", "ChatGPT", "Claude"],
  "topReview": {
    "quote": "Example Agency delivered a robust, user-friendly platform ahead of schedule.",
    "author": "VP of Engineering at FinTech Corp"
  },
  "whyChoose": [
    "Full-cycle agile product engineering",
    "Dedicated cross-functional pods",
    "Transparent weekly sprint reporting"
  ],
  "reviews": [],
  "discoveredFrom": "web-development-agency",
  "scrapedAt": "2026-11-01T23:59:00.000Z"
}
```

#### 🏢 Company Identity & Firmographics

| Field | Type | Coverage | Description |
|---|---|---|---|
| `recordType` | `string` | 🟢 High (100%) | `"company"` or `"software"` |
| `slug` | `string` | 🟢 High (100%) | Unique GoodFirms URL slug (primary deduplication key) |
| `profileUrl` | `string` | 🟢 High (100%) | Canonical GoodFirms profile URL |
| `name` | `string` | 🟢 High (100%) | Company or software product display name |
| `websiteUrl` | `string \| null` | 🟢 High (100%) | External company website URL with UTM tracking parameters stripped |
| `logoUrl` | `string \| null` | 🟢 High (100%) | Company or product logo image URL |
| `tagline` | `string \| null` | 🟢 High (100%) | Short positioning headline from the directory listing card |
| `description` | `string \| null` | 🟢 High (~99.7% in profile mode) | Full multi-paragraph "About" summary from the profile page |
| `rating` | `number \| null` | 🟢 High (~99.5%) | Aggregate star rating (`0.0`–`5.0`) |
| `reviewCount` | `integer \| null` | 🟢 High (~99%) | Total number of verified client reviews |
| `foundedYear` | `integer \| null` | 🟢 High (~98%) | Year the company was founded |
| `employeesRange` | `string \| null` | 🟢 High (100%) | Team size bracket (e.g., `"10 - 49"`, `"50 - 249"`, `"250 - 999"`) |
| `hourlyRateRange` | `string \| null` | 🟢 High (100%) | Hourly rate bracket (e.g., `"< $25/hr"`, `"$25 - $49/hr"`, `"$50 - $99/hr"`) |
| `minProjectSize` | `string \| null` | 🟡 Conditional | Minimum project budget when disclosed on the profile |

#### 📍 Location, Contact & Social Links

| Field | Type | Coverage | Description |
|---|---|---|---|
| `headquarters` | `object \| null` | 🟢 High (~99%) | Structured primary HQ (`{ city, state, country, address }`) |
| `offices` | `array<object>` | 🟡 Conditional (~11%) | Additional global branch offices (`[{ city, country }]`, profile mode) |
| `contact.phone` | `string \| null` | 🟢 High (~99.5% in profile mode) | Public business telephone number |
| `contact.email` | `string \| null` | 🟢 High (~88% in profile mode) | Public business contact email address |
| `socialLinks.linkedin` | `string \| null` | 🟢 High (~92% in profile mode) | Company LinkedIn page URL |
| `socialLinks.facebook` · `twitter` · `instagram` | `string \| null` | 🟢 High (82% / 68% / 37%) | Additional social profile links |

#### 🧩 Services, Client Focus, AI Stack & Reviews

| Field | Type | Coverage | Description |
|---|---|---|---|
| `topServices` | `array<string>` | 🟢 High (~99.7% in profile mode) | Top-level service lines offered by the agency |
| `services` | `array<object>` | 🟢 High (~99.7% in profile mode) | Sub-service breakdown with percentage share (`[{ name, percent }]`) |
| `focusBreakdown` | `array<object>` | 🟢 High (~95% in profile mode) | Client segment split (`Small Business`, `Medium Business`, `Large Business` with `percent`) |
| `aiTools` | `array<string>` | 🟡 Conditional (~47%) | AI coding/design/productivity tools listed on the company card |
| `topReview` | `object \| null` | 🟢 High (~99.5%) | Highlighted client review quote (`{ quote, author }`) from the listing card |
| `whyChoose` | `array<string>` | 🟡 Conditional (~50%) | Key differentiator bullet points from the listing card |
| `reviews` | `array<object>` | 🟡 Opt-in (`scrapeReviews`) | Full verified client review array (`rating`, `projectName`, `projectCost`, `projectDuration`, `reviewer`, `reviewerRole`, `reviewerCompany`, `summary`, `datePublished`) |
| `discoveredFrom` | `string` | 🟢 High (100%) | Category slug, country filter, or start URL that surfaced the record |
| `scrapedAt` | `string` | 🟢 High (100%) | ISO-8601 UTC extraction timestamp |

***

### 🔁 Pagination & scale

The **GoodFirms Scraper** supports seamless deep pagination to collect **1,000+ B2B companies or software products** in a single run:

- **Auto-governed pagination (`maxPagesPerCategory: 0`):** By default, `maxPagesPerCategory` is `0` (unlimited). The scraper walks `?page=1, 2, 3 …` across every selected category and country combination until `maxRecords` is reached or the category runs out of new companies.
- **End-of-category detection:** If a page returns zero new companies (or only repeats already-queued slugs), the actor stops paginating that category immediately and moves to the next target.
- **Cross-category deduplication:** Every company and software product is deduplicated globally by `slug` before profile scraping begins. Even if an agency appears across 8 different categories or countries, it is scraped and billed **only once** (while merging any card seed fields).
- **Safe-exit wall-clock guard:** On massive multi-hundred-profile runs, the actor monitors the run timer and gracefully finishes in-flight workers before the platform timeout so partial datasets are never lost.

***

### 💻 API Integration Examples

#### Python (`apify-client`)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run = client.actor("haketa/goodfirms-scraper").call(run_input={
    "mode": "companies",
    "serviceCategorySlugs": ["web-development-agency", "ai-development-agency"],
    "countrySlugs": ["us", "gb"],
    "scrapeProfileDetails": True,
    "maxRecords": 250,
    "maxPagesPerCategory": 0,
})

for company in client.dataset(run["defaultDatasetId"]).iterate_items():
    email = (company.get("contact") or {}).get("email")
    linkedin = (company.get("socialLinks") or {}).get("linkedin")
    print(f"{company['name']} | {company['hourlyRateRange']} | {company['employeesRange']} | {email} | {linkedin}")
```

#### Node.js / TypeScript (`apify-client`)

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

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

const run = await client.actor('haketa/goodfirms-scraper').call({
    mode: 'companies',
    serviceCategorySlugs: ['digital-marketing-agency', 'seo-agency'],
    scrapeProfileDetails: false,
    maxRecords: 1000,
    maxPagesPerCategory: 0,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Extracted ${items.length} unique B2B agencies`);
```

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/haketa~goodfirms-scraper/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "companies",
    "serviceCategorySlugs": ["web-development-agency"],
    "scrapeProfileDetails": false,
    "maxRecords": 100
  }'
```

***

### ❓ Frequently Asked Questions

#### What is the difference between `scrapeProfileDetails: false` and `scrapeProfileDetails: true`?

- **`scrapeProfileDetails: false` (Fast List Mode):** Extracts all data directly from the category listing cards (`name`, `websiteUrl`, `logoUrl`, `tagline`, `rating`, `reviewCount`, `hourlyRateRange`, `employeesRange`, `foundedYear`, `headquarters`, `aiTools`, `topReview`, `whyChoose`). Because each category page holds ~10–60 companies, you can collect **1,000+ companies in just a couple of minutes**.
- **`scrapeProfileDetails: true` (Full Profile Enrichment):** Visits each company's individual `/company/{slug}` page in addition to the listing card, adding `contact.email` (~88%), `contact.phone` (~99.5%), `socialLinks` (LinkedIn ~92%), `services` `%` share, `focusBreakdown` `%`, `offices`, and full `description`.

#### How do I scrape 1,000+ companies in one run?

Set `maxRecords: 1000` (or `0` for unlimited) and leave `maxPagesPerCategory: 0`. The scraper will automatically paginate as deep as needed across your chosen `serviceCategorySlugs` (or default categories) until 1,000 unique companies are collected.

#### Do I need to configure special proxies?

No. The default Apify Proxy configuration starts on low-cost datacenter IPs and automatically escalates to residential IPs only if a request is challenged.

#### Can I pass custom filtered GoodFirms URLs?

Yes! Copy any URL from `goodfirms.co` (such as a niche category, city page, or industry directory) and paste it into `startUrls`. The actor will automatically paginate through all pages of that URL.

***

### 🔗 Related B2B & lead-generation scrapers

Pair this **GoodFirms scraper** with complementary B2B intelligence actors from [haketa](https://apify.com/haketa):

- [D\&B / Dun & Bradstreet Scraper](https://apify.com/haketa/dnb-scraper) — Company firmographics, NAICS/SIC codes, revenue bands & executive contacts
- [BBB (Better Business Bureau) Scraper](https://apify.com/haketa/bbb-scraper) — Accredited North American businesses with ratings, complaints & phone numbers
- [YouTube Contact Scraper](https://apify.com/haketa/youtube-contact-scraper) — Channel business emails & social links for creator outreach
- [Marktplaats Scraper](https://apify.com/haketa/marktplaats-scraper) — Netherlands classifieds & commercial seller leads
- [Yad2 Real Estate Scraper](https://apify.com/haketa/yad2-scraper) — Israel property listings & seller contacts

***

### 🔍 SEO Keywords

GoodFirms scraper · scrape GoodFirms · GoodFirms data extractor · GoodFirms lead generation · B2B agency scraper · software development companies list · digital marketing agency leads · SaaS directory scraper · Clutch alternative scraper · B2B contact email extractor · bulk export JSON CSV Excel API · 1,000+ results pagination · B2B intelligence

***

### 📋 Changelog

| Version | Date | Notes |
|---|---|---|
| **1.2.0** | **2026-11** | **Unlocked 1,000+ deep pagination & auto page scaling:** Changed `maxPagesPerCategory` default from `5` to `0` (unlimited, governed by `maxRecords`), removed the 100-record clamp when `maxRecords > 100` is explicitly requested on default categories, added automatic multi-page pagination for category `startUrls`, and cleaned dataset schema validation. |
| **1.1.0** | **2026-11** | **Enhanced profile parser (`cp2-` layout + JSON-LD):** Updated `extractProfileExtras` for GoodFirms' current profile DOM (`services` `%`, `focusBreakdown` `%`, full `.cp2-about-text` description) and `pickCompanyOrg` JSON-LD extraction (`contact.email` 88%, `contact.phone` 99.5%, `reviewCount` 99%). |
| **1.0.10** | **2026-05** | Added automatic `-agency` canonical slug retry on first-page 404s and graceful `Actor.exit` status reporting. |
| **1.0.0** | **2026-03** | Initial release — Companies & Software modes, server-side ICP filters, and verified review extraction. |

# Changelog

This Actor's version history is a separate document: https://apify.com/haketa/goodfirms-scraper/changelog.md

# Actor input Schema

## `mode` (type: `string`):

Pick 'Companies' for B2B agencies (web dev, mobile, marketing…), 'Software' for SaaS products (CRM, project management…), or 'Auto' to detect from each Start URL.

## `serviceCategorySlugs` (type: `array`):

Pick one or more agency categories to discover B2B companies from. Great for agency research and lead generation. Leave empty for a popular, ready-to-go mix.

## `countrySlugs` (type: `array`):

Narrow company discovery to specific countries or US states. Leave empty to scrape the global category (all locations).

## `softwareCategorySlugs` (type: `array`):

Pick one or more SaaS categories to discover software products from. Used when mode is 'Software' or 'Auto'.

## `employeesFilter` (type: `string`):

Only include companies in this employee range.

## `hourlyRateFilter` (type: `string`):

Only include companies in this hourly rate bracket.

## `minReviews` (type: `integer`):

Only include companies with at least this many verified reviews. 0 = no minimum.

## `scrapeReviews` (type: `boolean`):

Also fetch verified client reviews (rating, review text, reviewer, project cost & duration). Slower and uses more requests.

## `scrapeProfileDetails` (type: `boolean`):

Visit each profile page for richer data (services breakdown, description, contact info). Turn off for fast list-only scraping.

## `maxRecords` (type: `integer`):

Stop after this many records. Set to 0 for no limit.

## `maxPagesPerCategory` (type: `integer`):

How many listing pages to crawl per category/location (≈10–60 companies per page). Set to 0 for unlimited (auto-governed by Max results).

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

Optional. Paste any GoodFirms page URL — a category, a company profile, or a software product. Most users can leave this empty and just pick categories above.

## `companySlugs` (type: `array`):

Optional. Scrape specific company profiles directly. The slug is the part after /company/ in a GoodFirms URL.

## `softwareSlugs` (type: `array`):

Optional. Scrape specific software products directly. The slug is the part after /software/ in a GoodFirms URL.

## `requestDelay` (type: `integer`):

Delay between requests. Higher values are gentler on GoodFirms.

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

How many requests to run in parallel. Keep this low (1–3) for the most reliable results.

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

Datacenter by default (low-cost); auto-escalates to residential if blocked.

## Actor input object example

```json
{
  "mode": "companies",
  "serviceCategorySlugs": [
    "web-development-agency"
  ],
  "countrySlugs": [],
  "softwareCategorySlugs": [],
  "employeesFilter": "",
  "hourlyRateFilter": "",
  "minReviews": 0,
  "scrapeReviews": false,
  "scrapeProfileDetails": false,
  "maxRecords": 20,
  "maxPagesPerCategory": 0,
  "startUrls": [],
  "companySlugs": [],
  "softwareSlugs": [],
  "requestDelay": 1200,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Open to view, filter and export all scraped results from this run (JSON, CSV, Excel).

# 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 = {
    "mode": "companies",
    "serviceCategorySlugs": [
        "web-development-agency"
    ],
    "countrySlugs": [],
    "softwareCategorySlugs": [],
    "scrapeReviews": false,
    "scrapeProfileDetails": false,
    "maxRecords": 20,
    "startUrls": [],
    "companySlugs": [],
    "softwareSlugs": [],
    "maxConcurrency": 3,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/goodfirms-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 = {
    "mode": "companies",
    "serviceCategorySlugs": ["web-development-agency"],
    "countrySlugs": [],
    "softwareCategorySlugs": [],
    "scrapeReviews": False,
    "scrapeProfileDetails": False,
    "maxRecords": 20,
    "startUrls": [],
    "companySlugs": [],
    "softwareSlugs": [],
    "maxConcurrency": 3,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/goodfirms-scraper").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 '{
  "mode": "companies",
  "serviceCategorySlugs": [
    "web-development-agency"
  ],
  "countrySlugs": [],
  "softwareCategorySlugs": [],
  "scrapeReviews": false,
  "scrapeProfileDetails": false,
  "maxRecords": 20,
  "startUrls": [],
  "companySlugs": [],
  "softwareSlugs": [],
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call haketa/goodfirms-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,haketa/goodfirms-scraper"
        }
    }
}
```

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/JrueWOjQRdUoXcwHF/builds/d2fhBEGdGwuh9cKle/openapi.json
