# Bring a Trailer Auction Results Scraper (`madjad33/bringatrailer-auction-scraper`) Actor

Extract Bring a Trailer auction results as structured JSON: realized sale price, sold vs reserve-not-met, year, model and end date. No personal data.

- **URL**: https://apify.com/madjad33/bringatrailer-auction-scraper.md
- **Developed by:** [Jad D.](https://apify.com/madjad33) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 auction 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/platform/actors/running/actors-in-store#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

## Bring a Trailer Auction Results Scraper

Extract **Bring a Trailer** auction results as clean JSON or CSV: **realized sale price**, whether it actually sold, year, model, no-reserve flag and end date. Point it at any model for instant comps.

Press **Start** and it returns 100 recent results immediately — every input field has a working default.

### What you get

One flat row per auction.

```json
{
  "auctionId": "119497800",
  "title": "1999 GMC Yukon SLT",
  "year": 1999,
  "url": "https://bringatrailer.com/listing/1999-gmc-yukon-24/",
  "outcome": "SOLD",
  "sold": true,
  "priceValue": 8200,
  "priceCurrency": "USD",
  "priceFormatted": "USD $8,200",
  "finalBidValue": 8200,
  "priceSource": "sold_text",
  "priceDiffersFromBid": false,
  "endedAt": "2026-08-11T14:48:51.000Z",
  "noReserve": true,
  "countryCode": "US",
  "commentCount": 0,
  "viewCount": 0,
  "watcherCount": 0,
  "scrapedAt": "2026-08-12T09:41:02.187Z"
}
```

### The two fields that matter, and why

**`outcome`.** A completed BaT auction reads either *"Sold for USD $8,200"* or *"Bid to USD $35,000"*. The second means the reserve was not met and **the car did not change hands** — but it still carries a bid number. Anyone averaging bids without splitting on outcome computes a market price that includes cars nobody bought. Use `soldOnly` when you want real transaction prices.

**`priceValue` vs `finalBidValue`.** These are not always the same. On a sample of 36 completed auctions, two disagreed: a final bid of `19,500` against *"Sold for USD $20,000"*, and `18,000` against *"Sold for USD $19,000"*. `priceValue` reports **what it actually sold for**; `finalBidValue` is the last live bid; `priceDiffersFromBid` flags the rows where they diverge. Most scrapers report the bid and quietly understate ~6% of sales.

| Field | Notes |
|---|---|
| `auctionId` | Stable BaT id — your join key across runs |
| `outcome` | `SOLD` · `RESERVE_NOT_MET` · `LIVE` |
| `priceValue` | The realized amount, read from the result line |
| `finalBidValue` | Last bid. Compare against `priceValue` |
| `year` | From the record, falling back to the title — BaT leaves the field null in practice |
| `noReserve` | No-reserve auctions clear at market rather than at a floor |
| `endedAt` | ISO timestamp, so you can build a time series |
| `commentCount`, `viewCount`, `watcherCount` | Engagement, as integers |

### Comps for one model

The useful pattern is a model URL rather than the global feed:

| Want | URL |
|---|---|
| Porsche 911 comps | `bringatrailer.com/porsche/911/` |
| Ford Bronco comps | `bringatrailer.com/ford/bronco/` |
| Everything BMW | `bringatrailer.com/bmw/` |
| Latest results, all models *(default)* | `bringatrailer.com/auctions/results/` |

Add as many as you like in one run.

### Coverage, stated honestly

**This returns the most recent auctions per URL, not the full archive.** BaT holds 257,297 completed auctions across 7,148 pages, and there is no working way to page through them: `/page/2/` returns 404 and `?page=2` silently re-serves page one. Real pagination goes through a private admin-ajax endpoint that rejects every documented parameter combination.

Rather than build on a guessed private endpoint that would break without warning, this actor reads the first feed of each URL you give it — roughly 24 per model page, 36 on the results page, and over 1,200 on the live `/auctions/` page. Multiple model URLs are the way to get breadth.

If BaT ever exposes public pagination, this will support it.

### Compliance

**No personal data.** Every person-field probe against BaT's raw feed came back empty — no seller, no bidder, no username, no email. The output schema is a fixed allowlist and rows are constructed from it rather than filtered, so if BaT ever adds bidder handles next to the price they cannot reach your dataset without a deliberate change here. Tests assert it.

**robots.txt respected in code:** `/wp-admin/`, `/wp-json/` and account paths are refused even if passed as input. **No login, ever.**

### Notes

Data comes from the listing feed BaT embeds in the page, not from CSS selectors, which makes it far more stable than markup scraping — and needs no browser, which is why it is cheap.

Duplicates are removed within a run. Auctions with no resolvable outcome are **skipped without charge**. You pay for results, not attempts.

# Actor input Schema

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

Results pages or model pages. Use a model URL to get comps for one vehicle — e.g. bringatrailer.com/porsche/911/ or /ford/bronco/. Add as many as you like; each returns its most recent auctions. Account, /wp-admin/ and /wp-json/ paths are refused.

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

Hard cap on billable results. You are charged per auction returned, so this is also your spend cap.

## `soldOnly` (type: `boolean`):

Return only vehicles that actually changed hands. Turn this on when computing average sale prices — otherwise reserve-not-met cars, which nobody bought, are mixed into your average.

## `includeUnsold` (type: `boolean`):

Reserve-not-met results carry a real top bid and are useful market signal, so they are included by default. Ignored when 'Sold auctions only' is on.

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

Parallel requests. The default is deliberately polite — no browser is needed, so it is already fast.

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

Optional. Bring a Trailer serves this data to plain HTTP clients, so no proxy is needed in normal use and leaving it off is cheaper.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://bringatrailer.com/auctions/results/"
    },
    {
      "url": "https://bringatrailer.com/porsche/911/"
    }
  ],
  "maxItems": 100,
  "soldOnly": false,
  "includeUnsold": true,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Table of auctions with vehicle, year, outcome, realized price and end date.

## `soldOnly` (type: `string`):

Only auctions that actually completed a sale — use this for average sale prices.

## `allFields` (type: `string`):

Every field, including final bid, price source, no-reserve flag, comment, view and watcher counts.

## `csv` (type: `string`):

The same results as a spreadsheet.

# 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": [
        {
            "url": "https://bringatrailer.com/auctions/results/"
        },
        {
            "url": "https://bringatrailer.com/porsche/911/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("madjad33/bringatrailer-auction-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": [
        { "url": "https://bringatrailer.com/auctions/results/" },
        { "url": "https://bringatrailer.com/porsche/911/" },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("madjad33/bringatrailer-auction-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": [
    {
      "url": "https://bringatrailer.com/auctions/results/"
    },
    {
      "url": "https://bringatrailer.com/porsche/911/"
    }
  ]
}' |
apify call madjad33/bringatrailer-auction-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,madjad33/bringatrailer-auction-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/yXvxFQ2cdIBLLUn9C/builds/qnUas6uv1mQxTpcpY/openapi.json
