# Sortlist Agency Scraper (`reventadata/sortlist-scraper`) Actor

Scrapes Sortlist agency directory listings by service and country: name, tagline, website, offices, rating, reviews, team size, languages, services, budget range and awards. Filter by rating, reviews, team size, language or city. No proxy needed.

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

## Pricing

from $1.00 / 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.

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

## Sortlist Agency Scraper

> **Unofficial.** This Actor is not affiliated with, authorised by, endorsed by, or in any
> way officially connected to Sortlist. "Sortlist" is a trademark of its respective owner and
> is used here only to describe what this tool reads. It reads the same public listing pages a
> browser does.

Collects agencies from Sortlist's public directory listings (sortlist.com) as one row per
agency: website, offices, rating, review count, team size, languages, services, budget range
and awards, ready for a spreadsheet or a CRM import.

### What does it do?

Opens Sortlist listing pages such as `https://www.sortlist.com/s/web-application/belgium-be`
for every service and country you name, walks each listing to its last page and returns one
row per agency. An agency found in several listings is returned once.

### Why use it?

- **The whole listing, not the first page.** One request returns up to 100 agencies, and the
  Actor follows the site's own pagination until the listing ends. Belgium "Web Application"
  is 471 agencies in 6 requests.
- **Numbers as numbers.** Rating, review count, team size, works count and budget range come
  as numeric fields, not as page text.
- **Filters the site does not offer.** Minimum rating, minimum reviews, minimum team size,
  language and office city are applied after the fetch.
- **No proxy needed.** Plain page requests worked on Apify's platform in testing (25 of 25
  listing pages, with and without datacenter proxy).

### How to use it

1. Set `services` (for example `web-application`, `branding`, `marketing`) and `countries`
   (for example `belgium-be`, `germany-de`). Every service is searched in every country.
   Or paste full listing addresses into `listingUrls`.
2. Optionally set `minRating`, `minReviews`, `minTeamSize`, `languages` or `locationContains`.
3. Set `maxItems` and run. Download JSON, CSV or Excel from the dataset.

#### Input

| Field | Type | Description |
|---|---|---|
| `services` | array | Service slugs from `sortlist.com/s/<service>/<country>`, such as `web-application`, `branding`, `web-design`, `marketing`, `software-development`, `cloud-computing`. |
| `countries` | array | Country slugs `<country>-<code>`, such as `belgium-be`, `germany-de`, `france-fr`, `switzerland-ch`. |
| `listingUrls` | array | Full `https://www.sortlist.com/s/<service>/<country>` addresses, used in addition to the two fields above. |
| `minRating` | number | Minimum client rating out of 5. Agencies without reviews have no rating and are dropped when this is set. |
| `minReviews` | integer | Minimum number of client reviews. |
| `minTeamSize` | integer | Minimum team size the agency states. |
| `languages` | array | Keep agencies working in any of these languages (`en`, `fr`, `nl`, `de`). `nl-BE` counts as `nl`. |
| `locationContains` | string | Keep agencies with an office whose English place text contains this, ignoring case and accents (for example `Antwerp`). |
| `maxItems` | integer | Most agencies to return across all listings. |
| `proxyConfiguration` | object | Optional. The default uses no proxy. |

#### Sample input

```json
{
    "services": ["web-application"],
    "countries": ["belgium-be"],
    "minRating": 4.5,
    "maxItems": 20
}
```

#### Output

Each row holds `id`, `url`, `name`, `tagline`, `description`, `website`, `logo`, `locations`,
`languages`, `teamSize`, `registrationNumber`, `registrationCountry`, `rating`,
`reviewsCount`, `recentRecommendedReviews`, `worksCount`, `serviceWorksCount`,
`serviceBudgetMin`, `serviceBudgetMax`, `budgetMin`, `budgetMax`, `services`, `sectors`,
`awards`, `topAwarded`, `trustedPartner`, `verified`, `claimed`, `sponsored`, `updatedAt`,
`searchService`, `search` and `scrapedAt`.

- `rating` is the client score out of 5, worked out as the site's review total divided by its
  review count times 5, to two decimals. The site shows it cut to one decimal. It is empty for
  an agency without reviews.
- `serviceWorksCount`, `serviceBudgetMin` and `serviceBudgetMax` describe the listing that
  returned the agency first. `worksCount`, `budgetMin`, `budgetMax` and `services` describe
  the agency as a whole.
- Budgets are shown in euros on the Belgium, Germany and Switzerland listings that were
  checked. Other markets were not checked, so confirm the currency before relying on it. A
  budget is empty when the agency gave none, and many agencies show 1000000 as the upper end:
  the site does not say what that value means.
- `url` is the agency's Sortlist profile page. The Actor does not open it. The listing data has
  no e-mail or phone field; `website` is the contact route it gives. Some agencies write an
  e-mail address into their own description (19 of 1,000 in a 2026-10-21 run), and it ships as
  written there.

#### Sample output

One real row from the Belgium "Web Application" listing, with the description, services and
sectors shortened:

```json
{
    "id": "fa2146d2-016b-4c81-9e2f-af6f1bb347ea",
    "url": "https://www.sortlist.com/agency/code-the-kiwi",
    "name": "Code The Kiwi",
    "tagline": "Maatwerk software web & mobile",
    "description": "Bij Code The Kiwi zijn we gespecialiseerd in het creëren van robuuste, schaalbare oplossingen die zijn afgeste...",
    "website": "https://codethekiwi.be",
    "logo": "https://sortlist-core-api.s3.eu-west-1.amazonaws.com/58arpu4ux2cu0n1hqvrgipw0n43d",
    "locations": [
        "Sint-Katelijne-Waver, Belgium"
    ],
    "languages": [
        "nl-BE",
        "en",
        "nl"
    ],
    "teamSize": 5,
    "registrationNumber": "1013800151",
    "registrationCountry": "BE",
    "rating": 5.0,
    "reviewsCount": 1,
    "recentRecommendedReviews": 0,
    "worksCount": 10,
    "serviceWorksCount": 10,
    "serviceBudgetMin": 3000,
    "serviceBudgetMax": 1000000,
    "budgetMin": 1000,
    "budgetMax": 1000000,
    "services": [
        {
            "name": "Web Application",
            "worksCount": 10
        },
        {
            "name": "Software Development",
            "worksCount": 10
        },
        {
            "name": "Artificial Intelligence",
            "worksCount": 3
        }
    ],
    "sectors": [
        "Others",
        "E-commerce",
        "Transportation"
    ],
    "awards": [
        {
            "name": "Microsoft Partner",
            "category": "",
            "wonAt": "2022-04-01"
        },
        {
            "name": "Google Partner",
            "category": "",
            "wonAt": "2022-04-01"
        },
        {
            "name": "Mollie partner",
            "category": "",
            "wonAt": "2022-11-01"
        }
    ],
    "topAwarded": false,
    "trustedPartner": false,
    "verified": true,
    "claimed": true,
    "sponsored": true,
    "updatedAt": "2026-09-30T13:32:07.483Z",
    "searchService": "Web Application",
    "search": "web-application/belgium-be",
    "scrapedAt": "2026-10-21T18:32:47+00:00"
}
```

### Limits

- Only listings of the form `https://www.sortlist.com/s/<service>/<country>` are read. Other
  Sortlist address shapes (`/i/...`, or `/<service>/<city>`), agency profile pages and the
  site's `/api/` paths are not read.
- A service or country the site does not know is skipped with a warning in the log. The same
  service can be missing in one country and present in another. When the site moves a listing
  to a differently named page, the Actor follows it only if the new page is also a `/s/`
  listing.
- The country slug must be the site's own. `united-states-us` and `united-kingdom-gb` have no
  `/s/` listing.
- Rating, review and budget numbers are reported as the site shows them. No review text is
  collected.

### How much does it cost to scrape Sortlist?

Pay-per-event: **$0.001 per agency** saved to the dataset (**$1.00 per 1,000 agencies**), plus
**$0.00005** charged once when the run starts. No subscription. The rating, review, team-size,
language and location filters run before a row is saved, so agencies they drop are not charged.

### Privacy and compliance

Rows carry public directory data: agency names, websites, office places, registration numbers
the agency published, awards and review counts. Nothing behind a login is read. Sortlist's
terms of use restrict scraping and copying of profiles; you are responsible for how you use
the data and for complying with the site's terms and applicable law.

# Actor input Schema

## `services` (type: `array`):

Sortlist service slugs, as in https://www.sortlist.com/s/<service>/<country>: for example web-application, branding, web-design, marketing, software-development, cloud-computing. Each service is searched in every country below. A slug the site does not know is skipped with a warning.

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

Sortlist country slugs in the form <country>-<two-letter code>: for example belgium-be, germany-de, france-fr, switzerland-ch. Each country is searched for every service above.

## `listingUrls` (type: `array`):

Optional full listing addresses in the form https://www.sortlist.com/s/<service>/<country>, copied from the site. Used in addition to services and countries. The page number and any filters in the address are ignored.

## `minRating` (type: `number`):

Only agencies whose client rating (out of 5) is at least this. Agencies without reviews have no rating and are dropped when this is set. Applied after the fetch.

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

Only agencies with at least this many client reviews. Applied after the fetch.

## `minTeamSize` (type: `integer`):

Only agencies whose stated team has at least this many people. Applied after the fetch.

## `languages` (type: `array`):

Only agencies that work in at least one of these languages, as two-letter codes such as en, fr, nl, de. A regional code such as nl-BE counts as nl. Applied after the fetch.

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

Only agencies with an office whose English place text contains this, ignoring case and accents: for example Brussels, Antwerp or Ghent. Applied after the fetch.

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

Most agencies to return across all listings. An agency that appears in several listings is returned once.

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

Proxy settings. The default needs no proxy; datacenter proxy also worked in testing.

## Actor input object example

```json
{
  "services": [
    "web-application"
  ],
  "countries": [
    "belgium-be"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Marketing and software agencies from the Sortlist directory.

# 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 = {
    "services": [
        "web-application"
    ],
    "countries": [
        "belgium-be"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("reventadata/sortlist-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 = {
    "services": ["web-application"],
    "countries": ["belgium-be"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("reventadata/sortlist-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 '{
  "services": [
    "web-application"
  ],
  "countries": [
    "belgium-be"
  ],
  "maxItems": 20
}' |
apify call reventadata/sortlist-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,reventadata/sortlist-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/2iQEt7CvWdJZoJPHe/builds/2LDMVPXcJeicJQsnG/openapi.json
