# Clutch Scraper — Agency Rates, Size & Services (`thenetaji/clutch-directory-scraper`) Actor

Shortlist B2B agencies without opening a hundred tabs. One row per agency in a Clutch directory, in Clutch's own ranking, with the rating and review count, the smallest project it takes, its hourly-rate band, headcount, city, phone, and the percentage split of what it actually does.

- **URL**: https://apify.com/thenetaji/clutch-directory-scraper.md
- **Developed by:** [The Netaji](https://apify.com/thenetaji) (community)
- **Categories:** Business, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.55 / 1,000 agencies

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Clutch Scraper — Agency Rates, Size & Services

Shortlisting a B2B agency on Clutch means opening a directory, then opening a tab per agency to find out
what it charges, how small a project it will take, how many people it has, and what it actually spends its
time doing. This Actor returns that as a spreadsheet. One row per agency, in Clutch's own ranking, with the
rating, the review count, the minimum project size, the hourly-rate band, the headcount band, the location,
the phone number and the agency's percentage service mix.

The service mix is the column worth the run. Firmographics are available in a dozen places; `45% Web
Development, 45% Web Design, 10% Branding` is a positioning statement, and it sits on the directory listing
rather than behind a profile page. It is what separates a web shop that also brands from a brand studio that
also ships websites, and neither of them describes itself that way in its own copy.

### Accepted input

`directory` is required and takes Clutch directory paths, one per line. A path is what follows `clutch.co/`
in the address bar: `web-developers`, `it-services`, `agencies/digital-marketing`. A pasted directory URL is
accepted and reduced to its path, and a query string on it is discarded. One or two segments is the accepted
shape.

`maxItems` caps how many agencies the run saves across every directory it was given, and defaults to `100`;
`0` walks each directory to its end. `startPage` defaults to `1` and is a resume point rather than a filter —
a run continues into later pages by itself, and the log prints the page to continue from when it stops.

```json
{
  "directory": ["web-developers", "agencies/digital-marketing"],
  "maxItems": 100,
  "startPage": 1
}
```

Where the path is unknown, [Clutch Agency List](https://apify.com/thenetaji/clutch-agency-list-scraper) run
in directory mode returns every ranked directory path Clutch publishes, and every row of it goes straight
into `directory` here.

### Response fields

A real row, from `web-developers`:

```json
{
  "position": 1,
  "name": "Lounge Lizard",
  "slug": "lounge-lizard",
  "agency_id": "23730",
  "clutch_url": "https://clutch.co/profile/lounge-lizard",
  "directory": "web-developers",
  "rating": 4.8,
  "review_count": 43,
  "rating_best": 5,
  "rating_worst": 0.5,
  "min_project_size": "$25,000+",
  "hourly_rate": "Undisclosed",
  "employees": "50 - 249",
  "location": "New York, NY",
  "service_mix": "45% Web Development, 45% Web Design, 10% Branding",
  "primary_service": "Web Development",
  "services": [
    { "share_pct": 45, "service": "Web Development" },
    { "share_pct": 45, "service": "Web Design" },
    { "share_pct": 10, "service": "Branding" }
  ],
  "telephone": "1-888-444-0110",
  "street": "112 West 34th Street 18th Floor",
  "locality": "New York",
  "region": "NY",
  "postal_code": "10120",
  "country": "US"
}
```

| Field | What it says |
| --- | --- |
| `position` | The agency's rank in the directory, as Clutch ordered it. |
| `rating`, `review_count` | The Clutch rating and how many reviews it is computed over. |
| `rating_best`, `rating_worst` | The scale that rating sits on. Clutch's floor is `0.5`, not `0`. |
| `min_project_size` | The smallest engagement the agency takes, as a display band: `$25,000+`. |
| `hourly_rate` | The rate band, or the literal string `Undisclosed`. |
| `employees` | The headcount band: `50 - 249`. |
| `service_mix` | The percentage mix on one line, so it survives an export to CSV. |
| `primary_service` | The line of work with the largest share. |
| `services` | The same mix as an array, one entry per line of work. |
| `telephone`, `street`, `locality`, `region`, `postal_code`, `country` | Contact and structured address. |
| `slug`, `agency_id`, `clutch_url`, `name`, `directory` | Identity, and which directory the row came from. |

`min_project_size`, `hourly_rate` and `employees` are kept as the strings Clutch renders rather than parsed
into numbers. The `+` in `$25,000+` and the boundaries of `$100 - $149 / hr` are the information, and a
numeric reading discards both.

### Questions

**Why did a run return fewer agencies than `maxItems`?**
Because the directory ran out. A directory is walked until it produces no agency the run has not already
saved, and that point arrives sooner than the row count on the page suggests: a Clutch directory page renders
80 cards but holds far fewer distinct agencies, because promoted placements repeat inside a page and roughly
thirty of them ride along on every adjacent pair of pages. Those repeats are dropped, so a run asked for 500
agencies gets 500 distinct ones or the whole directory, whichever is smaller.

**Why is `hourly_rate` the word `Undisclosed` on some rows and empty on others?**
They mean different things and are deliberately not merged. `Undisclosed` is what Clutch renders when a firm
declines to publish a rate, which is an answer in its own right and is worth filtering on. An empty value
means no rate was read from that listing at all. Collapsing the first into the second would make a firm that
withholds its rate indistinguishable from a row that came back short.

**A path from the Agency List Actor was rejected. Why?**
Clutch publishes deeper, country- and city-scoped variants of its directories — `de/it-services/msp/berlin`
is a real page, and most of the paths in its index are that shape. This Actor walks one- and two-segment
paths. Deeper paths in the input list are skipped with a note in the log naming each one, and the rest of the
list still runs; a run fails only when every path it was given is that shape.

**Can more than one directory be scraped in a single run?**
Yes — `directory` takes a list, and the directories are walked in the order given. They share one `maxItems`
budget rather than getting one each, so a run over three directories with `maxItems: 100` saves 100 rows in
total, filling from the first directory before it starts the second. Set `maxItems` to `0` when each
directory should be walked to its end.

**Why does a large run take minutes?**
Requests to Clutch are paced, and that pacing is what keeps a long walk working rather than being cut off
partway. Agencies arrive roughly fifty per request, so the wall-clock time of a run scales with rows rather
than with how much data each row carries. A run of a few hundred agencies is a matter of minutes; the log
prints progress per directory as it goes.

**What is not in a row?**
The agency's own website, its founding year, its long description and its review text are on the agency's
profile page, not on the directory listing, and none of them are returned here. Everything above comes off
the listing itself.

### Related

- [Clutch Agency List — Every Agency & Directory URL](https://apify.com/thenetaji/clutch-agency-list-scraper)
  — every directory path Clutch publishes, which is where the `directory` input for this Actor comes from,
  and every agency profile URL with its key.

# Actor input Schema

## `directory` (type: `array`):

Paste the clutch.co directory page's link, or just the last part of its address (what's after clutch.co/). This only takes clutch.co's top-level category pages, like web-developers, it-services or agencies/digital-marketing. Clutch also publishes narrower pages scoped to one country and city, like de/it-services/msp/berlin — those aren't accepted here.

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

Maximum agencies to save across every directory in the run. Set 0 to walk each directory to its end. Agencies are collected roughly fifty per request, and requests are paced, so a large number takes minutes rather than seconds.

## `startPage` (type: `integer`):

Which page of the directory to start from, in Clutch's own numbering, where page 1 is the bare directory URL. A run continues into later pages on its own, so this is a resume point for a second run rather than a filter — the run log prints where it stopped.

## Actor input object example

```json
{
  "directory": [
    "web-developers",
    "agencies/digital-marketing"
  ],
  "maxItems": 20,
  "startPage": 1
}
```

# Actor output Schema

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

All records scraped by this run

# 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 = {
    "directory": [
        "web-developers"
    ],
    "maxItems": 20,
    "startPage": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("thenetaji/clutch-directory-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 = {
    "directory": ["web-developers"],
    "maxItems": 20,
    "startPage": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("thenetaji/clutch-directory-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 '{
  "directory": [
    "web-developers"
  ],
  "maxItems": 20,
  "startPage": 1
}' |
apify call thenetaji/clutch-directory-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thenetaji/clutch-directory-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/9qBAwACl7LwpLBm7M/builds/b3ibRLqF5xfZqb76V/openapi.json
