# CarGurus Scraper — US Car Listings, VINs and Market Value (`s-r/cargurus-scraper`) Actor

Collect US CarGurus car listings by ZIP, radius, make and model. Get VINs, prices, mileage, deal ratings, market value estimates and dealer details for dealers, valuation tools and insurers.

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

## Pricing

$5.00 / 1,000 listings

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

## CarGurus Scraper

CarGurus Scraper collects US car listings by ZIP code, radius, make and model, with the VIN, asking price, mileage, CarGurus deal rating, market value estimate and dealer details for every car. Dealers, valuation tools and insurers get a ready-made CarGurus dataset without building their own CarGurus API integration.

### What CarGurus Scraper collects

Each row represents one vehicle offered for sale. The result includes the listing identifier, a direct listing link, the vehicle title, model year, manufacturer, model, trim and VIN. Prices are numeric USD amounts. Mileage and search distance use miles. The main listing image and the dealer's name, city, state and ZIP code help you match vehicles to local inventory.

CarGurus valuation fields are included when the source provides them. `expected_price` is the source's market value estimate, `deal_rating` is its categorical deal assessment, and `price_differential` is market value minus asking price. A negative difference means the asking price exceeds the estimated market value. `days_on_market` shows how long the car has been listed. These fields let you compare inventory without downloading individual vehicle detail pages.

### How to use CarGurus Scraper

1. Enter a five-digit US ZIP code and a search radius in miles.
2. Optionally narrow the search with a make and model, a price range, model years and a maximum mileage.
3. Set `limit` to the number of listings you want, up to 1000 per run.
4. Start the run and download the dataset as JSON, CSV or Excel, or read it through the Apify API.

Running the same search on a schedule gives you a time series of asking prices, market values and days on market for the vehicles you track.

### Input

Start with a five-digit US ZIP code. The default ZIP is `10001`, the search radius is 50 miles and the requested limit is 48 listings. A local radius may be between 10 and 500 miles. Set `radius` to 0 for a nationwide search. US inventory is supported; this actor does not collect Canadian or UK listings.

Use `make` and `model` to narrow the search. Both accept exact names regardless of letter case, or CarGurus entity identifiers. Honda is `m6`, and INFINITI QX60 is `d2243`. A model name requires a make to distinguish it from similarly named vehicles. A model identifier can be used without a make. Unknown names and identifiers produce a clear no-results response rather than broadening the search to other brands.

```json
{"zip":"10001","make":"m6","price_min":10000,"price_max":20000,"year_min":2018,"year_max":2022,"mileage_max":60000,"limit":48}
```

This search was tested against real Honda inventory. Price filters are in USD, year filters refer to model years, and `mileage_max` is an odometer limit in miles. Minimum values must not exceed their corresponding maximum values. Choose `condition: "used"` for used inventory or `"new"` for new inventory; the output records the requested inventory type.

Sorting options are `best_match`, `price_asc`, `price_desc`, `mileage_asc`, `newest_listing` and `deal_score`. The default is `best_match`. The `offset` input starts at a source row offset and is independent of the one-based output position.

By default, nationwide shipping and store-transfer offers are excluded from local searches. Set `include_shipping` to true if you also want these offers. Their `inclusion_type` and `distance_miles` fields remain visible, so a vehicle available for delivery can be distinguished from stock located near the search ZIP.

### Output

Listings land in the default Apify dataset and can be exported as JSON, CSV or Excel. The OUTPUT record contains collection status, counts and warnings. Row identifiers are strings, preserving a consistent identifier type. Dealer ZIP codes remain strings so leading zeros survive export.

The principal fields are `listing_id`, `url`, `title`, `price`, `currency`, `vin`, `year`, `make`, `brand`, `model`, `trim`, `mileage`, `mileage_unit`, `deal_rating`, `expected_price`, `price_differential`, `days_on_market`, `dealer_name`, `dealer_city`, `dealer_zip` and `image_url`. Additional fields include total price with dealer fees when available, dealer state and phone, stock number, MSRP, equipment options, body type, transmission, drivetrain, engine, fuel type and colours.

Missing source values remain null. A vehicle without an advertised price is still a valid listing and is included in the dataset. A deal rating of `NA` does not necessarily mean the asking price is missing: the price can exist while the valuation estimate does not. VINs are kept exactly as listed, including shorter identifiers on older vehicles. `source` identifies this scraper and `fetched_at` records the UTC collection timestamp.

#### Output example

The first row of the Honda search shown above, collected on 5 October 2026:

```json
{
  "listing_id": "458462492",
  "url": "https://www.cargurus.com/details/458462492",
  "title": "2019 Honda Accord 1.5T LX FWD",
  "source": "cargurus-scraper",
  "fetched_at": "2026-10-05T21:09:03.183Z",
  "position": 1,
  "country": "US",
  "currency": "USD",
  "condition": "used",
  "brand": "Honda",
  "make": "Honda",
  "make_id": "m6",
  "model": "Accord",
  "model_id": "d585",
  "vin": "1HGCV1F14KA116093",
  "year": 2019,
  "trim": "1.5T LX FWD",
  "price": 18738,
  "price_text": "$18,738",
  "total_price": 19536,
  "mileage": 35313,
  "mileage_unit": "MILES",
  "deal_rating": "GOOD_PRICE",
  "expected_price": 20328,
  "price_differential": 1590,
  "deal_score": 1.133627,
  "days_on_market": 26,
  "dealer_name": "Genesis of Denville",
  "dealer_id": "1363239",
  "dealer_city": "Denville, NJ",
  "dealer_state": "NJ",
  "dealer_zip": "07834",
  "dealer_phone": "(973) 319-7910",
  "seller_type": "DEALER",
  "image_url": "https://static.cargurus.com/images/forsale/2026/09/13/05/56/2019_honda_accord-pic-6954624440122660088-1024x768.jpeg",
  "distance_miles": 27.30666,
  "inclusion_type": "DEFAULT",
  "body_type": "Sedan",
  "transmission": "Continuously Variable Transmission",
  "drivetrain": "Front-Wheel Drive",
  "fuel_type": "Gasoline",
  "engine": "192 hp 1.5L I4",
  "exterior_color": "White",
  "interior_color": "Black",
  "options": ["Power Mirror Package", "Adaptive Cruise Control", "Alloy Wheels", "Bluetooth", "Backup Camera", "Android Auto", "CarPlay"],
  "stock_number": "26350TB",
  "msrp": null,
  "offset": 0
}
```

Here the asking price is $1,590 below the CarGurus market value of $20,328, which is why the listing carries the `GOOD_PRICE` rating.

### Pagination and collection limits

Request between 1 and 1000 listings. The actor follows continuation cursors when a collection needs multiple requests, removes duplicate listing identifiers and numbers positions across the delivered dataset. The requested limit is a maximum, not a guarantee that sufficient matching vehicles exist.

The source does not expose a reliable total count. A continuation cursor means the end has not yet been confirmed; a short final page or an empty source response ends collection. If a later page cannot be collected, earlier results remain available and the output reports a partial collection with a warning. Live inventory changes while pages are fetched, so repeated searches can return different counts and ordering.

### Use cases for CarGurus data

- **Dealers** compare competing inventory by make, model, age, mileage and location, and see which nearby cars CarGurus rates as a good or great price.
- **Valuation and pricing tools** compare asking prices with the CarGurus market value estimate and follow CarGurus price trends for a model by repeating the same search over time.
- **Insurers and vehicle research** join listings on VIN to a separate vehicle specification or recall dataset, so one row carries the asking price, the market value and the vehicle's technical facts.
- **Market analysts** measure days on market and price differentials per region to see where inventory moves quickly and where it sits.

The actor supplies public listing facts; it does not infer accident history, vehicle ownership or insurance risk from those facts.

### CarGurus Scraper compared with other options

CarGurus offers a developer program, but its public tools centre on features such as dealer reviews and a car selector widget, not on a bulk export of search inventory with market values. This actor fills that gap: it returns the listing data you see in a CarGurus search as structured rows, including the market value estimate, deal rating and price differential for each car.

Other CarGurus scrapers on the Apify Store mostly return the listing, price and dealer. This actor also delivers the VIN as a join key, the market value estimate and deal rating as a free valuation per car, days on market, and a resumable offset cursor so a large collection can continue in a later run. Listings without an advertised price are kept rather than dropped, and nationwide shipping offers are filtered out of local searches unless you ask for them.

### Pricing

This actor uses pay-per-event pricing: you pay per delivered vehicle listing, listed at $0.005 per listing ($5 per 1,000 listings). There is no start fee, and searches that deliver no listings cost nothing. Listings without prices still count because they provide vehicle and dealer data. The actor's Pricing tab shows the current published rate; check it before running a large collection. Standard Apify platform usage charges follow your account plan.

Free-tier runs are limited to ten delivered listings. Paid runs can request up to 1000. The cap applies to delivered dataset rows, and duplicate vehicles are counted once. The actor uses Apify's event accounting rather than a separate credit balance.

### FAQ

#### Is there a CarGurus API for listings?

CarGurus does not publish an open API for bulk search inventory. CarGurus Scraper works as a CarGurus listings API: send a ZIP, radius and filters through the Apify API and receive structured JSON rows back, or schedule the actor and read the dataset.

#### Does the scraper verify that a ZIP code exists?

It checks that the ZIP has five digits. CarGurus may silently fall back to another location for a well-formed but nonexistent ZIP, so use a known ZIP and inspect dealer locations when geographic precision matters.

#### Are mileage values kilometres?

No. Mileage, the mileage filter and search distance are in miles. Prices and market value estimates are USD. Convert units explicitly if your downstream system uses kilometres or another currency.

#### Why can a listing have a null market value?

CarGurus does not publish an estimate for every vehicle. Null valuation values are preserved, and the vehicle remains in the dataset. The scraper does not generate replacement estimates.

#### Can I collect more than 1000 listings for one search?

Yes, across several runs. Each run returns at most 1000 listings, and every row carries its source `offset`. Start the next run with the same search and `offset` set to the last row's offset plus one to continue where the previous run ended.

#### Can I collect accidents, ownership history or every photo?

Those fields are outside this actor's output. It collects search listing data and the main image. Use the supplied listing URL to review additional details in your own workflow.

# Actor input Schema

## `zip` (type: `string`):

Five-digit US ZIP code. CarGurus may silently fall back for a nonexistent ZIP.

## `radius` (type: `integer`):

Search radius in miles: 10–500, or 0 for nationwide.

## `make` (type: `string`):

Exact make name (case-insensitive) or CarGurus make id, such as m6 for Honda.

## `model` (type: `string`):

Exact model name with make, or a CarGurus model id, such as d2243 for QX60.

## `price_min` (type: `integer`):

Minimum asking price in USD.

## `price_max` (type: `integer`):

Maximum asking price in USD.

## `year_min` (type: `integer`):

Minimum model year.

## `year_max` (type: `integer`):

Maximum model year.

## `mileage_max` (type: `integer`):

Maximum odometer reading in miles, not kilometres.

## `sort` (type: `string`):

Sort order used by CarGurus.

## `condition` (type: `string`):

Search used or new vehicles. Output echoes the requested inventory type.

## `include_shipping` (type: `boolean`):

Include nationwide-shipping and store-transfer offers outside the local inventory.

## `limit` (type: `integer`):

Maximum delivered rows; requests exceeding 20 source pages continue with next_cursor. Apify follows the cursor.

## `offset` (type: `integer`):

Zero-based source listing offset. This is not the output row position.

## `cursor` (type: `string`):

Resume with next_cursor from a previous response, using the same search. Overrides offset.

## Actor input object example

```json
{
  "zip": "10001",
  "radius": 50,
  "sort": "best_match",
  "condition": "used",
  "include_shipping": false,
  "limit": 48,
  "offset": 0
}
```

# Actor output Schema

## `results` (type: `string`):

One dataset row per vehicle.

## `output` (type: `string`):

Collection counts, warnings and continuation status.

# 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 = {
    "zip": "10001"
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/cargurus-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 = { "zip": "10001" }

# Run the Actor and wait for it to finish
run = client.actor("s-r/cargurus-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 '{
  "zip": "10001"
}' |
apify call s-r/cargurus-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/cargurus-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/001rCvxs0afLphBPA/builds/nwVTMfjCJrUcxLddH/openapi.json
