# RM Sotheby's Scraper (`normdata/rmsothebys-scraper`) Actor

RM Sotheby's results and lots on offer for dealers, appraisers and analysts: 99,000+ collector cars, motorcycles and automobilia since 2002, with sold price, asking price or estimate, chassis numbers, highlights, catalogue essay and photos. Filter by make, model, year, auction, price.

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

## Pricing

from $16.00 / 1,000 lots

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

![Norm Data](https://raw.githubusercontent.com/FabriAV/normdata/refs/heads/main/assets/banner_norm2.png)

## 🏆 RM Sotheby's Scraper

Extract lots from **RM Sotheby's**, the auction house behind most of the record prices for collector cars: Ferraris, Bugattis, Porsches, pre-war classics, race cars, motorcycles, boats and automobilia. Get **auction results** (over 98,000 lots since 2002, with the sold price or the estimate) or **lots on offer** (upcoming auctions and private sales), each with its full catalogue entry, in one clean table.

Each lot comes with:

- **Sold price** for sold lots, the **asking price** of private sales, and the **low and high estimate** in the auction's currency (USD, EUR, GBP, CHF, CAD, DKK), plus the estimate in every other currency RM shows.
- Status: sold, unsold, upcoming, for sale (private sales) or withdrawn.
- **Chassis, engine, body, gearbox and frame numbers**, registration and every other identification number in the catalogue.
- The **highlights list**, the full **catalogue essay**, specs, addendum and saleroom notes.
- **Race history** as a table (date, event, driver, entrant, race number, result) for competition cars.
- The auction: name, code, sale type (live, online, sealed bid, private sale), location, country and dates. Lot number, collection, No reserve, open to offers, bidding open and close times.
- Every photo, the photo credit, the video, the history files link, the lot link and the auction link.

### 🎯 Who uses it?

#### 🚗 Collector car dealers and brokers

Pull every RM result for a model to price a car before you buy, consign or offer it.

#### 📊 Valuation guides, price indexes and analysts

Feed a market index with sold prices, estimates and dates across 24 years and every RM sale worldwide.

#### 🧾 Appraisers, insurers and lenders

Back an agreed value with comparable RM sales, each matched by chassis number, with the catalogue essay and lot link.

#### 🔍 Buyers, historians and registries

Track a chassis through its RM appearances, read its race history, and watch upcoming sales and private sales for the cars you want.

### ✨ What it does

- **Past results or lots on offer.** Results give the sold price or the estimate; lots on offer give estimates, bidding times and private sale asking prices.
- **Search the way you think:**
  - Search terms ("gullwing", "250 gt", "le mans", "scaglietti"), several per run.
  - Type (Cars, Motorbikes, Boats, Other) and RM's **24 collecting categories** (Supercars & Hypercars, Pre-War European Classics, European Racing Cars...).
  - Make, model and model year range.
  - Auction by code or name ("mo25", "Monterey 2025", "arizona" for every Arizona sale).
- **Or paste rmsothebys.com links:** a lot page, a private sale page or a whole auction (every lot in it). The filters are ignored with links.
- **Every useful filter:**
  - Sold, unsold, results, on offer or everything.
  - **Auction date range**: exact dates, or periods like "6 months" or "2 years".
  - Auction country, sale type (live, online, sealed bid, private sale), No reserve only, withdrawn lots.
  - **Price range** with a currency filter (sold price, asking price, or low estimate when there is neither).
  - Words to exclude (posters, models, automobilia...).
  - 7 sort orders: newest or oldest auction, highest or lowest price, newest or oldest model year, make.
- **New lots only.** For scheduled runs: saves only lots the same search has not saved before.

### 🏆 Why this scraper

- **The whole RM Sotheby's archive.** Every sale since 2002 (99,000+ lots), past the site's 10,000 lot search limit, not one auction at a time.
- **The full catalogue in every row.** Chassis and engine numbers, highlights, the essay, race history and every photo are always included, at no extra cost.
- **Real sort orders.** "Highest price" really ranks every matching lot across currencies, so the $51.7 million GTO comes first.
- **Fast.** About 1,000 lots with their full catalogue in under 20 seconds.
- **No proxy needed.** Nothing extra to set up or pay for.

### ⚖️ How it compares

No other Actor in the Apify Store covers RM Sotheby's. Below, the closest collector car auction scrapers, based on their public input options (October 2026).

| Capability | This actor | [parseforge Bring a Trailer](https://apify.com/parseforge/bringatrailer-auctions-scraper) | [growth-installations Mecum](https://apify.com/growth-installations/mecum-auctions-scraper) | [rastriq The Market (Bonhams)](https://apify.com/rastriq/themarket-scraper) | [rastriq Artcurial](https://apify.com/rastriq/artcurial-scraper) |
|---|:--:|:--:|:--:|:--:|:--:|
| RM Sotheby's lots | **yes** | no | no | no | no |
| Whole results archive | **yes, since 2002** | n/a | one auction per run | n/a | n/a |
| Sold prices | **yes** | yes | yes | yes | yes |
| Estimates | **yes, every currency** | no | no | no | no |
| Upcoming lots and private sales | **yes** | yes | yes | no | no |
| Search terms | **several per run** | no | no | no | no |
| Make, model, year filters | **yes** | no | no | make, year | make, year |
| Category, auction, country, sale type filters | **yes** | no | no | no | no |
| Auction date range | **yes** | no | no | no | no |
| Price range | **yes** | no | no | no | no |
| Sort orders | **7** | none | none | none | none |
| Chassis and engine numbers | **yes** | no | partial VIN | no | no |
| Catalogue essay, highlights, race history | **yes** | no | no | no | no |
| Lot and whole auction links | **yes** | page links | yes (slug) | no | no |
| New lots only (monitoring) | **yes** | no | yes | no | no |
| Needs a proxy | **no** | no | no | yes | yes |

### 📦 What data you get

| Field | Description |
| --- | --- |
| `image` | Main photo. |
| `title`, `year`, `tagLine` | Lot title, model year and RM's one-line pitch. |
| `category` | Cars, Motorbikes, Boats or Other (automobilia, memorabilia). |
| `status` | `sold`, `unsold`, `upcoming`, `for sale` (private sales and post-auction offers) or `withdrawn`. |
| `price` | Sold price, in `currency` (sold lots only). |
| `askingPrice` | Asking price of private sales and post-auction offers, in `currency`. |
| `currency`, `estimateLow`, `estimateHigh` | Currency of the sale, and the estimate. |
| `priceText` | The value as RM shows it ("$51,705,000 USD", "€850 - €2,600 EUR", "Price Upon Request"). |
| `lotNumber`, `referenceId`, `lotId` | Lot number in the sale, RM's reference (e.g. "r0001") and RM's lot id. |
| `saleType` | Live auction, Online auction, Sealed bid or Private sale. |
| `auction`, `auctionCode`, `collection` | Sale name, RM's code (e.g. "mo25") and the collection the lot belongs to. |
| `location`, `country`, `countryCode` | Where the lot is sold. |
| `chassisNumber`, `engineNumber`, `bodyNumber`, `gearboxNumber`, `frameNumber` | Catalogue numbers. |
| `identificationNumber`, `registration` | VIN or other id, and registration. |
| `description`, `addendum`, `saleroomNotes`, `specs` | Catalogue essay, addendum, saleroom notes and specs. |
| `photoCredit`, `imageCount` | Photo credit and number of photos. |
| `searchedFor` | Which of your searches or links found it. |
| `withoutReserve`, `canMakeOffer` | Sold whatever the price; open to offers. |
| `url`, `auctionUrl`, `videoUrl`, `historyFilesUrl` | Lot page, auction page, video and history files. |
| `highlights` | The highlights list. |
| `idNumbers` | Every catalogue number as name and value. |
| `estimatesAllCurrencies` | The estimate in every currency RM shows. |
| `raceHistory` | Race results: date, event, driver, entrant, race number, result. |
| `catalogueSymbols` | Tax and import symbols on the lot. |
| `images` | Every photo link. |
| `auctionStartDate`, `auctionEndDate`, `offeredOn` | Sale dates, and the day a lot was offered. |
| `biddingOpensAt`, `biddingClosesAt` | Online and sealed bid times (UTC). |
| `scrapedAt` | When the row was collected (UTC). |

#### Example row (trimmed)

```json
{
  "image": "https://cdn.rmsothebys.com/0/9/2/4/6/9/092469b8e80d531d0ebc2d5fd61bfc2e25391639.webp",
  "title": "1962 Ferrari 330 LM / 250 GTO by Scaglietti",
  "year": 1962,
  "category": "Cars",
  "status": "sold",
  "price": 51705000,
  "currency": "USD",
  "priceText": "$51,705,000 USD",
  "referenceId": "r0001",
  "saleType": "Live auction",
  "auction": "The One – 1962 Ferrari GTO",
  "auctionCode": "gt23",
  "location": "New York, New York",
  "country": "United States",
  "countryCode": "US",
  "chassisNumber": "3765 LM",
  "description": "THE DEFINITION OF A LEGEND\n\nA shimmering seaside sunset. A Perseid meteor streaking across the August night. A flash of...",
  "photoCredit": "Jeremy Cliff ©2023 Courtesy of RM Sotheby's",
  "imageCount": 127,
  "withoutReserve": false,
  "canMakeOffer": false,
  "url": "https://rmsothebys.com/auctions/gt23/lots/r0001-1962-ferrari-330-lm-250-gto-by-scaglietti/",
  "auctionUrl": "https://rmsothebys.com/auctions/gt23/",
  "historyFilesUrl": "http://catalogue.rmsothebys.com/books/psit/",
  "highlights": [
    "The only GTO Tipo 1962 raced by the Scuderia Ferrari",
    "Class win and 2nd overall finish at the 1962 Nürburgring 1000 KM"
  ],
  "idNumbers": [
    {
      "name": "Chassis No.",
      "number": "3765 LM"
    }
  ],
  "images": [
    "https://cdn.rmsothebys.com/b/1/f/3/7/0/b1f3708522d1e22b2b0ab7989dc88c8946ce5588.webp",
    "https://cdn.rmsothebys.com/f/a/2/4/b/e/fa24be557bf9cc5e8c144b27d4cebc2d4c72233b.webp"
  ],
  "auctionStartDate": "2023-11-13",
  "auctionEndDate": "2023-11-13",
  "offeredOn": "2023-11-13",
  "scrapedAt": "2026-10-12T21:33:26.600Z"
}
```

### 💡 Use cases

#### 📈 Every 300 SL Gullwing RM sold

```json
{ "searchTerms": ["gullwing"], "status": "sold", "maxItems": null }
```

#### 🔥 The 500 most expensive lots of the last 2 years

```json
{ "sortBy": "price_high", "dateFrom": "2 years", "status": "sold", "maxItems": 500 }
```

#### 🏁 European racing cars with race history

```json
{ "tags": ["European Racing Cars"], "maxItems": null }
```

#### 🏷️ Porsches between €100,000 and €500,000 at European sales

```json
{ "makes": ["Porsche"], "minPrice": 100000, "maxPrice": 500000, "currencies": ["EUR"], "maxItems": null }
```

#### 🔔 Private sales and upcoming No reserve lots

```json
{ "status": "on_offer", "withoutReserveOnly": true, "maxItems": null }
```

#### 🏍️ Every lot of one auction

```json
{ "urls": ["https://rmsothebys.com/auctions/mo25/"], "status": "all", "maxItems": null }
```

### ⚙️ How the input is organised

| Section | What it's for |
| --- | --- |
| **Maximum lots**, **What to scrape** | Always first: caps the whole run (empty means no limit), and results, sold, unsold, on offer or everything. |
| **What** | Search terms, or links. |
| **Vehicle** | Type, collecting category, make, model, model year. |
| **Auction** | Auction name or code, auction date range, country, sale type, No reserve, withdrawn lots. |
| **Price** | Price range, currency, words to exclude, sort order. |
| **Monitoring** | New lots only, with an optional monitor name. |

Several values in one field widen the search (a lot matching ANY of your search terms, or ANY of your makes, is kept); different fields narrow it. With links, the search terms and filters are ignored.

### 💰 Pricing

Pay-per-event: a one-time **$0.003** when the run starts, plus a price per lot saved to your dataset that drops with your Apify plan. The full catalogue entry is always included.

| Your Apify plan | Per lot | 1,000 lots |
| --- | --- | --- |
| Free | $0.025 | $25.00 |
| Bronze | $0.022 | $22.00 |
| Silver | $0.019 | $19.00 |
| Gold / Platinum / Diamond | $0.016 | $16.00 |

Lots dropped by your filters are not charged. There are no proxy costs. New Apify accounts start with $5 in free credit. On the Free plan a run saves up to 10 lots.

**Speed:** about 1,000 lots in under 20 seconds. "Lowest price" and "Oldest model year" read every matching lot first (RM Sotheby's own order for them is not reliable), so across the whole archive they take 20 to 40 seconds before the first lot is saved: narrow them with a make, type or date range.

### 🚀 Run it

1. Create a free Apify account with $5 in credit.
2. Open the RM Sotheby's Scraper.
3. Type a search term (or keep the prefilled one), pick results or lots on offer and your filters, then click **Start**.
4. Export the results as CSV, Excel, JSON, or XML from the Dataset tab.

You can also:

- Run it programmatically through the Apify API (`run-sync-get-dataset-items`) or the ApifyClient for JavaScript and Python.
- Schedule it with Apify's built-in Scheduler, with **New lots only** on, to catch new consignments and private sales as RM publishes them.

### 🤖 Use with AI agents (MCP)

Give an AI agent live access to RM Sotheby's results through the Model Context Protocol:

```
claude mcp add --transport http apify "https://mcp.apify.com?tools=normdata/rmsothebys-scraper"
```

Then prompt it in plain language, for example "what did Ferrari 275 GTB/4s sell for at RM Sotheby's in the last 5 years?".

### 🔧 Troubleshooting

**A sold lot has no `price`.**
RM shows "Sold" without a price on some lots, mostly private sales. They are kept as sold, with an empty price.

**Prices are in different currencies.**
Each lot keeps the currency of its sale. Use **Currency** to keep one, and `estimatesAllCurrencies` for RM's conversions of the estimate.

**A withdrawn lot or a private sale has no catalogue fields.**
RM removes the page of withdrawn lots and some sold private sales. Those rows have the search data and no catalogue, with no error.

**A row has an `error` field.**
Only when the lot's catalogue entry could not be read: the other fields are filled, the catalogue fields are empty and `error` says why. Rows that worked have no `error`.

**Private sales come last in date orders.**
RM gives sold private sales no sale date, so they come after the auctions. With **On offer**, private sales still for sale come first.

**A make finds nothing.**
Makes must be spelled as RM does ("Mercedes-Benz", "Rolls-Royce"); the log warns when a make matches no lot. Search terms are more forgiving.

**A scheduled "New lots only" run saved nothing.**
Nothing new matched since the last run. Changing terms, links or filters starts a fresh memory; set a **Monitor name** to keep it.

### ❓ FAQ

| Question | Answer |
| --- | --- |
| Do I need an RM Sotheby's account? | No. Only public lot data is read. |
| Does the price include the buyer's premium? | Yes, `price` is the result RM publishes, with premium. |
| How far back do results go? | To 2002, every sale in RM's online results. |
| Are private sales included? | Yes, both for sale and sold. |
| Is there a result limit? | No. Leave the maximum empty to get everything that matches. |
| Does it need a proxy? | No. |
| Can I track new lots? | Yes. Turn on **New lots only** and schedule the run. |

### 🛡️ Limits & responsible use

This Actor reads only public lot data shown on rmsothebys.com. It never signs in and never bids. Use the data in line with RM Sotheby's terms.

### 📧 Contact

Need a scraper for a different site, or found something wrong with this one? norm.data.scrapers@gmail.com

### 🧪 Local development

```powershell
bun install
bun run typecheck
bun test/qa.mjs
bun test/verify.mjs
apify run
```

Local results are stored in `storage/datasets/default`.

# Actor input Schema

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

Stop after this many lots in total. Leave empty for no limit (every matching lot). The Apify Free plan is always capped at 10.

## `status` (type: `string`):

Results are every RM Sotheby's auction since 2002 (98,820 lots) with the sold price, or the estimate for lots that did not sell. On offer is what is for sale now: lots of upcoming auctions (with estimates) and private sales (520 lots).

## `searchTerms` (type: `array`):

Words to search lots for, as on rmsothebys.com, e.g. "250 GTO", "Gullwing", "Scaglietti", "Steve McQueen", "Rolex". Several terms: a lot matching ANY of them is kept.

## `urls` (type: `array`):

Lot pages (rmsothebys.com/auctions/mo25/lots/...) or auction pages (rmsothebys.com/auctions/mo25/, every lot of the auction). Private sales: rmsothebys.com/ps00/. The filters are ignored with links.

## `categories` (type: `array`):

Keep only these kinds of lots.

## `tags` (type: `array`):

RM Sotheby's collecting categories, e.g. Supercars & Hypercars, Pre-War European Classics, Automobilia. A lot in ANY of them is kept.

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

Keep only these makes, e.g. "Ferrari", "Porsche", "Mercedes-Benz", "Aston Martin", "Bugatti". Case doesn't matter. A make RM Sotheby's never had shows a warning in the log.

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

Keep only these models, e.g. "250", "911", "300 SL", "Countach". Combine with Make to avoid other brands' models of the same name.

## `yearFrom` (type: `integer`):

Keep lots from this model year on, e.g. 1950 (the year in the lot title). Lots with no year in the title (most automobilia) are left out by a year filter.

## `yearTo` (type: `integer`):

Keep lots up to this model year, e.g. 1973.

## `auctions` (type: `array`):

Keep only these auctions, by name or code: "Monterey" (every Monterey auction), "Arizona 2025", "Paris", "mo25". Every word must match the auction name and year.

## `dateFrom` (type: `string`):

Keep lots of auctions held on or after this day. A date like "2024-01-01", or a period like "6 months" or "2 years". Private sales have no auction date, so a date filter leaves them out.

## `dateTo` (type: `string`):

Same format as "Auction date from", e.g. "2024-12-31".

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

Keep lots offered in these countries.

## `saleTypes` (type: `array`):

Live auction (in the room), Online auction (timed, online only), Sealed bid (one-lot sealed auctions) or Private sale.

## `withoutReserveOnly` (type: `boolean`):

Keep only lots offered without reserve (sold to the highest bidder whatever the price).

## `includeWithdrawn` (type: `boolean`):

Also save lots withdrawn from the sale (they have no price or lot page).

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

Price (or asking price, or low estimate) at least this.

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

Price (or asking price, or low estimate) at most this.

## `currencies` (type: `array`):

Keep only lots priced in these currencies.

## `titleExcludes` (type: `array`):

Drop lots whose title, tag line or collection contain any of these words, e.g. "replica", "poster", "model", "kart".

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

Order of the results. Matters most when you set a Maximum. Price sorts use RM Sotheby's own ranking across currencies.

## `onlyNew` (type: `boolean`):

For scheduled runs: save only lots this same search has not saved before. The first run saves everything; later runs save just what is new. Kept per search (terms, links and filters).

## `monitorName` (type: `string`):

Optional. Give "New lots only" a fixed name to keep its memory even after you change the filters.

## Actor input object example

```json
{
  "maxItems": 10,
  "searchTerms": [
    "ferrari"
  ]
}
```

# Actor output Schema

## `lots` (type: `string`):

No description

# 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 = {
    "maxItems": 10,
    "searchTerms": [
        "ferrari"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("normdata/rmsothebys-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 = {
    "maxItems": 10,
    "searchTerms": ["ferrari"],
}

# Run the Actor and wait for it to finish
run = client.actor("normdata/rmsothebys-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 '{
  "maxItems": 10,
  "searchTerms": [
    "ferrari"
  ]
}' |
apify call normdata/rmsothebys-scraper --silent --output-dataset

```

## MCP server setup

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