# Cars.com Listings Scraper (`devilscrapes/cars-com-listings-scraper`) Actor

Scrape used and new car listings from cars.com by zip code, make, model, and radius. We handle the blocks and retries so you get VIN, price, mileage, full spec sheet, seller info, and photos in one clean, normalized dataset.

- **URL**: https://apify.com/devilscrapes/cars-com-listings-scraper.md
- **Developed by:** [DevilScrapes](https://apify.com/devilscrapes) (community)
- **Categories:** Automation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

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

<div align="center">
  <img src=".actor/icon.svg" width="160" alt="Devil Scrapes mark" />

## Cars.com Listings Scraper

**💰 $1.40 / 1 000 results**  ·  pay only for results  ·  no credit card to try

*The devil's in the data -- we make sure it lands clean.* 😈

Scrape used and new car listings from cars.com by ZIP code, make, model, and radius. Get VIN, price, mileage, a full spec sheet, seller info, and photos -- normalized into one clean dataset instead of a raw HTML dump.

</div>

***

### What this scrapes 🎯

cars.com's zip-centered search results and each listing's own vehicle detail page, for a make/model/distance/stock-type-filtered search -- one dataset row per vehicle. Point it at a ZIP code and optional make/model/radius filters, or paste a full search URL you built on the site yourself, and get back VIN, price, mileage, year, make/model/trim, engine spec, exterior/interior color, seller info, dealer rating, photos, and description, all normalized into one Pydantic-validated schema.

### 🔥 What we handle for you

- 🛡️ **We rotate browser fingerprints on every request** -- `curl-cffi` impersonates real Chrome, Firefox, and Safari TLS/HTTP handshakes, so nothing about the traffic looks like a bare Python script.
- 🌐 **We route every request through Apify Proxy**, with a fresh session on each run.
- 🔁 **We retry with exponential backoff** on rate-limit and block responses -- up to 5 attempts, re-impersonating a fresh browser profile each time, before we give up on a page.
- 🧱 **We isolate faults per listing.** One malformed card or one dealer's detail page that won't load logs a warning and gets skipped -- the rest of the run keeps going, and you always get a clear status message, never a silent empty dataset.
- 🧊 **Clean, typed dataset rows** -- every row is `ResultRow`-validated (Pydantic), VIN charset-checked, ISO-8601 timestamps, ready to export as JSON, CSV, or Excel.
- 💰 **Pay-per-result pricing** -- a small one-off warm-up charge, then you pay only for rows that land in your dataset.

### Use cases 💡

- Used-car price analytics and comps by make, model, and year.
- Dealer inventory monitoring -- diff successive runs to catch new arrivals and price cuts.
- Market research on price, mileage, and spec mix across a metro area.
- Lead generation from dealer names, locations, and inventory depth.
- Feeding a VIN-decode or vehicle-history pipeline with a clean, deduplicated VIN list.

### How to use it ⚙️

1. Click **Try for free** at the top of the page.
2. Set a **ZIP code** and, optionally, **Makes** / **Models** / **Maximum distance** / **Stock type** -- or paste a **Search URL override** you already built on cars.com.
3. Click **Start**. Output streams into the run's dataset.
4. Export from **Storage → Dataset** as JSON, CSV, or Excel -- or fetch via the API.

### Input 📥

| Field | Type | Required | Default | Notes |
|---|---|:--:|---|---|
| `zipCode` | `string` | no | `"90210"` | US 5-digit ZIP code anchoring the zip-centered search. |
| `maximumDistance` | `string` | no | `"50"` | Search radius in miles from `zipCode`, or `"all"` for nationwide. |
| `stockType` | `string` | no | `"used"` | `new`, `used`, or `all`. |
| `makes` | `array` | no | `[]` | Make slugs (e.g. `"toyota"`). Leave empty for all makes. Up to 10 entries. |
| `models` | `array` | no | `[]` | Model slugs in `<makeSlug>-<modelSlug>` form (e.g. `"toyota-camry"`). Up to 10 entries. |
| `maxResults` | `integer` | no | `50` | Hard cap on dataset rows (max 1 000). The Actor paginates until this cap or the last page. |
| `fetchDetails` | `boolean` | no | `true` | Fetch each listing's vehicle detail page for VIN, stock number, drivetrain, split colors, engine spec, accident/one-owner badges, dealer rating, photos, and description. Turn off for search-card fields only (fewer requests). |
| `searchUrl` | `string` | no | `null` | Full cars.com search URL, used verbatim instead of the filter fields above. |
| `proxyConfiguration` | `object` | no | `{"useApifyProxy": true}` | Apify Proxy configuration. |

#### Example input

```json
{
  "zipCode": "90210",
  "maximumDistance": "50",
  "stockType": "used",
  "makes": ["toyota"],
  "models": ["toyota-camry"],
  "maxResults": 5,
  "fetchDetails": true,
  "searchUrl": null,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

### Output 📤

Every row is one vehicle listing.

| Field | Type | Notes |
|---|---|---|
| `listing_id` | `string` | cars.com listing ID. |
| `listing_url` | `string` | Absolute URL to the vehicle detail page. |
| `vin` | `string` | 17-character VIN, charset-validated (no `I`/`O`/`Q`); null when absent or malformed. |
| `stock_number` | `string` | Dealer stock number. Detail-page only. |
| `title` | `string` | Listing headline (year + make + model + trim). |
| `make` / `model` / `trim` | `string` | Vehicle manufacturer, model name, and trim / version line. |
| `year` | `integer` | Model year. |
| `price` | `integer` | Asking price; null for "Call for price" listings. |
| `currency` | `string` | Constant `"USD"`. |
| `mileage_mi` | `integer` | Odometer reading in miles. |
| `fuel_type` / `transmission` | `string` | Fuel type and gearbox. |
| `drivetrain` | `string` | FWD / RWD / AWD / 4WD. Detail-page only. |
| `engine_power_hp` / `engine_displacement_l` / `cylinder_count` | `number` | Engine spec. Detail-page only. |
| `body_type` | `string` | Body style (e.g. Sedan, SUV, Truck). |
| `exterior_color` / `interior_color` | `string` | Split exterior and interior colors. Detail-page only. |
| `accident_history` / `one_owner` | `string` / `boolean` | Free badge text, best-effort. Detail-page only. |
| `location` | `string` | Dealer city/state. |
| `distance_from_zip` | `number` | Distance in miles from your input ZIP code. |
| `seller_type` | `string` | `private` or `dealer` -- overwhelmingly `dealer` on cars.com. |
| `seller_name` | `string` | Dealer / seller name. |
| `dealer_rating` | `number` | Dealer rating, 0-5 scale. Detail-page only. |
| `photo_urls` | `array` | Listing photo URLs; empty array when none matched. |
| `description` | `string` | Full listing description text. Detail-page only. |
| `posted_date` | `string` | ISO-8601 posted date when resolvable. Detail-page only. |
| `scraped_at` | `string` | ISO-8601 wall-clock time of row construction. |

#### Example output

```json
{
  "listing_id": "704f8221-1111-2222-3333-000000000001",
  "listing_url": "https://www.cars.com/vehicledetail/704f8221-1111-2222-3333-000000000001/",
  "vin": "4T1BF1FK5GU123456",
  "stock_number": "P12345",
  "title": "2023 Toyota Camry SE",
  "make": "Toyota",
  "model": "Camry",
  "trim": "SE",
  "year": 2023,
  "price": 24998,
  "currency": "USD",
  "mileage_mi": 18420,
  "fuel_type": "Gasoline",
  "transmission": "Automatic",
  "drivetrain": "FWD",
  "engine_power_hp": 203,
  "engine_displacement_l": 2.5,
  "cylinder_count": 4,
  "body_type": "Sedan",
  "exterior_color": "Celestial Silver",
  "interior_color": "Black",
  "accident_history": "No Accidents Reported",
  "one_owner": true,
  "location": "Beverly Hills, CA",
  "distance_from_zip": 4.2,
  "seller_type": "dealer",
  "seller_name": "Beverly Hills Toyota",
  "dealer_rating": 4.6,
  "photo_urls": [
    "https://platform.cstatic-images.com/xlarge/.../1.jpg"
  ],
  "description": "Certified Pre-Owned, one owner, clean history...",
  "posted_date": "2026-08-01T00:00:00Z",
  "scraped_at": "2026-08-15T12:00:00.000Z"
}
```

### Pricing 💰

Pay-Per-Event -- you pay only when these events fire:

| Event | USD | What it is |
|---|---:|---|
| `actor-start` | $0.20 | One-off warm-up charge per run |
| `result-row` | $0.0012 | Per dataset item |

Example: 1 000 results at the rates above ≈ **$1.40**. No subscription, no minimum, no card to start -- Apify gives every new account $5 of free credit.

### Limitations 🚧

- `maxResults` is hard-capped at 1 000 rows per run -- split larger pulls across multiple runs.
- `accident_history` and `one_owner` reflect only the free badge text cars.com shows on the listing page -- this is not a purchased CARFAX or AutoCheck report, and we never buy or scrape one on your behalf.
- `vin` is emitted `null` whenever the site's value doesn't pass a strict 17-character VIN charset check (no `I`/`O`/`Q`), rather than handing you a malformed VIN.
- Detail-page-only fields (VIN, stock number, drivetrain, split colors, engine spec, accident/one-owner badges, dealer rating, photos, description, posted date) require `fetchDetails: true`; turn it off for a faster, cheaper search-card-only run.
- One search configuration per run -- no multi-search fan-out in a single call.
- We actively retry and rotate our browser fingerprint on any block or rate-limit response; on a genuinely hostile run the Actor fails loud with a clear status message instead of handing back a quiet empty dataset.

### FAQ ❓

**What happens if cars.com blocks a request mid-run?**

We retry with exponential backoff and rotate to a fresh browser fingerprint automatically -- up to 5 attempts per page. If the very first search page can't be read at all, the run fails loud with a clear error instead of returning an empty dataset with a green status.

**Why is `vin` sometimes `null`?**

We only emit a VIN that passes a strict 17-character charset check (no `I`, `O`, or `Q` -- the standard VIN exclusion set). If the site's value doesn't pass, we return `null` rather than hand you a value that isn't a real VIN.

**Do I need `fetchDetails` turned on?**

Only if you want VIN, stock number, drivetrain, split exterior/interior colors, full engine spec, accident/one-owner badges, dealer rating, photos, or description. Search-card fields (title, price, mileage, year, make/model/trim, location, distance) come back either way, faster and cheaper with `fetchDetails: false`.

**Can I get a full CARFAX or AutoCheck report?**

No. `accident_history` and `one_owner` are the free badge text cars.com shows publicly on the listing page -- we never purchase or scrape a paywalled vehicle-history report.

**What if one listing has a broken or unusual page?**

We isolate failures per listing. A malformed card or an unreadable detail page logs a warning and gets skipped; the rest of the run keeps going, and you get a clear status message on how many rows landed.

**Is this legal to run?**

We only fetch what cars.com serves on its public search and listing pages. We never log in, never touch a dealer contact form, and never scrape any authenticated account feature. Match your own use case against cars.com's terms before using the data commercially.

### Your feedback 💬

Spotted a bug, hit a weird edge case, or need a new field? Open an
issue on the Actor's **Issues** tab on Apify Console -- we ship
fixes weekly and we read every report.

***

<div align="center">

Built by **[Devil Scrapes](https://apify.com/DevilScrapes)** 😈 -- a small fleet of
opinionated public-data Actors. Honest pricing, real engineering, zero fine print.

</div>

# Actor input Schema

## `zipCode` (type: `string`):

US 5-digit ZIP code anchoring the zip-centered search (e.g. <code>"90210"</code>).

## `maximumDistance` (type: `string`):

Search radius in miles from <b>ZIP code</b>, or <code>"all"</code> for a nationwide search.

## `stockType` (type: `string`):

cars.com's <code>stock\_type</code> filter.

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

Make slugs to filter by (e.g. <code>"toyota"</code>). Leave empty for all makes. Up to 10 entries.

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

Model slugs in <code>\<makeSlug>-\<modelSlug></code> form (e.g. <code>"toyota-camry"</code>). Leave empty for all models within <b>Makes</b>. Up to 10 entries.

## `maxResults` (type: `integer`):

Hard cap on dataset rows. The Actor paginates cars.com's search results until this cap or the last page.

## `fetchDetails` (type: `boolean`):

Fetch each listing's vehicle detail page for stock number, drivetrain, split colors, engine/cylinder detail, accident/one-owner badge, dealer rating, photos, and description. Costs one extra browser render PER ROW -- off by default. Core fields (make/model/year/price/mileage/VIN/photos) are already included either way.

## `searchUrl` (type: `string`):

Full cars.com search URL, used verbatim instead of building one from <b>ZIP code</b> / <b>Maximum distance</b> / <b>Stock type</b> / <b>Makes</b> / <b>Models</b>. Leave empty to use those fields instead.

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

Apify Proxy configuration. Defaults to RESIDENTIAL, country=US -- the only tier that clears cars.com's bot management.

## Actor input object example

```json
{
  "zipCode": "90210",
  "maximumDistance": "50",
  "stockType": "used",
  "makes": [
    "toyota"
  ],
  "models": [
    "toyota-camry"
  ],
  "maxResults": 10,
  "fetchDetails": false,
  "searchUrl": null,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

All dataset items as JSON.

## `datasetItemsCsv` (type: `string`):

Same data exported to CSV.

## `datasetView` (type: `string`):

Open the run dataset in the Console.

# 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 = {
    "zipCode": "90210",
    "maximumDistance": "50",
    "stockType": "used",
    "makes": [
        "toyota"
    ],
    "models": [
        "toyota-camry"
    ],
    "maxResults": 10,
    "fetchDetails": false,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("devilscrapes/cars-com-listings-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 = {
    "zipCode": "90210",
    "maximumDistance": "50",
    "stockType": "used",
    "makes": ["toyota"],
    "models": ["toyota-camry"],
    "maxResults": 10,
    "fetchDetails": False,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("devilscrapes/cars-com-listings-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 '{
  "zipCode": "90210",
  "maximumDistance": "50",
  "stockType": "used",
  "makes": [
    "toyota"
  ],
  "models": [
    "toyota-camry"
  ],
  "maxResults": 10,
  "fetchDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call devilscrapes/cars-com-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,devilscrapes/cars-com-listings-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/W01QP69oUWX5zC8Jg/builds/ZxLbE7fFKJEQkGTFL/openapi.json
