# CarMax Used Car Listings & Price Drop Alerts (`superslowsloth/carmax-listings`) Actor

Search CarMax.com used-car inventory by make and model near a ZIP code and get one flat row per car: price, price drop, mileage, store, shipping fee, trim, colours, engine, MPG, features, VIN, URL. Newest listings first. For new-inventory and price-drop alerts.

- **URL**: https://apify.com/superslowsloth/carmax-listings.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 1 total users, 0 monthly users, 92.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 car listing scrapeds

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

## CarMax Used Car Listings & Price Drop Alerts

Search [CarMax](https://www.carmax.com)'s used-car inventory by make, and
optionally model, near a US ZIP code and get one flat row per car: price, the
price before a drop, mileage, the store it is at and how far that is, the
shipping fee to bring it to you, when CarMax made it available, trim, colours,
engine, MPG, the feature list, VIN and the carmax.com link. Run it on a
schedule sorted **newest listings first** and diff on `stock_number` to get a
**CarMax new-inventory alert**, or filter on `price_dropped` for a **price-drop
alert** on the cars you are watching.

No account, no API key, no login, no browser. One request returns up to 100 cars.

### Input

| Field | Notes |
|---|---|
| `make` | Required. As it appears in a carmax.com address: `toyota`, `ford`, `land-rover`, `mercedes-benz`. Case and spaces do not matter. |
| `model` | Optional. `camry`, `cr-v`, `f150`, `mustang-mach-e`. Spelling that differs from CarMax's only in punctuation (`F-150`, `Mustang Mach-E`) is mapped onto CarMax's. Empty means every model. |
| `zipCode` | Required. Five-digit US ZIP. Distance, shipping fee and arrival dates are measured from the store CarMax assigns to it. |
| `radius` | `nationwide` (default), `25`, `50`, `75`, `100`, `250` or `500` miles from the ZIP. |
| `sort` | `new-arrival` (default, newest listings first), `price-asc`, `price-desc`, `mileage-asc`, `mileage-desc`, `year-desc`, `year-asc`, `distance-asc`, `best-match`. |
| `maxItems` | Cars to read (default 100, up to 10,000). 100 per request. |
| `proxyConfiguration` | Apify proxy by default. |

#### A make or model CarMax does not know

CarMax answers a make or model it has never heard of with HTTP 200 and its
**whole 64,000-car inventory, unfiltered**, and a model that does not belong to
the make drops the make filter too. Left alone, `make: toyta` would return and
bill 100 arbitrary cars. The actor reads the filters CarMax says it applied
(`selectedFacets`) and, when they are not the ones asked for, either maps the
spelling onto CarMax's own list or stops the run with the list of valid makes
(or the models of that make). Nothing is charged for the rows it refuses.

#### The ZIP code and the radius

- A ZIP CarMax does not recognise (`00000`, letters) is answered with HTTP 200
  and a store CarMax picks itself (Kansas City). The actor compares the ZIP CarMax
  echoes with the one you gave and stops the run if they differ.
- The radius is honoured at 25, 50, 75, 100, 250 and 500 miles. Measured for
  Honda from ZIP 90001 (Los Angeles): 142, 395, 485, 546, 803 and 1,312 cars
  against 6,111 nationwide. CarMax silently ignores 5 miles and any other
  distance and answers nationwide, so only the honoured ones are offered.

#### About the sorts

The sorts are CarMax's own and the actor checks each one: CarMax answers a sort
name it does not know with HTTP 200 and its default "best match" order, so the
actor reads the sort the response says it applied and fails the run (at no
charge) rather than return mis-ordered rows. `date-desc`, the name some
write-ups use for newest-first, is one of those ignored names; the working one
is `newarrival`, which this actor sends for `new-arrival`.

`new-arrival` orders by `made_saleable_at`, the time CarMax made the car
available (newest in the 2026-10-12 probe: 2026-10-11 19:38 UTC, descending
from there). Cars marked **coming soon** are listed before they are for sale;
they have no `made_saleable_at`, `is_coming_soon` is true and
`is_saleable` is false. Filter them out if you only want cars you can buy.

### Output

Prices are US dollars, distances and mileage are miles.

| Field | Notes |
|---|---|
| `query` | The make (and model) searched, as CarMax URL segments: `ford` or `ford/f150`. |
| `stock_number`, `url`, `vin` | CarMax's stock number (the number in `https://www.carmax.com/car/<stock_number>`), the link, and the VIN. Compare runs on `stock_number`. |
| `year`, `make`, `model`, `trim`, `body`, `series` | As CarMax shows them. `trim` is null on cars CarMax lists without one (15 of 332 sampled); `series` is null on most cars. |
| `price` | CarMax's listed price, before taxes, title, registration and shipping. |
| `original_price`, `price_dropped` | `price_dropped` is CarMax's own flag. `original_price` is the price before the drop and is **null unless CarMax sends it** - 1 of 332 sampled cars - never 0. A car can be cheaper than last week without CarMax flagging it; for a price history, diff `price` between runs. |
| `mileage` | Odometer, miles. |
| `store_id`, `store_name`, `store_city`, `state`, `state_code`, `distance_miles` | The store the car is at and the distance from your ZIP. `distance_miles` is 0.0 for a car at your ZIP's own store. |
| `made_saleable_at` | When CarMax made the car available (ISO 8601 UTC). **Null for cars that are coming soon** (24 of 332 sampled). |
| `is_new_arrival`, `is_coming_soon`, `is_saleable`, `is_reserved`, `is_available_to_transact` | CarMax's flags. `is_available_to_transact` is whether it can be bought online from your ZIP. |
| `transfer_type`, `transfer_fee`, `transfer_text` | How the car reaches you: `test-drive` (at your store), `shipping-from` (shipped in), `available-elsewhere`, `coming-soon`. `transfer_fee` is the shipping fee in dollars, 0.0 for a car already there or shipped free, and **null when CarMax sends none** (63 of 332 sampled: coming-soon and available-elsewhere cars and some at your store). `transfer_text` is CarMax's line verbatim (`$1999 Shipping`, `Free Shipping`). |
| `transfer_min_days`, `transfer_max_days`, `transfer_arrival` | Estimated transfer time and CarMax's arrival text (`10/13 - 10/16`, `Tuesday`). The arrival text moves with the day the run happens, so do not diff on it. Null when CarMax sends no estimate. |
| `exterior_color`, `interior_color`, `transmission`, `drive_train`, `engine_type`, `engine_size`, `cylinders`, `horsepower`, `torque` | As CarMax words them. `interior_color` is null on 3 of 332 sampled cars, `horsepower` and `torque` on 20. |
| `mpg_city`, `mpg_highway` | Null where CarMax prints none (22 of 332 sampled, mostly electric cars), never 0. |
| `ev_range_miles` | Original battery range, on electric cars. Null on the rest. |
| `vehicle_size`, `vehicle_types`, `packages`, `features` | CarMax's size class, categories, option packages and the full feature list. Empty list when there are none. |
| `prior_use` | Prior use CarMax discloses: `Rental`, `Fleet`, `Leased Vehicle`. Empty when none is disclosed. |
| `badge` | CarMax's card badge: `Popular`, `Coming soon`, `Fast shipping`, `Price drop`. Null on most cars. |
| `image_url` | The hero photo as CarMax sends it (400 px wide; change `width` in the URL for another size). |

#### Honest nulls

A field CarMax did not send is `null`, never `0` or `""`. `original_price`,
`made_saleable_at`, `transfer_fee`, `trim`, `series`, `mpg_city`,
`mpg_highway`, `ev_range_miles` and `badge` are null when the source has
nothing.

#### Reading a result as an alert

- **New inventory:** sort `new-arrival`, keep `is_coming_soon` false, diff on
  `stock_number` against the last run. Newest-first means the first page holds
  what changed since yesterday.
- **Price drops:** keep rows with `price_dropped` true, or diff `price` per
  `stock_number` between runs.
- **Nearby only:** set a radius. Nationwide lists every store's cars, with the
  shipping fee to bring each to you in `transfer_fee`.

### Pricing

Pay per event:

- **$0.002** per run (`actor-start`), charged only after your input is
  validated, so a run that fails on bad input costs nothing.
- **$0.0007** per car row written (`listing-scraped`), i.e. $0.70 per 1,000
  cars.

### How it fetches

It calls the JSON API behind CarMax's own search page
(`www.carmax.com/cars/api/search/run`), up to 100 cars per request. Measured
2026-10-12 from an Apify datacenter exit: HTTP 200 with JSON and no key, no
cookie and no login, held over a 30-minute session. CarMax's edge (Akamai)
answers some requests with an "Access Denied" page and HTTP 403: 15 of 92 probe
requests (about 1 in 6; none in the first 24). It is not tied to a parameter:
one URL was refused in one batch and answered in the next, while two others
(a `take=6` newest-first search for an unknown make, and mileage-high-to-low
with `take=6`) were refused every one of the three times they were sent and
answered once `take` changed. The actor treats a 403, 429 or 5xx as a refusal,
rotates to a fresh address and retries; a refusal costs time and is never
charged. An HTTP 400 is permanent and is not retried. How often a production
run sees a refusal at volume is unmeasured.

Things worth knowing, all measured:

- **Page size.** `take` up to 100 works; 101 and above is HTTP 400. Each
  response carries about 200 KB of filter data on top of the cars, so the actor
  asks for 100 at a time.
- **Totals.** `totalCount` is exact but drifts by a few between requests as cars
  are sold and listed (64,327 to 64,348 within the same minute). A walk can show
  a car twice across a page boundary; it is returned once.
- **Depth.** Offsets 5,000 and 6,000 into a 6,113-car make answered normally;
  an offset past the end is HTTP 200 with no cars, which ends the walk.
- **Not offered.** CarMax's price, year, mileage and colour filters, and its
  free-shipping filter, are not inputs; this actor searches by make, model, ZIP
  and radius.

# Actor input Schema

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

The make to search, as it appears in a carmax.com address (for example toyota, ford, land-rover or mercedes-benz). Case and spaces do not matter. CarMax answers a make it does not know with its whole inventory, so the actor checks the make against CarMax's own list and stops with the list of valid makes instead.

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

Optional. Only this model of the make, as it appears in a carmax.com address (for example camry, cr-v, f150 or mustang-mach-e; F-150 and Mustang Mach-E are mapped onto CarMax's spelling). Leave empty for every model of the make.

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

A five-digit US ZIP code, for example 60601. CarMax measures each car's distance, shipping fee and arrival dates from the store assigned to this ZIP. A ZIP CarMax does not recognise stops the run before anything is charged.

## `radius` (type: `string`):

Only cars at stores within this many miles of the ZIP code, or nationwide (every CarMax store, with the shipping fee to bring the car to you). Only the distances CarMax honours are offered; it ignores 5 miles and answers nationwide.

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

The order CarMax lists the cars in. 'Newest listings first' orders by when CarMax made each car available and is the one to schedule for new-inventory alerts; cars that are coming soon (not yet for sale) have no such date. 'Distance' is measured from the ZIP code.

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

Read at most this many cars. CarMax serves 100 per request. Up to 10,000 are accepted; a single make can hold several thousand (Ford: about 3,450 on 2026-10-12).

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

Apify proxy (automatic datacenter exits) is the default. CarMax's edge now and then answers a request with an Access Denied page (HTTP 403); the request is retried from a fresh address, which is what the proxy is for.

## Actor input object example

```json
{
  "make": "toyota",
  "zipCode": "60601",
  "radius": "nationwide",
  "sort": "new-arrival",
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (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 = {
    "make": "toyota",
    "zipCode": "60601",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/carmax-listings").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 = {
    "make": "toyota",
    "zipCode": "60601",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/carmax-listings").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 '{
  "make": "toyota",
  "zipCode": "60601",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call superslowsloth/carmax-listings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,superslowsloth/carmax-listings"
        }
    }
}
```

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/xkKaRCu0xMG8scDv9/builds/ZTD9sqePdAOQvlj6R/openapi.json
