# Bring a Trailer Car Scraper (`axiomworks/bringatrailer-auctions-scraper`) Actor

Collect Bring a Trailer auction records, including live and completed listings, with title, status, year, make, model, bids, prices, mileage, seller and location. Search by keyword, use model pages to find listings, or provide individual listing URLs. No login or API key is required.

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

## Pricing

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

## Bring a Trailer Auctions Scraper

**Returns:** one row per auction with title, status, year, currentBid, soldPrice, mileage, engine and transmission.
**Input:** `{"searchTerms": ["porsche 911"], "auctionStatus": "completed", "result": "sold", "maxItems": 10}`
**Best for:** collector-car price history, tracking live auctions that are about to end, and building dealer or buyer research lists from public Bring a Trailer listings.

```json
{
  "id": "123054328",
  "sourceUrl": "https://bringatrailer.com/listing/1996-porsche-911-turbo-222/",
  "title": "1996 Porsche 911 Turbo 6-Speed",
  "status": "sold",
  "soldPrice": 239000,
  "currency": "USD",
  "engine": "Turbocharged 3.6L Flat-Six",
  "transmission": "Six-Speed Manual Transaxle"
}
```

### What does Bring a Trailer Auctions Scraper do?

This Bring a Trailer scraper turns the public auction pages of bringatrailer.com into a clean dataset. Think of it as a Bring a Trailer API for people who need rows instead of web pages. It collects live auctions that are still running and completed auctions with their final result, for any make, model or keyword.

You can start from a keyword such as "porsche 911", from a make or model page such as `/porsche/911/`, from the live auctions page, from a results search URL, or from individual listing URLs. For every auction the Actor returns the headline facts (title, year, status, bids, sold price) and, when listing details are switched on, the facts that only live on the listing page: make, model, bid count, mileage, VIN, seller, location, lot number, views, watchers and comments.

It works without a login, an API key or a browser. The data comes from public pages and the public listings endpoint that the site itself uses, so runs need no browser. The Actor is not affiliated with or endorsed by Bring a Trailer.

Typical jobs:

- Pull the sold history of one model to see how prices moved over time.
- Watch live auctions for a model and see the current bid, bid count and end time.
- Compare reserve-not-met results with sold results for the same car.
- Export seller usernames and locations to see who lists which cars.

### What data can you get?

Each row has the fields below. Fields that need the listing page are empty when you turn off `includeDetails`. Live-only fields such as latitude and longitude are empty for completed auctions.

| Field | Type | Description |
|---|---|---|
| id | string | Stable record id, the Bring a Trailer post id as text |
| sourceUrl | string | Listing page the record came from |
| listingId | integer | Bring a Trailer post id |
| title | string | Listing title with HTML entities decoded |
| status | string | live, sold, reserve_not_met, withdrawn or ended |
| year | integer | Model year taken from the listing data or title |
| make | string | Vehicle make from the listing page |
| model | string | Bring a Trailer model label, for example Porsche 991 911 Targa 4 GTS |
| era | string | Decade label such as 2010s |
| origin | string | Country-of-origin group such as German |
| categories | array | Category labels, often empty |
| currentBid | number | Live: current high bid. Ended: final high bid |
| soldPrice | number | Final sale price from the result text when status is sold (usually equals currentBid; differs when a post-auction deal changed the price), otherwise empty |
| currency | string | Currency code (USD, EUR or GBP), amounts are never converted |
| bidCount | integer | Number of bids |
| highBidder | string | Public username of the high bidder or buyer |
| commentCount | integer | Number of comments on the listing |
| viewCount | integer | Listing views |
| watcherCount | integer | Number of watchers |
| mileage | integer | Odometer number parsed from the listing details |
| mileageText | string | The raw mileage line, for example 32k Miles or TMU |
| vin | string | Chassis or VIN line from the listing details |
| location | string | Seller location |
| countryCode | string | Two-letter country code |
| seller | string | Public seller username |
| sellerUrl | string | Seller profile link (the profile page is never fetched) |
| sellerType | string | Private Party or Dealer |
| lotNumber | integer | Lot number |
| noReserve | boolean | True for no-reserve auctions |
| endDate | string | ISO 8601 end time, scheduled for live and actual for ended |
| resultText | string | Result line for ended auctions, such as a sold-for line with the amount and date |
| engine | string | First matching engine specification line from Listing Details, or null. |
| transmission | string | First matching transmission specification line from Listing Details, or null. |
| listingDetails | array | The bullet list from the Listing Details block |
| thumbnailUrl | string | Thumbnail image link |
| excerpt | string | Short listing summary |
| imageUrls | array | Full-size gallery photo URLs (needs includeDetails) |
| imageCount | integer | Number of gallery photos found |
| description | string | Seller summary paragraph from the listing page (needs includeDetails) |
| latitude | number | Live auctions only |
| longitude | number | Live auctions only |
| scrapedAt | string | ISO timestamp of the scrape |

The mileage number keeps the unit of the listing. A line such as "12k Kilometers Shown" gives 12000 and the text stays in mileageText, so you can tell kilometers from miles.

Engine and transmission are separate nullable columns copied verbatim from the first matching Listing Details line. They preserve the seller's wording, including modifications; they are not decoded from the VIN or inferred from the title. Location and seller type also support the older listing essentials layout. Engine matching accepts ordinary and typographic hyphens while preserving the original listing text. Unrecognized or absent specifications stay null. The original `listingDetails` array remains available, and `includeDetails=false` leaves both columns null. No additional requests or enrichment service are used.

### How to use Bring a Trailer Auctions Scraper

1. Open the Actor in Apify Console and go to the Input tab.
2. Enter one or more search terms, or paste start URLs. If you enter neither, the Actor searches for "porsche 911" so a first run always returns data.
3. Choose which auctions you want: completed, live, or both.
4. Optionally filter by result, time frame and model year range, and pick a sort order.
5. Set Max items. The default is 50.
6. Click Start. Results appear in the Output tab and can be downloaded as JSON, CSV or Excel.

A few practical tips:

1. Start small. Ten items finish in well under a minute and show you the exact shape of the data.
2. For bulk price history, turn off `includeDetails`. The run then needs only one request per 60 auctions instead of one per auction.
3. Use make or model pages (such as `/mercedes-benz/190sl/`) when you want every auction for one model without guessing the right keyword.
4. For monitoring, schedule the Actor with `auctionStatus` set to live and compare runs by `listingId`.

Speed matters here: the Actor keeps to about one request per second to be polite to the site. Fetching the listing page for each auction therefore takes about one second per item, so 1,000 items with details take roughly 17 minutes. List-only runs are much faster.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| searchTerms | array of strings | empty | Keywords such as "porsche 911". Completed auctions use the site search, live auctions need every word to appear in the title or description. |
| startUrls | array | empty | Listing, make, model, category, live list or results search URLs. Plain strings and `{"url": ...}` objects both work. |
| auctionStatus | string | completed | completed, live or all (live first, then completed) |
| result | string | any | Completed only: sold, unsold (reserve not met) or any |
| timeFrame | string | all | Completed only: all, 7D, 30D, 1Y, 2Y or 5Y |
| yearFrom | integer | none | Earliest model year |
| yearTo | integer | none | Latest model year |
| sortBy | string | recent | recent, oldest, highestBid or popular |
| vehiclesOnly | boolean | true | Skip parts, wheels and automobilia |
| includeDetails | boolean | true | Fetch each listing page for the detail fields |
| maxItems | integer | 50 | Total auctions to return, 1 to 100000 |
| maxConcurrency | integer | 3 | Parallel listing page fetches, 1 to 10 |
| proxyConfiguration | object | no proxy | Optional Apify Proxy settings |

Supported start URL shapes:

| URL | Result |
|---|---|
| `https://bringatrailer.com/listing/{slug}/` | That single listing, whatever its status |
| `https://bringatrailer.com/porsche/911/` | Auctions for that model or make, honouring auctionStatus |
| `https://bringatrailer.com/auctions/` | All live auctions |
| `https://bringatrailer.com/auctions/results/?search=land%20cruiser&result=sold&timeFrame=1Y` | Completed auctions for that search |

Unsupported URLs are skipped with a warning and listed in the RUN_SUMMARY record.

Example input:

```json
{
  "searchTerms": ["bmw m3", "toyota supra"],
  "auctionStatus": "completed",
  "result": "sold",
  "yearFrom": 1985,
  "yearTo": 2002,
  "sortBy": "highestBid",
  "maxItems": 20
}
```

When you pass several terms or URLs, the same auction is only returned once. Max items is a total across everything you provide.

### Output

Results are stored in the default dataset, one item per auction. The overview view shows title, status, year, make, model, bids, price, mileage, location, seller and end date. Here is a live auction from a real run:

```json
{
  "id": "119269832",
  "sourceUrl": "https://bringatrailer.com/listing/1982-amc-eagle-13/",
  "listingId": 119269832,
  "title": "1982 AMC Eagle Standard Wagon",
  "status": "live",
  "year": 1982,
  "make": "AMC",
  "model": "AMC Eagle",
  "era": "1980s",
  "origin": "American",
  "categories": ["Station Wagons", "Truck & 4x4"],
  "currentBid": 6666,
  "soldPrice": null,
  "currency": "USD",
  "bidCount": 7,
  "highBidder": "r32fan",
  "mileage": 111000,
  "mileageText": "111k Miles Shown",
  "location": "Elmsford, New York 10523",
  "seller": "JD65DartGT",
  "sellerType": "Private Party",
  "lotNumber": 266403,
  "noReserve": true,
  "endDate": "2026-10-03T17:03:00.000Z"
}
```

Two extra records are written to the key-value store. RUN_SUMMARY lists, for every input, how many auctions were found, pushed and skipped as parts, plus any warnings. If you used the verification option, SNAPSHOTS holds the source text for the first records.

### How much does it cost?

The Actor is charged per result: you pay for each auction row it returns, and nothing for requests that return no rows. See the Pricing tab on the Actor page for the current rate. Apify's free plan credit is usually enough for a first test run.

To keep cost down, set Max items to what you need, and turn off includeDetails when list-level fields are enough.

### Use with AI agents (MCP)

You can call this Actor from any MCP-compatible assistant through the Apify MCP server. Use this configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/bringatrailer-auctions-scraper"
    }
  }
}
```

Example prompts:

1. "Get the last 30 sold Porsche 911 auctions on Bring a Trailer from the past year and tell me the median sold price."
2. "List the live Ford Bronco auctions on Bring a Trailer with their current bid and end time."
3. "Find reserve-not-met results for the Mercedes-Benz 190SL and show the high bids."

### Integrations and API

Run the Actor from code with the Apify API clients.

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("axiomworks/bringatrailer-auctions-scraper").call(run_input={
    "searchTerms": ["porsche 911"],
    "auctionStatus": "completed",
    "result": "sold",
    "maxItems": 20,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["soldPrice"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('axiomworks/bringatrailer-auctions-scraper').call({
    searchTerms: ['ford bronco'],
    auctionStatus: 'live',
    maxItems: 15,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((i) => process.stdout.write(`${i.title}: ${i.currentBid}\n`));
```

cURL:

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~bringatrailer-auctions-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchTerms": ["porsche 911"], "maxItems": 10}'
```

The Actor also works with Apify schedules, webhooks, and integrations such as Make, Zapier and Google Sheets, so you can push new sold prices into a spreadsheet every day.

### FAQ

**Does it need a proxy?** Normally no. The Actor works from a datacenter address with a modest request rate. If the site answers with a block page repeatedly, the Actor switches to Apify datacenter proxy by itself. You can also turn on a proxy in the input.

**Why is a run with details slower?** Make, model, bid count, mileage, seller, location and lot number exist only on the listing page, so the Actor fetches one page per auction at about one request per second. Turn off includeDetails for a fast list-level run.

**What does an empty result mean?** No auction matched. The run still succeeds, the status message names the search, and RUN_SUMMARY records the details. Check the spelling of the term or loosen the filters.

**Why are some fields empty?** Not every listing has every detail. Mileage can be TMU (true mileage unknown), VIN may be absent on old cars, and high bidder is empty when there are no bids or the reserve was not met. Live-only fields stay empty for completed auctions.

**Are amounts converted to dollars?** No. Amounts are in the listing's own currency, shown in the currency field. Most listings use USD, a few use EUR or GBP.

**Why did I get fewer items than Max items?** Only that many auctions matched your filters, or listing pages were not found. Direct listing URLs that no longer exist are skipped.

**Does it include parts and wheels?** Not by default. vehiclesOnly drops parts and wheels lots. Motorcycles and boats are Bring a Trailer auctions and are kept.

**Can I get bid-by-bid history or comments?** No. The Actor returns one row per auction with bid, view, watcher and comment counts, not the individual bids or comment text.

**Does it scrape member profiles?** No. Seller and bidder usernames are shown as they appear on the listing, and the profile pages are never requested.

### Is it legal to scrape Bring a Trailer?

The Actor collects only data that any visitor can see without logging in, and it keeps to a low request rate. It does not log in, solve CAPTCHAs or reach private data. The output contains public usernames shown on the listings, and no emails or phone numbers.

Whether your use is lawful depends on your jurisdiction, your purpose and the site's terms of use, which may restrict automated collection. Check the terms yourself, avoid republishing copyrighted photos or descriptions, and handle any personal data according to the privacy rules that apply to you, such as GDPR. This is general information, not legal advice.

### Feedback

Found a missing field, a wrong value or a page shape that does not work? Open an issue from the Actor page in Apify Console, with the input you used and the listing URL involved. Reports with a concrete example are the quickest to fix.

# Actor input Schema

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

Keyword strings, e.g. \['porsche 911', 'bmw m3']. Each term runs separately; live matches require every word. Combine with startUrls under one maxItems limit. If both are empty, searches 'porsche 911'. Unmatched or blocked targets produce no rows and a status message.

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

Bring a Trailer listing, make/model/category, /auctions/ or /auctions/results/ URLs as objects, e.g. \[{"url":"https://bringatrailer.com/porsche/911/"}]. Apify input validation requires objects. Direct listings ignore auctionStatus and vehiclesOnly; results URLs supply their own query filters. Other URL shapes are skipped.

## `auctionStatus` (type: `string`):

Choose 'completed' (default), 'live', or 'all' (live first). Applies to searchTerms and make/model/category URLs. Example: 'live' for current auctions. Direct listing URLs retain their actual status; /auctions/ always selects live auctions.

## `result` (type: `string`):

Choose 'sold', 'unsold' (reserve not met), or 'any' (default, includes withdrawn). Example: 'sold' for completed sales. Applies only to completed auctions; ignored for live auctions and direct listing URLs.

## `timeFrame` (type: `string`):

Completed-auction lookback: 'all' (default), '7D', '30D', '1Y', '2Y' or '5Y'. Example: '1Y' for auctions ending within the last year. Ignored for live auctions and direct listing URLs.

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

Earliest vehicle model year to include, e.g. 1985. Optional. Applies to searches and make/model pages, not direct listing URLs. Omit for no bound.

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

Latest vehicle model year to include, e.g. 2002. Optional. Applies to searches and make/model pages, not direct listing URLs. Omit for no bound.

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

Choose 'recent' (default), 'oldest', 'highestBid' or 'popular'. Example: 'highestBid' for descending bid amounts. Completed recent/oldest sorts by closing time; both recent and oldest order live auctions ending soonest. Live popular preserves site order.

## `vehiclesOnly` (type: `boolean`):

Set true (default) to skip parts, wheels and automobilia from searches and model pages; motorcycles and boats remain. Example: false to include parts lots. Direct listing URLs are always included.

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

Set true (default) to fetch make, model, mileage, VIN, engine, transmission, seller, location, bid counts and gallery URLs. Example: false for faster list-level price history, with detail fields null or empty. Direct listing URLs still require a detail request.

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

Total unique auctions across all searchTerms and startUrls, 1-100000, default 50. Example: 10 for a small sample. Stops when this shared limit is reached; fewer rows may exist or match your filters.

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

Number of listing pages fetched concurrently, 1-10, default 3. Example: 1 for sequential detail fetching. Overall request spacing still applies; this does not change maxItems.

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

Apify Proxy or custom proxy configuration, e.g. {"useApifyProxy":false} (default) for direct requests or {"useApifyProxy":true} to use Apify Proxy. Repeated blocks may trigger automatic datacenter proxy fallback when available. Persistent blocks return no rows for that target.

## Actor input object example

```json
{
  "searchTerms": [
    "porsche 911"
  ],
  "startUrls": [],
  "auctionStatus": "completed",
  "result": "sold",
  "timeFrame": "all",
  "sortBy": "recent",
  "vehiclesOnly": true,
  "includeDetails": true,
  "maxItems": 10,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `auctions` (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 = {
    "searchTerms": [
        "porsche 911"
    ],
    "auctionStatus": "completed",
    "result": "sold",
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/bringatrailer-auctions-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 = {
    "searchTerms": ["porsche 911"],
    "auctionStatus": "completed",
    "result": "sold",
    "maxItems": 10,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/bringatrailer-auctions-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 '{
  "searchTerms": [
    "porsche 911"
  ],
  "auctionStatus": "completed",
  "result": "sold",
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call axiomworks/bringatrailer-auctions-scraper --silent --output-dataset

```

## MCP server setup

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