Bring a Trailer Scraper - Sold Prices, VIN & Results avatar

Bring a Trailer Scraper - Sold Prices, VIN & Results

Pricing

$1.30 / 1,000 per auction result delivereds

Go to Apify Store
Bring a Trailer Scraper - Sold Prices, VIN & Results

Bring a Trailer Scraper - Sold Prices, VIN & Results

From $1.30 per 1,000 results, no start fee. Every completed Bring a Trailer auction as one row: chassis/VIN, realized sale price, sale date, lot number, city and postal code, bid count, odometer, make and model. 209,076 sold results, and it pages past BaT's 10,000-row search limit.

Pricing

$1.30 / 1,000 per auction result delivereds

Rating

0.0

(0)

Developer

Scrapers Delight

Scrapers Delight

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Share

๐Ÿš— Bring a Trailer Scraper โ€” sold prices, chassis numbers and auction results

A VIN-keyed price database for collector cars. Every completed Bring a Trailer auction comes back as one row: the chassis / VIN number, what it actually sold for, the date, the lot number, the odometer, where the car was, who sold it and how many bids it took.

Read this first: this is a price database, not a lead list. BaT sellers are pseudonymous handles โ€” CobraKid, stim4u โ€” and Bring a Trailer publishes no seller phone number, no email and no company name, anywhere, for anyone. This Actor collects what BaT shows publicly on a completed listing. If you came here for contact details for the people selling cars, this Actor cannot give you them and no BaT scraper can. What it can give you is the comps table behind a valuation.

Scope is deliberately narrow: completed auctions only. Live auctions in progress are not polled and current bids are not tracked.


๐Ÿ“Š What one row contains

Field
IdentitylistingId ยท url ยท lotNumber ยท chassis (VIN / chassis number) ยท title
Vehicleyear ยท make ยท model ยท modelUrl ยท era ยท origin ยท category
The resultstatus ยท soldPrice ยท highBid ยท currency ยท priceText ยท resultDate ยท resultAt ยท endedAt ยท bidCount ยท commentCount
FlagsnoReserve ยท premium ยท batAlumni ยท verifiedCheckout ยท priceSourceDisagreement
Conditionmileage ยท mileageUnit ยท mileageText ยท engine ยท transmission ยท exteriorColor ยท interiorColor ยท essentials
PartiessellerUsername ยท sellerProfileUrl ยท sellerType (private / dealer) ยท buyerUsername
LocationlocationText ยท city ยท region ยท postalCode ยท countryCode ยท countryCodeAlpha3
Interestviews ยท watchers
Media & copythumbnailUrl ยท imageCount ยท imageUrls (opt-in) ยท excerpt ยท description (opt-in)
ProvenancedetailFetched ยท sourceQuery ยท sourceUrl ยท scrapedAt

A real row, from a real run

{
"listingId": 121100523,
"url": "https://bringatrailer.com/listing/1997-porsche-911-turbo-s-24/",
"lotNumber": "263485",
"chassis": "WP0AC2996VS375797",
"title": "1997 Porsche 911 Turbo S",
"year": 1997,
"make": "Porsche",
"model": "Porsche 993 911 Turbo S",
"modelUrl": "https://bringatrailer.com/porsche/993-911-turbo-s/",
"era": "1990s",
"origin": "German",
"status": "sold",
"soldPrice": 852000,
"highBid": 852000,
"currency": "USD",
"priceText": "Sold for USD $852,000 on 9/18/2026",
"resultDate": "2026-09-18",
"endedAt": "2026-09-18T17:24:34.000Z",
"bidCount": 33,
"commentCount": 212,
"noReserve": false,
"premium": true,
"batAlumni": false,
"mileage": 24000,
"mileageUnit": "miles",
"mileageText": "24k Miles Shown",
"engine": "Twin-Turbocharged 3.6L Flat-Six",
"transmission": "Six-Speed Manual Transaxle",
"exteriorColor": "Guards Red Paint",
"interiorColor": "Supple Black Leather Upholstery",
"sellerUsername": "stim4u",
"sellerType": "private",
"buyerUsername": "gosmarte",
"city": "Fairfield",
"region": "Connecticut",
"postalCode": "06824",
"countryCode": "US",
"views": 28033,
"watchers": 2542,
"imageCount": 222
}

๐ŸŽฏ Who this is for

BuyerWhat they do with it
Valuation and insurance data vendorsJoin chassis to their own VIN records and build a realized-price series per model. modelUrl is BaT's own normalised model key, so "993 911 Turbo S" groups correctly without string matching.
Classic-car dealers and consignment shopsPrice inventory against what comparable cars actually made, filtered by year, mileage and colour.
Collector-car lendersSupport a loan-to-value against public transaction evidence rather than an asking price.
Auction housesBenchmark their own estimates against BaT results for the same model and year.
Market analysts and journalistsTrack a model's price curve, no-reserve premium, or bid counts over a decade of results.

๐Ÿงญ What makes this different from the other BaT scrapers

There are 21 Bring a Trailer Actors on the Apify Store (counted from the full store census โ€” apify.com/sitemap/actors1..12.xml, 599,202 URLs, 70,945 of them Actor records). Three of them have real monthly usage. Here is what this one does that they do not, each item measured rather than claimed.

1. It reports the price the car actually sold for

BaT ends some auctions with a post-auction sale: the reserve was not met during bidding, and the car sold afterwards at a different price. On those listings BaT's own list feed still reports the final bid in current_bid, while the sale price is in the result line.

Measured on a 400-row live run: 12 rows (3.0%) were post-auction sales, and 11 of them had a sale price different from the final bid โ€” $8,500 bid against $13,000 sold, $13,500 against $16,750, $111,000 against $115,000, $23,250 against $23,750. A comps table built on current_bid is understated on those rows by up to 53%, always in the same direction.

This Actor carries both: soldPrice (what it sold for), highBid (the final bid), a status of sold / sold-after-auction / reserve-not-met, and a priceSourceDisagreement object on the rows where they differ, so you can see them rather than average them in.

2. It gets past BaT's 10,000-row search limit

BaT's results endpoint is ElasticSearch-backed and inherits the default 10,000-document window. Measured by binary search on 2026-09-18 against state=sold:

Rows per pageLast page that returns anythingRows reachable
362779,972
482089,984
601669,960

Past that, BaT answers HTTP 200 with items_total: 0 and an empty array โ€” while pages_total goes on claiming 5,808 pages. There is no error to catch. A scraper that pages until it sees no rows reports a clean, successful, complete sweep of the archive after reading 3.8% of it. One rival's README advertises "up to a million per run" from this endpoint; the endpoint will not give anyone more than 9,984 rows for one query.

This Actor handles it two ways:

  • Two-ended reading. sort=td and sort=ta walk the same result set from opposite ends (verified: zero id overlap between the first 60 of each on a 10,421-row set), so any query with up to 19,920 hits is read completely.
  • Model-year partitioning. Anything bigger is split one model year at a time, then by category, then by origin, deduplicating on listing id. Measured across all 127 model years from 1900 to 2026: 200,070 of 209,076 sold listings carry an indexed model year (95.7%), and the largest single year is 2006 at 5,437 โ€” comfortably inside one window.

Either way, RUN_SUMMARY records what BaT said was there against what was actually read, per partition. A partial sweep is never reported as a complete one.

3. Fields the others advertise but cannot fill

Two competing Actors list latitude and longitude among their output fields, and one's README shows a worked example with coordinates in it. BaT's feed does not publish them. Measured across 155 feed rows on 2026-09-18: lat and lon were null on 155 of 155, along with country, era, categories, year, in_subscription, keyword_pages, processing_type and searchable. This Actor does not ship a latitude column; it ships city, region, postalCode and countryCode, read off the listing page, filled on 100% of sampled listings.

The same applies to engagement. The feed's comments is the literal string "0" and views is "0 Views" on every row โ€” placeholders the browser fills in over a websocket. Read naively they make every car look like it drew no interest. This Actor takes views, watchers and commentCount from the listing page, or leaves them null if you turn listing pages off. Never a fabricated zero.

4. No run-start fee

All 21 rival Actors charge one, from $0.00005 to $0.10 per run โ€” one of them charges more to start a run than this Actor charges for 76 rows. This one charges nothing to start and nothing for a run that matches nothing.


๐Ÿ“ˆ Measured coverage and field fill

Counted on 2026-09-18 against real bytes fetched through the Apify proxy โ€” not estimates, and not copied from a competitor.

The corpus. BaT publishes 263,924 completed listings: 209,076 sold and 54,848 ended below reserve. (209,076 + 54,848 = 263,924 exactly โ€” the sold/unsold facet is a real server-side split, not a filter applied after download.)

Field fill on a real 400-row run โ€” the 400 most recently closed sold listings, every category included, nothing filtered out to flatter the numbers. These are the figures RUN_SUMMARY printed for that run:

FieldFillNote
listingId, url, lotNumber, title, status, highBid, currency, priceText, resultDate, resultAt, endedAt, bidCount, commentCount, essentials, sellerUsername, sellerType, buyerUsername, locationText, city, region, countryCode, views, watchers, thumbnailUrl, imageCount, excerpt100%400/400
soldPrice99.5%
make99.5%
origin99.3%
model, modelUrl97.5%
postalCode97.3%
era92.0%
chassis (VIN)91.3%365/400 across all categories. See below.
transmission90.8%
year89.8%Parsed from the title and cross-checked against BaT's own era tag โ€” 151 of 151 listings that carried both agreed.
mileage88.3%
interiorColor85.3%Derived from BaT's own "Listing Details" bullets.
engine82.3%Same.
exteriorColor75.8%Same.
category67.8%BaT only tags a listing with a category when it fits one of its 25. A 1995 Ferrari with no tag will not match a Convertibles filter even if it is one.
priceSourceDisagreement2.8%Fires only on post-auction sales โ€” see below.

The chassis caveat that matters. The 91.3% above is across everything BaT sells, including lots that have no VIN because they are not vehicles. Of the 35 rows with no chassis number, 32 were BaT's own Parts or Wheels categories (gas pumps, wall art, a set of Fuchs wheels, a racing simulator) and the other three were an engine project, a bicycle project and one truck. On vehicles the fill is 365 of 368 โ€” 99.2%, and on a separate 154-listing sample weighted towards cars and motorcycles it was 153 of 154, 99.4%. Filter out Parts and Wheels and expect a VIN on essentially every row; leave them in and expect correct nulls.

What the same run showed about the rest of the corpus: 388 of 400 sold during the auction and 12 (3.0%) were post-auction sales, of which 11 had a sale price different from the final bid. 398 rows were priced in USD and 2 in EUR. 389 cars were in the US, 7 in Canada and one each in Japan, Italy, Switzerland and Belgium. The median gallery held 151 photos.

Speed. 400 rows with full listing-page enrichment: 141 seconds at 1 GB, 400 ร— HTTP 200, 0 unreachable listings, 0 truncated bodies, 7 API requests. An earlier 155-page burst at 10 in parallel ran in 31 seconds. The list feed costs ~300 bytes of wire per row; a listing page is ~74 KB on the wire (about 500 KB uncompressed).


โš™๏ธ How to use it

The quickest useful run

{
"searchTerms": ["porsche 911"],
"minYear": 1995,
"maxYear": 1999,
"maxResults": 100
}

Everything a model sold for, ever

Paste the BaT model page and let the Actor read BaT's own curated listing set off it:

{
"startUrls": [{ "url": "https://bringatrailer.com/porsche/911/" }],
"maxResults": 0
}

A results page you already filtered by hand

Set the filters on bringatrailer.com/auctions/results/, copy the URL, paste it. Every parameter โ€” search, result, yearFrom, yearTo, category, era, origin, location, type, timeFrame, bidTo, exclude, sortby โ€” is translated:

{
"startUrls": [{
"url": "https://bringatrailer.com/auctions/results/?search=e30+m3&result=sold&yearFrom=1988&yearTo=1991"
}],
"maxResults": 500
}

A comps table, one row per car

{
"categories": ["Motorcycles"],
"origins": ["Japanese"],
"minYear": 1970,
"maxYear": 1985,
"dedupeByChassis": true,
"maxResults": 0
}

Prices only, eight times faster

{
"soldWithin": "30D",
"fetchDetails": false,
"maxResults": 0
}

Turning listing pages off drops chassis, lotNumber, location, seller, buyer, bidCount, odometer, engine, transmission, colours, essentials, views, watchers, commentCount and the photo count. Price, date, title, flags, country and the listing URL still come through. The per-row price is the same either way โ€” turn it off for speed, not for cost.

Every input

InputWhat it does
resultsold (default, 209,076 rows), reserve-not-met (54,848), or all. BaT's own server-side facet.
searchTermsWords that must appear, e.g. ["porsche 911"].
excludeTermsA word that must not appear, e.g. project.
startUrlsA model/make page, a results page with filters, or a single listing.
minYear / maxYearModel-year range.
erasBaT's 14 decade tags.
categoriesBaT's 25 category tags.
originsBaT's 14 origin tags.
locations38 countries plus BaT's three region groups.
listingTypesNo Reserve, Premium, BaT Alumni.
maxPriceUsdKeep only results at or below this.
soldWithin7D, 30D, 1Y, 2Y, 5Y, or all time.
sortRecently closed / oldest / most viewed / highest bid.
maxResultsHard cap on rows delivered and charged. 0 = no cap.
fetchDetailsOpen each listing page. Default on.
includePhotosAdd every gallery URL (median 151 per listing, measured).
includeDescriptionAdd the full write-up (~2,000โ€“4,400 characters; the always-included excerpt is BaT's ~350-character teaser).
dedupeByChassisOne row per VIN โ€” collapses repeat sales of the same car.
autoPartitionWork around the 10,000-row search limit. Default on.
detailConcurrencyListing pages in parallel. Default 8.
proxyConfigurationApify Proxy, datacenter by default.

Every filter except dedupeByChassis is applied by Bring a Trailer, before a row is sent, so filtered-out listings are never downloaded and never charged.


๐Ÿ’ต Pricing

$0.0013 per result delivered โ€” $1.30 per 1,000. No run-start fee.

ResultsCost
50 (the default run)$0.07
100$0.13
1,000$1.30
10,000$13.00
0 rows matched$0.00

You are charged once per row delivered to your dataset, and the maxResults cap is counted against rows produced rather than batches flushed โ€” a cap of 60 charges exactly 60. Opening each listing page for the chassis number and the rest is included in the rate; so is the partitioning that gets past BaT's search limit.

How that compares over the same 200-row job. Rates were read from each Actor's live pricingInfos on 2026-09-18, taking the FREE-tier rate where the Actor uses tiered pricing, and the run-success figures are each Actor's own public 30-day stats:

ActorPer resultStart fee200 resultsPublishes VIN?
This Actor$0.0013none$0.26Yes โ€” 99.2% fill on vehicles
jongoose/bring-a-trailer-scraper$0.001$0.00005$0.20No โ€” no VIN or chassis field
mrdoe/bringatrailer-car-data-scraper-us$0.0015$0.00005$0.30Yes
devilscrapes/bring-a-trailer-auctions-scraper$0.0015$0.005$0.30Yes
tortuga/bringatrailer-scraper$0.003 + $0.004 detailnone$1.40Yes
lulzasaur/bringatrailer-scraper$0.005$0.00005$1.00No
silentflow/bringatrailer-scraper$0.006$0.00005$1.20Yes
parseforge/bringatrailer-auctions-scraper$0.015$0.05$3.05No

One Actor on the Store is cheaper per row, and it is listed above rather than left out: jongoose at $0.001 will save you six cents on a 200-row job. It publishes no VIN or chassis number โ€” the field this product is built around โ€” so if you only need sold prices and dates it is the cheaper choice, and you should take it. Of the Actors that do publish a VIN, this is the cheapest, and it is the only one of any of them with no run-start fee at all.


โ“ FAQ

Does this give me the seller's phone number or email? No, and nothing can. Bring a Trailer identifies sellers by a pseudonymous handle and publishes no phone, email or company name. You get sellerUsername, a link to their public BaT profile, and whether BaT lists them as a private party or a dealer. If you need contact data, this is the wrong Actor โ€” it is a price database.

Is the chassis number really a VIN? It is whatever the seller entered in BaT's "Chassis" field, which for a modern car is the 17-digit VIN and for a pre-1981 car is the manufacturer's chassis number. It is delivered verbatim, not validated or checksummed. Fill measured at 99.4% on vehicles and 66.7% on a sample weighted towards parts and wheels lots, which have no chassis at all.

Can I get all 209,076 sold results in one run? Set maxResults: 0 and leave autoPartition on. The Actor will walk it one model year at a time. Two things to know first: at $0.0013 a row that is $272, and the model-year axis reaches 95.7% of the corpus โ€” the remaining ~9,000 listings (parts, wheels, and a few lots BaT indexes with no year) are not addressable through it. RUN_SUMMARY tells you exactly what was read against what BaT said was there.

Why is category empty on so many rows? Because BaT leaves it empty. A category tag is applied only when a listing fits one of BaT's 25 categories, and about a third of listings carry none. Filtering by category is therefore narrower than it looks.

What is sold-after-auction? The auction ended below reserve and the car sold afterwards, usually at a higher number than the final bid. BaT labels the result row "Sold" instead of "Winning Bid". Those rows carry both numbers and a priceSourceDisagreement object.

Does it track live auctions or current bids? No. Completed results only, by design.

How current is the data? As current as the site. A listing appears in the feed the moment its auction ends; results captured during testing included auctions that had closed within the hour.

What currency are the prices in? BaT quotes in USD. currency is read from the listing rather than assumed, and it was USD on 155 of 155 sampled rows, including a Canadian listing.

Does it need a login? No. Everything it reads is public and no account is used. BaT's own results page demands a login nonce only for the logged-in-user filters (watched / following / admin), which this Actor does not touch.

Can I run it on a schedule to catch new results? Yes. soldWithin: "7D" with fetchDetails: true gives you the week's results โ€” measured at 1,005 sold in the last 7 days. Deduplicate on listingId in your own store.

What happens if a listing page can't be fetched? It is retried on a fresh proxy session. If it still fails, the row is delivered from the feed alone with detailFetched: false, and the URL is listed in RUN_SUMMARY.listingsUnreachableAfterRetries. A row that could not be identified at all is neither delivered nor charged.

Why does a run sometimes make more requests than rows? Each partition costs one probe request to learn how many rows BaT says it holds. On a big partitioned sweep that is roughly 130 extra requests for the whole model-year axis. They are not charged.


๐Ÿ” Honest limits

  • No seller contact data exists on BaT. Stated three times in this README because it is the single most common wrong expectation about this site.
  • The model-year sweep reaches 95.7% of the sold archive, measured. Listings BaT indexes with no model year โ€” parts, wheels, some memorabilia โ€” cannot be reached through that axis.
  • engine, transmission, exteriorColor and interiorColor are inferred from BaT's free-text "Listing Details" bullets, not from structured fields. The full bullet list is always delivered in essentials so you can re-derive them yourself. Measured fill 79โ€“99%.
  • year is parsed from the listing title, because BaT does not publish it in the feed even though it indexes it. It is cross-checked against BaT's era tag: 151 of 151 agreed.
  • mileage is what the seller claimed, expanded from BaT's own wording (24k Miles Shown โ†’ 24,000). mileageText keeps the original, including qualifiers like TMU.
  • Bidder and seller handles are pseudonyms, published by BaT on the public listing page. No real names, no contact details, no attempt to resolve identities.
  • BaT occasionally answers 403 to an Apify datacenter IP โ€” 2 of 60 on a first pass; retrying on a fresh session cleared both, and a 155-page run afterwards saw 0 failures. If you see the rate climb, switch proxyConfiguration to RESIDENTIAL.
  • Currency is not converted. soldPrice is in currency as BaT published it. BaT is US-centric but not US-only: on the 400-row live run 398 rows were in USD and 2 in EUR, and 11 of 400 cars were outside the United States.
  • A sale with no readable price is not delivered and not charged. On a price database the price is the record, so a row BaT reports as sold that carries no number is treated as a parse failure rather than shipped with a null โ€” it is listed by URL in RUN_SUMMARY.soldRowsWithNoPriceNotDelivered so the gap is visible instead of averaging into your comps. On the verification runs this list was empty.
  • Rating and last-updated for competing Actors are not in the Apify API; the comparison table above uses pricing, usage and run-success figures that are.

Data comes from two public surfaces on bringatrailer.com:

  1. wp-json/bringatrailer/1.0/data/listings-filter โ€” the same endpoint the site's own Auctions โ†’ Results page calls to render itself.
  2. The public listing pages at /listing/<slug>/.

No login, no account, no private data, no bidding, no messaging.

bringatrailer.com/robots.txt, quoted verbatim as served on 2026-09-18:

User-agent: *
Crawl-delay: 1
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php
Disallow: /message/
Disallow: /listing/*/carfax
Disallow: /member/
Disallow: /*/contact/
Disallow: /*/feed/
Disallow: /account/
Disallow: /?q=
Disallow: /search/
Disallow: /*corder=
Disallow: /*utm_source=

Neither /wp-json/... nor /listing/<slug>/ is disallowed. This Actor does not request any of the disallowed paths โ€” in particular it never opens /member/ profile pages or /listing/*/carfax, even though a seller handle links to one.

You are responsible for how you use the output. Bring a Trailer's own Terms of Use govern your use of their site, and nothing here is legal advice.