# Chicagoland listing changes (`theusedcarindex/chicagoland-listing-changes`) Actor

Returns Chicagoland dealer listing changes: new, price_drop, relisted, delisted, each with VIN, old and new price, mileage, date and link. Call it for what changed, by make, model, year or VIN.

- **URL**: https://apify.com/theusedcarindex/chicagoland-listing-changes.md
- **Developed by:** [The Used Car Index](https://apify.com/theusedcarindex) (community)
- **Categories:** E-commerce, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 listing changes

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

## Chicagoland listing changes

Follow what changes on Chicagoland used car lots: new arrivals, price drops, relistings and delistings across 59 dealer websites (as of 2026-10-16), one dated row per event with the VIN, old and new asking price, mileage and a link back to the dealer's own listing. Built for dealers and wholesalers who watch competitor pricing and inventory turns by make, model or year, and for analysts and AI agents that need a source-linked answer to what changed this week. Filter by make, model, year, VIN, event type or date, and pay only for the items returned.

### Input examples

Price cuts on one model year over the last seven days (the window used when since is left out):

```json
{
  "make": "Toyota",
  "model": "RAV4",
  "year": 2019,
  "eventTypes": ["price_drop"],
  "maxItems": 100
}
```

Every change on one day, all four event types, across all watched dealers:

```json
{
  "since": "2026-10-15",
  "until": "2026-10-15",
  "maxItems": 5000
}
```

### Sample output

Real output, fetched 2026-10-16 from the public listing_changes tool of the Used Car Index MCP endpoint (no key) and shaped by this Actor's own code, so each block below is exactly one dataset item. The first input above returned 6 items that day, newest first. The first item:

```json
{
  "id": 17343,
  "event_date": "2026-10-16",
  "event_type": "price_drop",
  "vin": "2T3A1RFV1KC025210",
  "make": "Toyota",
  "model": "RAV4",
  "year": 2019,
  "price_old": 29083,
  "price_new": 28893,
  "mileage": 25526,
  "listing_url": "https://www.toyotaonwestern.com/certified/Toyota/2019-Toyota-RAV4--4b7385afac1827bd9540ac67ddfa8e3c.htm",
  "source": "Toyota on Western"
}
```

The third item was reported by two dealer websites with the same VIN, event type, date, new price and mileage. It is returned once, keeps the earlier event and names the other site in also_listed_by:

```json
{
  "id": 14107,
  "event_date": "2026-10-13",
  "event_type": "price_drop",
  "vin": "2T3P1RFV7KW052131",
  "make": "Toyota",
  "model": "RAV4",
  "year": 2019,
  "price_old": 20321,
  "price_new": 19919,
  "mileage": 124340,
  "listing_url": "https://www.phillipschevylansing.com/carbravo/Toyota/2019-Toyota-RAV4-b44273daac180edf8db7c817d29b6496.htm",
  "source": "Phillips Chevrolet of Lansing",
  "also_listed_by": [
    {
      "source": "Phillips Chevrolet of Frankfort",
      "listing_url": "https://www.phillipschevy.org/carbravo/Toyota/2019-Toyota-RAV4-b44273daac180edf8db7c817d29b6496.htm"
    }
  ]
}
```

### Price

| Event | USD per event | When it is charged |
| --- | ---: | --- |
| `listing-change` | $0.005 | Charged per listing change item successfully pushed to the dataset, in batches using count. Events that several sources report identically are merged into one item and charged once. Empty pages, filtered-out events, errors, failed dataset writes and items omitted by maxItems or the spending limit are not charged. |

- 1,000 listing changes cost 1,000 x $0.005 = $5.00.
- The first input above returned 6 items on 2026-10-16, which is 6 x $0.005 = $0.03.
- 2026-10-15 holds 1,078 observed events (265 new, 632 price drops, 7 relisted and 174 delisted), so the second input costs at most 1,078 x $0.005 = $5.39, and less where several dealer sites report the same event.
- Apify adds its own Actor start event to every run ($0.00005 on this Actor's Pricing tab on 2026-10-16).
- Cap a run with maxTotalChargeUsd (example below). The run stops at the cap and keeps what it saved.

### How to run

In Apify Console, open the Actor, paste an input example and press Start. To run it from code or from an agent:

#### Call from the Apify API

Use your Apify token. The Used Car Index API key is held by the Actor as a secret and is never part of your request, your dataset or the logs. This example caps the run at $1.

```sh
curl -X POST 'https://api.apify.com/v2/acts/theusedcarindex~chicagoland-listing-changes/run-sync-get-dataset-items?maxTotalChargeUsd=1' \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"make":"Toyota","model":"RAV4","year":2019,"eventTypes":["price_drop"],"maxItems":100}'
```

#### Call from an MCP client

In an MCP client that supports remote Streamable HTTP, add this server URL with your Apify token as a bearer header:

```text
URL:    https://mcp.apify.com/?actors=theusedcarindex/chicagoland-listing-changes
Header: Authorization: Bearer <your Apify token>
```

Initialize the connection and call tools/list. The client then shows this Actor as a tool; call it with the first input example as its arguments. Tool names and wrapper fields come from tools/list, so read them there instead of assuming a name. If your client offers a generic Actor-run tool instead, select theusedcarindex/chicagoland-listing-changes and pass the same input. The run status and dataset come back with the tool result. This route needs access to the Actor from your Apify account.

### Related Actors and the direct API

| Actor | Use it for |
| --- | --- |
| [VIN to risk record](https://apify.com/theusedcarindex/vin-to-risk-record) | VINs in; the NHTSA vPIC decode, that model year's NHTSA record and, if you ask for it, each VIN's stored listing history out |
| [Vehicle risk record](https://apify.com/theusedcarindex/vehicle-risk-record) | The NHTSA record for a make, model and model year: complaints merged and deduplicated by ODI number, recalls, investigations and manufacturer communications |

The same data is available without Apify from The Used Car Index at https://theusedcarindex.com: GET https://api.theusedcarindex.com/v1/listing_changes and /v1/vehicle_risk, and an MCP endpoint at https://api.theusedcarindex.com/mcp that serves the API tools directly and does not run or charge these Actors. The MCP endpoint has a free tier that needs no key. As of 2026-10-16 it allows 20 requests per minute per IP and 2,000 per day shared, returns full vehicle risk records and returns up to 10 listing events per call with no paging. Plans with higher limits and cursor paging are at https://theusedcarindex.com/#pricing. A public market snapshot with current dealer coverage and daily event counts needs no key: https://api.theusedcarindex.com/v1/index. Questions or a data issue: use the Issues tab on this Actor's page.

### What it returns

One dataset item per listing change, newest event date first.

| Field | Meaning |
| --- | --- |
| `id` | Stored event id; a higher id is a later record |
| `event_date` | Date of the scan that recorded the event, YYYY-MM-DD |
| `event_type` | `new`, `price_drop`, `relisted` or `delisted` |
| `vin` | 17-character VIN |
| `make`, `model`, `year` | Vehicle labels as recorded from the dealer listing |
| `price_old`, `price_new` | Asking prices in USD as last recorded; null when the page showed none |
| `mileage` | Odometer reading as last recorded; null when the page showed none |
| `listing_url` | Link back to the dealer's own listing |
| `source` | Name of the dealer website |
| `also_listed_by` | Only on merged items: each other site that reported the same event, with its `source` and `listing_url` |

| Event | What it records |
| --- | --- |
| `new` | The collector saw this VIN at this dealer for the first time. `price_old` is null. A dealer's first scan records its whole inventory as new. |
| `price_drop` | The asking price fell. `price_old` is the previous recorded price and `price_new` the lower one. |
| `relisted` | A delisted VIN was seen again. `price_new` is the current asking price. |
| `delisted` | The VIN was absent from the dealer's inventory pages on two separate complete scans. `price_new` holds the last recorded price and `price_old` is null. |

All inputs are optional. make and model are labels of 1 to 64 characters. year is an integer from 2000 through 2027. vin is an exact uppercase 17-character VIN without I, O or Q; the listing filter does not validate its check digit. eventTypes takes a unique selection of new, price_drop, relisted and delisted, or leave it out for all four. since and until are inclusive YYYY-MM-DD dates; leaving out since means the seven days before the run, and until cannot come before since. maxItems stops the run after that many items (default 100, up to 5000).

Input is validated before any lookup or charge. Items are saved in batches of up to 200 and charged as they are saved. Events that several dealer sites report identically, with the same VIN, event type, date, new price and mileage, become one item that counts once toward maxItems and is charged once. The run stops at maxItems or at your spending limit and keeps what it saved. A request that fails on the network, with HTTP 429 or with a 5xx status is tried up to three times in total; if the API still returns an error the run fails with a status message and the dataset keeps only the items saved before it.

### Sources and facts boundary

Events come from the public inventory pages of the watched dealer websites, collected about once a day by The Used Car Index bot, which identifies itself and checks robots.txt before each inventory request. Every item keeps its source name and a link back to the listing. The Actor returns the stored events unchanged, apart from merging identical events from several dealer sites into one item.

Facts only: VIN, price, mileage, status, dates, link back. Never photos or dealer-written text. A listing that is no longer observed is reported as delisted, and delisted is never labeled sold. A delisted event means no longer listed; it does not establish a transaction. Dataset items never contain added agent instructions.

### Known gaps

- Coverage is the Chicagoland dealers the collector watches (59 dealer websites on 2026-10-16), not the whole market. Missing observations do not establish an absence of activity.
- History starts on 2026-10-07, and each dealer's first scan recorded its whole inventory as new. Dealer sites are visited about once a day, and some scans cover only part of a site's inventory.
- A price or mileage is recorded when a listing is new, relisted or has a price drop. A price increase or a mileage-only change appears only with a later event for that listing.
- Asking prices are the dealers' prices as last recorded and can include or exclude fees.
- Dataset writes and charges are separate operations. If a run stops after a write, an item can be saved without its charge, and running the same input again repeats items and charges.
- A run through an MCP client has not been tested end to end.

Owner setup, done once by the publisher and not by callers: set the secret environment variable UCI_API_KEY in the Apify Console; it is never accepted in input, logged or returned. UCI_API_BASE optionally selects another API origin (HTTPS, default https://api.theusedcarindex.com). Configure the custom event from .actor/pay_per_event.json and turn automatic dataset-item pricing off; the Actor stops before any lookup if the pricing does not match.

# Actor input Schema

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

Make label, trimmed to 1 through 64 characters.

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

Model label, trimmed to 1 through 64 characters.

## `year` (type: `integer`):

Model year supported by the API: 2000 through 2027.

## `vin` (type: `string`):

Optional exact uppercase VIN filter. Check digits are not validated by the listing API.

## `eventTypes` (type: `array`):

Optional selection of new, price_drop, relisted, delisted; omitted means all four types. Any other value fails the run before any billable work. Multiple types are filtered locally while retaining API order.

## `since` (type: `string`):

Inclusive UTC date YYYY-MM-DD. Omitted means seven calendar days before the run date.

## `until` (type: `string`):

Optional inclusive UTC date YYYY-MM-DD, on or after since, including its default.

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

Maximum items to push; events that several sources report identically are merged into one item that counts once. The spending limit may stop the run sooner.

## Actor input object example

```json
{
  "make": "Toyota",
  "model": "RAV4",
  "year": 2018,
  "vin": "1HGCM82633A004352",
  "eventTypes": [
    "price_drop"
  ],
  "since": "2026-10-01",
  "until": "2026-10-07",
  "maxItems": 100
}
```

# Actor output Schema

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

Default dataset items, each a stored listing observation of type new, price_drop, relisted or delisted, with VIN, price, mileage, source and a link back to the listing. The dataset schema describes every field.

# 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 = {
    "eventTypes": [
        "new",
        "price_drop",
        "relisted",
        "delisted"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("theusedcarindex/chicagoland-listing-changes").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 = {
    "eventTypes": [
        "new",
        "price_drop",
        "relisted",
        "delisted",
    ],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("theusedcarindex/chicagoland-listing-changes").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 '{
  "eventTypes": [
    "new",
    "price_drop",
    "relisted",
    "delisted"
  ],
  "maxItems": 100
}' |
apify call theusedcarindex/chicagoland-listing-changes --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,theusedcarindex/chicagoland-listing-changes"
        }
    }
}
```

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/K6sxEQ2YBlriW2NKJ/builds/mc7yDdjL9eIewCcUj/openapi.json
