# Craigslist Scraper & Monitor (`hydedata/craigslist-scraper`) Actor

Scrape Craigslist by keyword, city, ZIP radius, state or nationwide, with complete results past Craigslist's 360 cap. Monitor mode returns only new listings, price drops and reposts, with Discord, Slack and Telegram alerts. Deal scores, repost detection, scam flags and VIN decoding included.

- **URL**: https://apify.com/hydedata/craigslist-scraper.md
- **Developed by:** [Jacob Hyde](https://apify.com/hydedata) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 listings

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

## Craigslist Scraper & Monitor

Scrape Craigslist listings by keyword and location: a city, a ZIP code with a radius, whole states, or
every Craigslist site in the US at once. You get **every** matching listing, not just the first 360 that
Craigslist's own search shows. No account or login needed.

Turn on **monitor mode** and schedule it: each run returns only what's new since the last run (new
listings, price drops, reposts, and optionally listings that sold or were removed) and can post them to
Discord, Slack or Telegram. You're never billed for a listing you've already received.

Every listing also gets a **deal score** against similar listings in the same search, **repost
detection** by photo, and **scam-risk flags**. Vehicles get **VIN decoding and safety recalls** from
NHTSA. All included, no extra charge.

### What you get

For every listing:

| Field | Example |
| --- | --- |
| Title, price and currency | 2023 Honda Civic EX 4dr Sedan, 17900, USD |
| Posted date | 2026-09-27T16:27:19Z |
| Location, coordinates and distance from your search point | Katy, houston, TX, 29.74, -95.64, 12.4 mi |
| Every photo | image links |
| Category and owner or dealer | cars & trucks - by dealer |
| Mileage (vehicles), bedrooms and square feet (housing), pay (jobs) | 90174 mi / 2 BR, 1065 sq ft |
| **Deal rating**: price against the median of comparable listings | great, 23% below market ($19,500) |
| **Repost group**: the same item posted several times | 1 of 4 postings, duplicate: true |
| **Scam-risk level** and the reasons | medium: price-far-below-market |
| Link to the listing | craigslist.org/view/d/... |

In monitor mode each row also says what changed (`new`, `price-drop`, `repost`, `renewed` or `removed`),
the previous price, and when it was first seen.

Turn on **Add listing details** to also get the full description, every attribute (VIN, title status,
condition, drive, fuel, bathrooms, laundry, parking...), the updated date and the map address. Vehicles
with a VIN are decoded (year, make, model, trim, engine, drivetrain) and matched with open NHTSA safety
recalls.

Seller names and contact details aren't collected.

### How to use it

#### Search by keyword and location

Add keywords, a category and one or more locations. A location can be:

- a city: `"Plano, TX"`, `"Toronto, ON"`, `"London, UK"`
- a ZIP or Canadian postal code: `"78704"`, `"M5V 2T6"`
- a Craigslist site: `"sfbay"`, `"orlando"`, `"SF bay area"`

Cities and postal codes search a radius around them (25 miles unless you set **Radius**), across
Craigslist site borders. Site names search that whole site.

```json
{
  "searchQueries": ["toyota tacoma", "4runner"],
  "category": "cta",
  "locations": ["Plano, TX", "78704"],
  "radiusMiles": 60,
  "maxItemsPerSearch": 500
}
```

#### Search whole states or the whole country

```json
{
  "searchQueries": ["airstream"],
  "category": "rva",
  "searchEverywhere": "US",
  "sortBy": "best_deal"
}
```

**Whole states or provinces** (`"TX"`, `"Florida"`, `"ON"`) searches every Craigslist site in them.
**Search everywhere** covers the US, Canada, both, or every Craigslist site worldwide. A nationwide US
search reads all 413 US sites in about a minute and a half.

#### Complete results

Craigslist's search page stops at 360 results. This Actor reads the full result set, so a search for
every apartment in Orlando returns all 8,000+, and sorting by price or deal finds the real cheapest ones,
not the cheapest of the newest 360.

#### Deals, reposts and scam flags

- **Deal scores** compare each price with similar listings in the same search: vehicles by model year
  and mileage, housing by bedrooms, everything else within the same kind of item. Ratings: `great` (20%+
  below market), `good` (8%+ below), `fair`, `high` (10%+ above). Sort by **Best deals first** to put
  them on top, or only get alerts for good deals.
- **Repost detection** matches postings by their photos. A single Orlando apartment was posted 88 times
  under different titles; you get it once. Turn on **Hide reposts** to drop the copies before you're
  charged.
- **Scam-risk flags** mark listings priced far below comparable ones, photos reused 100+ miles apart
  (the classic copied rental), and, with details on, phrases common in scams: wire transfers or gift
  cards, deposits before viewing, owners out of the country, shipping-only deals.

A **market snapshot** per search is saved too (Output tab, Market snapshot): listing count, median and
quartile prices, new listings in the last day and week, owner vs dealer, and median rent by bedrooms.

#### Filters

All of Craigslist's filters are inputs, grouped by what you're searching:

- **Everything:** price, posted within N hours, owner or dealer, condition, has image, titles only,
  delivery available.
- **Vehicles:** make and model, model year, odometer, title status, transmission, fuel, drive, body
  type, cylinders, paint color.
- **Housing:** bedrooms, bathrooms, square feet, housing type, laundry, parking, cats, dogs, furnished,
  no smoking, wheelchair accessible, AC, EV charging, no broker or application fee.
- **Jobs and gigs:** employment type, remote, internship, non-profit, paid gigs.

Craigslist matches keywords anywhere in a post, so a "tacoma" search also returns cars that mention a
Tacoma in the description. **Only keep listings whose title matches the keywords** and **Exclude listings
with these words** drop that noise before you're charged. Craigslist's own syntax works in keywords:
`road bike | gravel bike` matches either, `-kids` excludes a word.

#### Paste search URLs

Run any search on craigslist.org and paste its URL into **Craigslist search URLs**. Every filter in the
URL is kept.

#### Monitor new listings and changes

1. Set up your searches and turn on **Monitor mode**.
2. Run it once. The first run is the baseline.
3. Add a schedule (every 15 minutes, hourly, daily). Each later run returns only new listings, price
   drops and reposts. Turn on **Include renewed listings** to also see listings sellers bumped, and
   **Report removed listings** to see what sold or disappeared, with how many days it was listed.

A quiet check reads a whole search in one or two requests, so frequent schedules stay cheap. Use a
different **Monitor state store name** for each independent monitor.

#### Get alerts

- **Discord or Slack:** paste an incoming webhook URL. Each listing shows with photo, price, deal
  rating, distance and link.
- **Telegram:** add a bot token (from @BotFather) and a chat ID.
- **Any other URL** receives the listings as JSON.

Nothing is sent when a run finds nothing new. **Only alert on deals** limits alerts to good or great
deals while the dataset still gets everything. For email, Google Sheets, Zapier or Make, use Apify's
integrations on the Actor or your task.

### Pricing

You pay per event. Platform usage is included.

| Event | Price |
| --- | --- |
| Listing delivered | $0.001 ($1 per 1,000) |
| Listing details (optional) | $0.001 per listing with details |
| Search checked (once per keyword and location on each run) | $0.001 |
| Run start | $0.00005 |

Deal scores, repost detection, scam flags, market snapshots, VIN decoding and recalls are free.

Examples:

- **Pull 1,000 listings once:** $1.00 for the listings plus $0.001 for the search.
- **1,000 cars with full details, VINs and recalls:** $2.00.
- **Watch one search every hour for a month:** 720 checks x $0.001 = $0.72, plus $0.001 per new
  listing.
- **Nationwide search:** searches spanning many Craigslist sites count one search per 25 sites, so a
  whole-US search is $0.017 per run plus listings.

Listings you've already received are never billed in monitor mode, and listings your filters drop are
never billed. A search that fails or comes back empty is never billed. Set a maximum charge per run in
the run options and the Actor stops cleanly when it's reached.

### Output example

```json
{
  "id": "7973798862",
  "url": "https://www.craigslist.org/view/d/houston-2023-honda-civic-ex-4dr-sedan/rLwUTpC68RG_nanPRqzzgQ",
  "title": "2023 Honda Civic EX 4dr Sedan",
  "price": 17900,
  "currency": "USD",
  "category": "ctd",
  "categoryName": "cars & trucks - by dealer",
  "sellerType": "dealer",
  "postedAt": "2026-09-27T16:27:19.000Z",
  "area": "houston",
  "locationText": "Katy",
  "latitude": 29.7458,
  "longitude": -95.6453,
  "distanceMiles": 12.4,
  "photoUrl": "https://images.craigslist.org/00505_5xoSIIkuFP2_0g80c6_600x450.jpg",
  "photoCount": 17,
  "odometer": 90174,
  "year": 2023,
  "marketPrice": 19500,
  "comparableCount": 14,
  "priceVsMarket": -0.08,
  "dealRating": "good",
  "repostGroupSize": 1,
  "isDuplicate": false,
  "riskFlags": [],
  "riskLevel": "low",
  "changeType": "new",
  "vin": "2HGFE1F77PH304701",
  "vinTrim": "EX",
  "vinEngineLiters": 1.5,
  "recallCount": 4,
  "searchKeyword": "honda civic",
  "searchLocation": "25 mi around 77077",
  "scrapedAt": "2026-09-27T18:00:00.000Z"
}
```

The Output tab has views for listings, deals, monitor changes, vehicles and housing. Download results as
JSON, CSV, Excel or HTML, or read them through the Apify API.

### FAQ

**Do I need a Craigslist account?**
No. The Actor only reads what anyone can see on Craigslist without logging in.

**Can I get seller emails or phone numbers?**
No. Craigslist hides reply addresses behind a CAPTCHA, and this Actor doesn't collect contact details.
The listing description is included as posted.

**How accurate are deal scores?**
They compare against the listings in your own search, so they're as good as the search is specific.
"2015-2018 Toyota Tacoma" gives sharper scores than "truck". Vehicles without a model year in the
title get a score once details supply the year.

**Location not found?**
Try "City, ST", a ZIP code, or a Craigslist site name as it appears in its address (sfbay for
sfbay.craigslist.org).

**Is it legal to scrape Craigslist?**
The Actor collects only publicly visible listing data and no personal profiles. How you use the data is
up to you; check the rules that apply where you are.

**Something broke?**
Open an issue on the Actor's Issues tab. The Actor is tested against live Craigslist every day.

Place names for city lookups come from [GeoNames](https://www.geonames.org/) (CC BY 4.0). Vehicle data
comes from NHTSA's public APIs.

# Changelog

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

# Actor input Schema

## `searchQueries` (type: `array`):

What to search for. Each keyword is its own search in every location below. Leave empty to browse the whole category. Craigslist syntax works: "road bike | gravel bike" matches either, "-kids" excludes a word.

## `category` (type: `string`):

Craigslist section to search. "for sale (all)" covers every for-sale category. The "by owner" and "by dealer" entries search only that kind of seller.

## `locations` (type: `array`):

Where to search. Any of: "City, ST" ("Plano, TX", "Toronto, ON"), a ZIP or Canadian postal code ("78704", "M5V 2T6"), or a Craigslist site name ("sfbay", "orlando", "SF bay area"). Cities and postal codes search the radius below; site names search that whole Craigslist site.

## `radiusMiles` (type: `integer`):

Search this far around each city or postal code, across Craigslist site borders. Defaults to 25 miles. With a site name, searches this far around the site's center instead of the whole site. Up to 250 miles uses Craigslist's own radius search; bigger radii search every site in range.

## `searchStates` (type: `array`):

Search every Craigslist site in these states or provinces, e.g. "TX", "Florida", "ON".

## `searchEverywhere` (type: `string`):

Search every Craigslist site in a country at once. Each site is one request, so a nationwide US search is about 410 requests (still only a few MB).

## `searchUrls` (type: `array`):

Optional. Run a search on craigslist.org with any filters and paste its URL. Every filter in the URL is kept. Can be combined with keywords.

## `categoryCode` (type: `string`):

Any Craigslist category code, overriding the list above, e.g. "sof" for software jobs or "lbs" for labor and moving services.

## `minPrice` (type: `integer`):

Lowest price.

## `maxPrice` (type: `integer`):

Highest price.

## `postedWithinHours` (type: `integer`):

Only listings posted or renewed in the last this many hours, e.g. 24.

## `sellerType` (type: `string`):

Owners, dealers, or both. Works with any for-sale category; the "by owner" and "by dealer" categories do the same for one section.

## `conditions` (type: `array`):

Only listings in these conditions. Leave empty for any.

## `hasImage` (type: `boolean`):

Only listings with photos.

## `searchTitlesOnly` (type: `boolean`):

Craigslist matches keywords in the title only instead of the whole post.

## `strictKeywordMatch` (type: `boolean`):

Craigslist matches keywords anywhere in a post, so a "tacoma" search also returns cars whose description mentions a Tacoma. When on, a listing is kept only if its title contains every keyword word ("bike" also matches "bikes"). Dropped listings aren't charged.

## `excludeKeywords` (type: `array`):

Drop listings whose title contains any of these words or phrases, e.g. "parts", "wanted", "kids". Dropped listings aren't charged.

## `deliveryAvailable` (type: `boolean`):

Only listings that offer delivery.

## `hideCraigslistDuplicates` (type: `boolean`):

Craigslist's own duplicate bundling. The Actor's repost grouping (below) catches more.

## `makeModel` (type: `string`):

Vehicle make and/or model as Craigslist matches it, e.g. "toyota tacoma".

## `minYear` (type: `integer`):

Oldest model year.

## `maxYear` (type: `integer`):

Newest model year.

## `minMiles` (type: `integer`):

Lowest mileage.

## `maxMiles` (type: `integer`):

Highest mileage.

## `titleStatus` (type: `array`):

Leave empty for any.

## `transmission` (type: `array`):

Leave empty for any.

## `fuelType` (type: `array`):

Leave empty for any.

## `drivetrain` (type: `array`):

Leave empty for any.

## `bodyType` (type: `array`):

Leave empty for any.

## `cylinders` (type: `array`):

Leave empty for any.

## `paintColor` (type: `array`):

Leave empty for any.

## `minBedrooms` (type: `integer`):

Fewest bedrooms.

## `maxBedrooms` (type: `integer`):

Most bedrooms.

## `minBathrooms` (type: `integer`):

Fewest bathrooms.

## `maxBathrooms` (type: `integer`):

Most bathrooms.

## `minSqft` (type: `integer`):

Smallest size.

## `maxSqft` (type: `integer`):

Largest size.

## `housingTypes` (type: `array`):

Leave empty for any.

## `laundry` (type: `array`):

Leave empty for any.

## `parking` (type: `array`):

Leave empty for any.

## `catsOk` (type: `boolean`):

Only listings marked cats ok.

## `dogsOk` (type: `boolean`):

Only listings marked dogs ok.

## `furnished` (type: `boolean`):

Only listings marked furnished.

## `noSmoking` (type: `boolean`):

Only listings marked no smoking.

## `wheelchairAccessible` (type: `boolean`):

Only listings marked wheelchair accessible.

## `airConditioning` (type: `boolean`):

Only listings marked air conditioning.

## `evCharging` (type: `boolean`):

Only listings marked ev charging.

## `noBrokerFee` (type: `boolean`):

Only listings marked no broker fee.

## `noApplicationFee` (type: `boolean`):

Only listings marked no application fee.

## `employmentTypes` (type: `array`):

Leave empty for any.

## `telecommuting` (type: `boolean`):

Only jobs that allow telecommuting.

## `internship` (type: `boolean`):

Only internships.

## `nonprofit` (type: `boolean`):

Only non-profit organizations.

## `paidGigsOnly` (type: `boolean`):

Only gigs marked as paid.

## `extraSearchParams` (type: `object`):

Any other Craigslist search parameter, as it appears in a search URL, e.g. {"crypto\_currency\_ok": 1} or {"language": \[5, 6]}.

## `maxItemsPerSearch` (type: `integer`):

Upper limit of listings delivered per keyword and location (or search URL). Craigslist's own search stops at 360 results; this Actor reads the complete result set, so this can be in the thousands. In monitor mode, listings past this limit on the first run are remembered as seen.

## `sortBy` (type: `string`):

Which listings come first, and so which ones make the cut when a search has more than the max. "Best deals" sorts by price against comparable listings.

## `includeDetails` (type: `boolean`):

For each delivered listing, also get its full description, every attribute (VIN, title status, condition, bathrooms, laundry...), updated date and map address. Charged per listing that gets details. In monitor mode only new and changed listings are fetched. Seller names and contact details are never collected.

## `enrichVehicles` (type: `boolean`):

With details on, vehicles with a VIN get year, make, model, trim, engine and drivetrain from NHTSA's VIN decoder, plus open safety recalls for that model. No extra charge.

## `dealScores` (type: `boolean`):

Compare each listing's price with similar listings in the same search (vehicles by model year and mileage, housing by bedrooms) and rate it great, good, fair or high. Free.

## `groupReposts` (type: `boolean`):

Spot the same item posted more than once, by its photos, and mark every copy but the newest as a duplicate.

## `hideReposts` (type: `boolean`):

Drop duplicate postings before you're charged for them. In monitor mode, also skips reposts of listings you've already seen.

## `riskFlags` (type: `boolean`):

Flag listings priced far below comparable ones, photos reused 100+ miles apart, and (with details) phrases common in scams like wire transfers, deposits before viewing and owners out of the country.

## `marketSnapshot` (type: `boolean`):

Save a summary per search to the key-value store (MARKET\_SNAPSHOT): listing count, median and quartile prices, new listings in the last day and week, owner vs dealer, and median rent by bedrooms.

## `monitorMode` (type: `boolean`):

Remembers what previous runs returned and only outputs new listings, price drops and reposts. Use with a Schedule. The first run returns listings as the baseline.

## `includeRenewed` (type: `boolean`):

In monitor mode, also output listings the seller renewed (bumped to the top) since the last run.

## `reportRemoved` (type: `boolean`):

In monitor mode, add a row for each listing that disappeared since the last run (sold, deleted or expired), with how many days it was listed. Charged as a listing.

## `notifyWebhookUrl` (type: `string`):

Paste a Discord or Slack incoming webhook URL to get each run's listings as a message, with photo, price, deal rating and link. Any other URL gets the listings as JSON. Only sent when the run delivers something.

## `telegramBotToken` (type: `string`):

Also send alerts to Telegram. Create a bot with @BotFather and paste its token here.

## `telegramChatId` (type: `string`):

The chat, group or channel ID the bot posts to.

## `notifyMinDealRating` (type: `string`):

Only send alerts for listings rated at least this good. The dataset still gets every listing.

## `stateStoreName` (type: `string`):

Named key-value store that keeps monitor memory between runs. Use different names to run independent monitors.

## `stateRetentionDays` (type: `integer`):

Listings not seen for this many days are dropped from monitor memory.

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

Apify Proxy is recommended.

## Actor input object example

```json
{
  "searchQueries": [
    "road bike"
  ],
  "category": "sss",
  "locations": [
    "Orlando, FL"
  ],
  "searchEverywhere": "",
  "sellerType": "all",
  "hasImage": false,
  "searchTitlesOnly": false,
  "strictKeywordMatch": false,
  "deliveryAvailable": false,
  "hideCraigslistDuplicates": false,
  "catsOk": false,
  "dogsOk": false,
  "furnished": false,
  "noSmoking": false,
  "wheelchairAccessible": false,
  "airConditioning": false,
  "evCharging": false,
  "noBrokerFee": false,
  "noApplicationFee": false,
  "telecommuting": false,
  "internship": false,
  "nonprofit": false,
  "paidGigsOnly": false,
  "maxItemsPerSearch": 100,
  "sortBy": "newest",
  "includeDetails": false,
  "enrichVehicles": true,
  "dealScores": true,
  "groupReposts": true,
  "hideReposts": false,
  "riskFlags": true,
  "marketSnapshot": true,
  "monitorMode": false,
  "includeRenewed": false,
  "reportRemoved": false,
  "notifyMinDealRating": "any",
  "stateStoreName": "craigslist-monitor-state",
  "stateRetentionDays": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `listings` (type: `string`):

Dataset items, one per delivered listing. Field meanings are in the dataset schema.

## `marketSnapshot` (type: `string`):

Per search: listing count, median and quartile prices, freshness, owner vs dealer, rent by bedrooms.

# 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 = {
    "searchQueries": [
        "road bike"
    ],
    "locations": [
        "Orlando, FL"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("hydedata/craigslist-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 = {
    "searchQueries": ["road bike"],
    "locations": ["Orlando, FL"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("hydedata/craigslist-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 '{
  "searchQueries": [
    "road bike"
  ],
  "locations": [
    "Orlando, FL"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call hydedata/craigslist-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hydedata/craigslist-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/Zoj1DpctJIdX5MWTh/builds/XEgh63c6F5aDDEVZ1/openapi.json
