# Collecting Cars \[$3💰] | 33k SOLD prices + live bids (`memo23/collectingcars-scraper`) Actor

💰$3 per 1,000 lots. Turn Collecting Cars into auction-results data: ~33,000 finished lots with their sale prices, plus every live lot with its current bid and closing time. Filter by country, make, year and price. Optional VIN, colours, original market and full write-up.

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

## Pricing

from $3.00 / 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/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

## Collecting Cars Scraper

**Turn Collecting Cars into a structured auction dataset: every live lot with its current bid, and the full archive of ~33,000 finished lots with the price each one sold for.** Scrape cars, motorbikes, watches and number plates with make, model, generation, year, mileage, bid count, reserve state, closing time, country and seller type, then optionally add VIN, exterior and interior colour, engine size, original market, the seller's write-up and every photo. Filter by country, make, model, year and price. JSON, CSV or Excel out.

💰 **$3 per 1,000 lots.** No monthly fee, no proxy bill, no subscription.

#### How it works

![How the Collecting Cars Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-collectingcars.png)

#### ✨ Why use this scraper?

The collectingcars.com listing grid only shows the ~300 auctions that are live right now. Once a lot finishes it drops off the grid, and with it the result it made. This Actor reads the site's own search index instead, which still holds every finished lot, so the whole sold archive comes back with its prices.

- **~33,000 sold lots with their sale price.** 99.9% of the archive carries one, with the final bid, bid count and date sold.
- **Live and upcoming lots too:** current bid, bid count, reserve state and the exact closing time, so you can follow an auction as it runs.
- **No result ceiling.** 250 lots per request with no cut-off, so the entire catalogue is reachable in about 140 requests.
- **Filter the way a buyer does:** country, make, model, year, price, drive side, seller type, no-reserve only and sale format.
- **Optional detail pass** adds VIN, engine size, exterior and interior colour, body style, registration, original market, the seller's full write-up, every photo, and view and watcher counts.
- **Cars, bikes, watches, plates and parts.** Collecting Cars and its sister site Watch Collecting share one catalogue, and both are covered.

#### 🎯 Use cases

| Team | What they build |
|------|-----------------|
| **Valuation & price guides** | Sale prices by make, model, generation, year and country from ~33,000 real results |
| **Dealers & traders** | Sourcing lists of live lots in chosen countries, and comps for what a model actually fetched |
| **Market analysts** | Price trends over time, and how UK results compare with German, Swedish or Australian ones |
| **Insurers & lenders** | Evidence-based agreed values for collector-car policies and finance |
| **Auction watchers** | Daily feeds of new consignments with `listedWithinHours`, plus live bid tracking |
| **ML / data teams** | Training data that pairs spec, mileage, location and bidding activity with a real sale price |

#### 📥 Supported inputs

You don't need a URL. Set the filters and run. `startUrls` is optional:

| Input | Behaviour |
|---|---|
| Nothing at all | Returns the auctions live right now |
| `https://collectingcars.com/buy?refinementList[productMake][0]=Porsche` | **Search:** the page's filters are translated into the same search the site runs |
| `https://collectingcars.com/makes/Honda/48/NSX/18435` | **Make/model page:** read as a make and model filter |
| `https://collectingcars.com/for-sale/1990-honda-nsx-1` | **Single lot:** scrapes just that lot, always with its full detail |
| `https://watchcollecting.com/for-sale/...` | **Watch lot** from the sister site |

Paste as many URLs as you like. Results are de-duplicated by lot ID across all of them, so overlapping searches never bill twice, and `maxItems` is a total across every URL.

If the Actor cannot read any filter from a search URL you paste, it stops with an error rather than running. An unreadable URL would otherwise fall through to scraping the whole catalogue instead of your selection. A run given only single-lot URLs scrapes exactly those lots and nothing else.

**Not supported:** hosts other than collectingcars.com and watchcollecting.com, and the price-range sliders on the site's search page (set `priceMin`/`priceMax` on the input instead).

#### ⚠️ Proxy requirement

None for the search itself, which is why a run without the detail option is fast and cheap. The lot pages behind the detail option sit behind Cloudflare and need a residential IP. One is built in, so leave `proxy` empty unless you want to use your own.

#### 🔄 How it works

1. Your filters, or the URLs you pasted, become one search against the site's search index.
2. Lots come back 250 per request until `maxItems` is reached or the matches run out.
3. Each lot becomes one row; lots already seen in another search are skipped.
4. With `includeDetails` on, each lot's own page is fetched through the residential proxy and its VIN, colours, engine, registration, original market, description, gallery and view counts are merged into the row.
5. Rows are pushed to the dataset, ready to export as JSON, CSV or Excel.

#### ⚙️ Input parameters

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `startUrls` | array | `[]` | Collecting Cars search, make/model or lot URLs |
| `listingStage` | select | `live` | `live`, `comingsoon`, `active` (live + coming soon), **`sold`**, `all` |
| `lotTypes` | array | `["car"]` | `car`, `bike`, `watch`, `plate`, `part` |
| `saleFormats` | array | all | `auction`, `buyItNow`, `offer` |
| `makes` | array | – | e.g. `["Porsche", "Ferrari"]`; spelling and case are forgiving |
| `models` | array | – | e.g. `["911"]`; must match the site's model name |
| `keywords` | string | – | Free text across titles, makes and models |
| `countries` | array | all | ISO-2 codes of where the lot is, e.g. `["GB", "DE", "AU"]` |
| `regions` | array | all | The site's groupings, e.g. `UK`, `EU`, `AU`, `US` |
| `driveSide` | select | any | `left` / `right` |
| `sellerType` | select | any | `private` / `trade` / `managed` |
| `noReserveOnly` | boolean | `false` | Only lots offered without a reserve |
| `priceMin` / `priceMax` | integer | – | In the lot's own currency; bounds the sale price, or the current bid on a lot still running |
| `yearMin` / `yearMax` | integer | – | Model year |
| `listedWithinHours` | integer | – | Only lots published in the last N hours; `24` makes a daily new-listings feed |
| `sortBy` | select | `relevance` | `newest`, `endingSoonest`, `recentlySold`, `priceHighest`, `priceLowest`, `bidHighest`, `mostBids` |
| `includeDetails` | boolean | `false` | Fetch each lot's page for VIN, colours, description, gallery and more |
| `maxItems` | integer | `1000` | Total lots to return. The sold archive holds ~33,000, so set it deliberately |
| `maxConcurrency` | integer | `10` | Parallel lot-page requests when `includeDetails` is on |
| `proxy` | object | built-in residential | Used only for lot pages |

> **For sale prices, set `listingStage` to `sold`.** The default, `live`, matches what collectingcars.com/buy shows and keeps an exploratory run to a few hundred rows.

##### Example input

Every Porsche 911 sold in the UK or Germany, newest sales first, with full detail:

```json
{
    "listingStage": "sold",
    "lotTypes": ["car"],
    "makes": ["Porsche"],
    "models": ["911"],
    "countries": ["GB", "DE"],
    "sortBy": "recentlySold",
    "includeDetails": true,
    "maxItems": 2000
}
```

#### 📊 Output overview

One row per lot. The core fields come from the search index and are filled on every row. The detail fields (VIN, colours, engine, registration, original market, description, gallery, view and watcher counts) are `null` or empty unless `includeDetails` is on. Every field appears on every row, so CSV columns never shift between runs.

#### 📦 Output sample

A real row, trimmed:

```json
{
  "lotId": "91887",
  "lotUrl": "https://collectingcars.com/for-sale/1990-honda-nsx-1",
  "title": "1990 Honda NSX",
  "lotType": "car",
  "listingStage": "sold",
  "isSold": true,
  "saleFormat": "auction",
  "saleType": "buy_now",
  "currency": "GBP",
  "currentBid": 46750,
  "soldPrice": 50000,
  "bidCount": 58,
  "noReserve": false,
  "reserveMet": false,
  "auctionEndedAt": "2026-09-17T18:22:32.000Z",
  "soldAt": "2026-09-23T18:18:53.000Z",
  "publishedAt": "2026-09-10T10:00:08.000Z",
  "make": "Honda",
  "model": "NSX",
  "variant": "Base Model",
  "generation": "1st Gen - NA1",
  "year": 1990,
  "mileage": "67,265 Miles (Indicated)",
  "fuelType": "Petrol",
  "transmission": "automatic",
  "driveSide": "right",
  "country": "GB",
  "region": "UK",
  "location": "Surrey",
  "sellerType": "private",
  "priceGbp": 50000,
  "priceUsd": 66698,
  "priceEur": 58258,

  "vin": "JHMNA12600T000145",
  "engineSize": "3.0L V6",
  "bodyStyle": "coupe",
  "exteriorColour": "Red",
  "interiorColour": "Black",
  "originalMarket": null,
  "description": "KEY FACTS This Honda NSX is an iconic and highly engaging modern classic performance coupe. It is powered by a 3.0-litre V6 …",
  "imageCount": 132,
  "viewCount": 6632,
  "watcherCount": 318
}
```

This lot shows why `saleType` matters: bidding closed at £46,750 under the reserve, and the car sold afterwards for £50,000.

#### 🗂 Key output fields

| Group | Fields |
|---|---|
| **State** | `listingStage` (`live` / `comingsoon` / `sold`), `isLive`, `isSold`, `saleFormat`, `saleType` |
| **Price** | `soldPrice`, `currentBid`, `bidCount`, `currency`, `buyNowPrice`, `priceGbp` / `priceUsd` / `priceEur` (normalised by Collecting Cars, for comparing across currencies), `priceBand` |
| **Reserve** | `noReserve`, `reserveMet`, `reserveLowered`, `soldPriceHidden` |
| **Timing** | `stageEndsAt` (when a live auction closes), `auctionEndedAt`, `soldAt`, `publishedAt` |
| **Vehicle** | `make`, `model`, `variant`, `generation`, `year`, `mileage`, `fuelType`, `transmission`, `driveSide` |
| **Location & seller** | `country`, `region`, `location`, `latitude`, `longitude`, `sellerType`, `sellerId`, `sellerBadges` |
| **Detail option** | `vin`, `engineNumber`, `engineSize`, `bodyStyle`, `exteriorColour`, `interiorColour`, `originalMarket`, `registration`, `description`, `images`, `imageCount`, `videoUrl`, `viewCount`, `watcherCount`, `sellerName`, `reservePrice`, `guidePriceLow`, `guidePriceHigh` |

#### ❓ FAQ

**Does it return the sale price on finished lots?**
Yes. 99.9% of the ~33,000 lots in the archive carry one. `soldPriceHidden` flags the roughly 20 where Collecting Cars withheld it.

**Why is `soldPrice` sometimes higher than `currentBid`?**
Check `saleType`. On `auction` lots the car sold at the final bid, and the two match. On `buy_now` lots bidding closed under the reserve and the car sold afterwards at an agreed price, which is usually above the last bid. In our checks about 87% of sold cars were `auction` and about 12% `buy_now`.

**Are the buyer's fees included?**
No. `soldPrice` is the price the lot sold for, before the buyer's fee that Collecting Cars adds on top.

**Does the archive include cars that failed to sell?**
No. Every lot in it sold: the data has no "unsold" state, and 99.9% of archive lots carry a price. That makes it a record of results, not a source for sell-through rates.

**How do I get the whole archive?**
Set `listingStage` to `sold`, tick every lot type, and set `maxItems` to `35000`. A test run returned all 33,289 sold lots in 62 seconds, from 134 search requests. With `includeDetails` on, add one lot-page request per lot.

**Why is `originalMarket` empty on so many cars?**
It is only set on imports. A car sold new in the country it is being sold from has no separate original market to record.

**Does it log in or use a browser?**
Neither. The core fields come from the site's public search data, and the detail option reads the public lot page.

**How much will a run cost?**
$3 per 1,000 lots, whether or not the detail option is on. The whole sold archive comes to about $100.

#### 💬 Support

- Issues tab on the Actor page
- Email: <muhamed.didovic@gmail.com>

#### 🛠 Additional services

- Custom output shape, extra fields, or a one-off dataset: <muhamed.didovic@gmail.com>
- Need the same for another collector-car auction house (Bring a Trailer, Cars & Bids, Historics, Catawiki)? Drop an email.
- For API access (no Apify fee, just a usage fee for the API): <muhamed.didovic@gmail.com>

#### 🔎 Explore more scrapers

See other scrapers at [memo23's Apify profile](https://apify.com/memo23), including the [PistonHeads](https://apify.com/memo23/pistonheads-scraper) classifieds-and-auctions scraper and the [Car & Classic](https://apify.com/memo23/carandclassic-scraper) scraper, plus job boards, real estate and more.

***

### 🤖 For AI Agents & LLM Apps

- **Deterministic input.** Every filter is plain JSON; makes are matched against the site's own list and a name that matches nothing stops the run instead of returning zero rows.
- **Stable schema.** Every field is present on every row (`null` when absent), so downstream parsing needs no defensive key checks.
- **Bounded cost.** `maxItems` caps the number of rows exactly, and a pasted URL the Actor cannot read is refused rather than widened into a full-catalogue run.
- **Unambiguous prices.** `saleType` says whether `soldPrice` is the final bid or a post-auction sale, and `currency` plus the normalised `priceGbp`/`priceUsd`/`priceEur` make lots comparable across markets.
- **Grounding-friendly.** `lotUrl` gives every row a citable public source; `soldAt`, `publishedAt` and `scrapedAt` support freshness reasoning.

***

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Collecting Cars Limited, Watch Collecting, or any of their subsidiaries or affiliates. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available listing data on collectingcars.com and watchcollecting.com: no authenticated endpoints, member-only features, or content behind a login. It does not place bids. Users are responsible for ensuring their use complies with Collecting Cars' Terms of Service, applicable data-protection law (GDPR, CCPA, etc.), and any contractual obligations of their own organisation.

***

### SEO Keywords

collecting cars scraper, collectingcars scraper, scrape collectingcars.com, collecting cars api, Apify collecting cars, collecting cars sold prices, car auction results scraper, classic car auction data, collector car auction prices, car auction sold prices dataset, classic car valuation data, supercar auction results, live car auction bids, car auction archive, classic car market data, porsche 911 auction results, watch collecting scraper, watch auction results scraper, number plate auction data, bring a trailer alternative, car and classic alternative, pistonheads auctions alternative

# Actor input Schema

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

Optional. Build a search on collectingcars.com, copy the URL and paste it here — its filters are translated into the same search the site runs. A single lot URL (/for-sale/...) scrapes just that lot. Leave empty to use the filters below.

## `listingStage` (type: `string`):

Which auctions to return. "Live" matches what collectingcars.com/buy shows. Choose "Sold" to scrape the finished archive, which is where the hammer prices are — roughly 33,000 lots, so set Max results accordingly.

## `lotTypes` (type: `array`):

The index behind Collecting Cars also carries Watch Collecting lots, number plates and parts. Defaults to cars only.

## `saleFormats` (type: `array`):

Leave empty for all three.

## `makes` (type: `array`):

e.g. Porsche, Ferrari. Matched against Collecting Cars' own list of makes, so spelling and case are forgiving. A name that matches nothing stops the run rather than quietly returning zero rows.

## `models` (type: `array`):

e.g. 911, Testarossa. Must match the model name the site uses.

## `keywords` (type: `string`):

Free-text search across lot titles, makes and models.

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

ISO-2 country codes of where the lot is located, e.g. GB, DE, AU, SE, US. Leave empty for every country.

## `regions` (type: `array`):

Broader groupings as the site uses them, e.g. UK, EU, AU, US.

## `driveSide` (type: `string`):

Which side the steering wheel is on.

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

Who is selling the lot.

## `noReserveOnly` (type: `boolean`):

Only lots offered without a reserve.

## `priceMin` (type: `integer`):

Bounds the sold price, or the leading bid on a lot that has not finished.

## `priceMax` (type: `integer`):

Upper bound on the sold price, or the leading bid on a lot that has not finished.

## `yearMin` (type: `integer`):

Earliest model year to include.

## `yearMax` (type: `integer`):

Latest model year to include.

## `listedWithinHours` (type: `integer`):

Only lots published recently — set 24 and schedule the Actor daily for a cheap new-listings monitor.

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

Matters when Max results is smaller than the number of matching lots — it decides which ones you get.

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

Adds VIN, engine size, exterior and interior colour, body style, registration, original market, the seller's full write-up, every photo, view and watcher counts, and the reserve/guide price where shown. Costs one extra request per lot through the proxy, so a run takes roughly three times as long.

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

Maximum lots to return. The sold archive holds roughly 33,000, so set this deliberately.

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

Parallel detail-page requests. Ignored unless the detail option above is on.

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

Only used for the detail pages, which sit behind Cloudflare and need a residential IP. The search itself runs without a proxy. Leave empty to use the built-in residential proxy.

## Actor input object example

```json
{
  "startUrls": [],
  "listingStage": "live",
  "lotTypes": [
    "car"
  ],
  "saleFormats": [],
  "makes": [],
  "models": [],
  "keywords": "",
  "countries": [],
  "regions": [],
  "driveSide": "",
  "sellerType": "",
  "noReserveOnly": false,
  "sortBy": "relevance",
  "includeDetails": false,
  "maxItems": 100,
  "maxConcurrency": 10
}
```

# Actor output Schema

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

Every scraped lot.

# 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": [],
    "listingStage": "live",
    "lotTypes": [
        "car"
    ],
    "makes": [],
    "models": [],
    "countries": [],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/collectingcars-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": [],
    "listingStage": "live",
    "lotTypes": ["car"],
    "makes": [],
    "models": [],
    "countries": [],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/collectingcars-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 '{
  "startUrls": [],
  "listingStage": "live",
  "lotTypes": [
    "car"
  ],
  "makes": [],
  "models": [],
  "countries": [],
  "maxItems": 100
}' |
apify call memo23/collectingcars-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/collectingcars-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/FmDaTDJA2XcXSK87n/builds/3AaH1YOOWhJCq3F73/openapi.json
