# Car Dealer Website Inventory Scraper: VIN, Price & Stock (`fayoussef/dealer-inventory-scraper`) Actor

Scrape live vehicle inventory from any car dealership's own website, not a marketplace. Paste a dealer homepage and get every car at VIN level with price, mileage and trim. Auto-detects DealerOn, Dealer.com, Dealer Inspire and more. Tracks price drops and sold units.

- **URL**: https://apify.com/fayoussef/dealer-inventory-scraper.md
- **Developed by:** [youssef farhan](https://apify.com/fayoussef) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 vehicle scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

### What does Car Dealer Website Inventory Scraper do?

**Car Dealer Website Inventory Scraper pulls live vehicle inventory straight from a dealership's own website.** Paste a dealer homepage such as `https://www.examplemotors.com` and it finds their inventory pages by itself, then returns **every vehicle at VIN level with the dealer's own asking price, mileage, trim, colour, stock number and a link to the listing**. Run it on a schedule and it also tells you **what changed: which cars are new, which were discounted, which went up and which have left the lot**.

This is not a marketplace scraper. A dealer's own website carries cars that never reach AutoTrader or Cars.com, and it carries the dealer's own number, which is the price that moves first when they discount. Reading the dealer site directly is the only way to see either.

**It works on dealer sites it has never seen before.** A thousand dealership websites are really about a dozen vendor platforms with a thousand tenants, so nothing here is written per dealer. The Actor detects the platform, finds the inventory page the way that platform lays it out, and reads whichever structured source the page carries: the Automotive Standards Council data layer, schema.org markup, the JSON behind a client-side grid, or the `data-vin` attributes on the vehicle cards. Detected platforms include **DealerOn, Dealer.com, Dealer Inspire, DealerFire, Sincro/CDK, Dealer eProcess, Fox Dealer, Team Velocity, Dealer Spike, AutoFusion, EDealer, D2C Media and Convertus**.

Runs on Apify, so you get a REST API, scheduling, webhooks, integrations (Google Sheets, Slack, Make, Zapier), monitoring, residential proxy rotation and exports to JSON, CSV, Excel or Google Sheets without building any of it.

### Why use this car dealer inventory scraper?

- **Competitor inventory monitoring.** Watch the lot down the road: what they stock, what they ask, and how long a unit sits before it gets cut.
- **Automotive agency reporting.** Pull VIN-level inventory for every rooftop you manage into one dataset, on a schedule.
- **Price-drop and discount tracking.** Get the exact dollar change per VIN between runs, not a vague "prices dropped" signal.
- **Days-on-lot and sell-through analysis.** The `listedSince` date plus the `removed` status tells you how fast a dealer actually turns metal.
- **Market and pricing intelligence.** Build a dealer-priced dataset that marketplaces cannot give you, because marketplace listings lag the dealer's own site.
- **Feed and syndication QA.** Check what a dealer's website really shows against what their feed claims.
- **Lead lists and vehicle sourcing.** Find specific VINs, trims or price bands across a set of dealers in one run.
- **AI agents and RAG.** Clean, flat, VIN-keyed rows that drop straight into a vector store or an agent tool.

### How to use Car Dealer Website Inventory Scraper

1. Click **Try for free**.
2. Paste dealer websites into the **Dealer websites** field, one per line. The homepage is enough; an inventory URL works too if you want one exact search.
3. Pick **Which vehicles** to read: everything, used only, new only or certified pre-owned.
4. Click **Start**. The log names the platform it detected and where it found the inventory.
5. Open the **Output** tab and export as JSON, CSV, Excel or HTML, or read it from the API.

To watch dealers over time, turn on **Track changes between runs**, give the run a **Watchlist name**, and schedule it. The first run is your baseline; every run after that labels each vehicle `new`, `price_drop`, `price_increase`, `unchanged` or `removed`.

No API keys and no proxy setup are required.

### Input

Set everything in the **Input** tab. Only **Dealer websites** is required.

| Field | What it does |
|---|---|
| `dealerUrls` | Dealership websites to read, one per line. Homepage or inventory URL. |
| `condition` | `all`, `used`, `new` or `certified`. |
| `maxVehiclesPerDealer` | Stop after N vehicles per dealer. Default 200. |
| `fetchDetails` | Open each vehicle's own page to fill in mileage, engine, transmission and description. Only vehicles actually missing data are fetched. |
| `trackChanges` | Compare with the previous run and label new, discounted, dearer and removed vehicles. |
| `monitorKey` | Names the history that change tracking compares against. |
| `maxPagesPerDealer` | Safety cap on pagination depth. Paging stops early on its own. |
| `concurrency` | How many dealer sites to read at once. |
| `proxyConfiguration` | Optional. Defaults to Apify Proxy residential, which most dealer sites require. |

```json
{
    "dealerUrls": [
        "https://www.toyotaofdowntownla.com",
        "https://www.mbofsmithtown.com"
    ],
    "condition": "used",
    "maxVehiclesPerDealer": 200,
    "fetchDetails": false,
    "trackChanges": true,
    "monitorKey": "my-competitors"
}
```

### Output

One row per vehicle. Download as JSON, HTML, CSV or Excel, or read it straight from the API.

```json
{
    "vin": "4T1DAACK1SU189265",
    "stockNumber": "TU13244T",
    "condition": "used",
    "year": 2025,
    "make": "Toyota",
    "model": "Camry",
    "trim": "SE",
    "bodyStyle": "Sedan",
    "price": 31791,
    "msrp": null,
    "mileage": 12480,
    "exteriorColor": "Ice Cap",
    "fuelType": "gas",
    "vehicleUrl": "https://www.toyotaofdowntownla.com/viewdetails/used/4t1daack1su189265/2025-toyota-camry",
    "listedSince": "2025/07/29",
    "dealerWebsite": "www.toyotaofdowntownla.com",
    "websitePlatform": "Team Velocity",
    "status": "price_drop",
    "priceChange": -750,
    "scrapedAt": "2026-09-04T18:42:19Z"
}
```

The dataset has three ready-made views: **Inventory**, **Changes since last run** and **Full specification**.

#### What `status` means

| Value | Meaning |
|---|---|
| `new` | Not on the lot at the previous run. Every row on a first run. |
| `price_drop` | Cheaper than last run. `priceChange` is negative. |
| `price_increase` | Dearer than last run. |
| `unchanged` | Same price as last run. |
| `removed` | Was on the lot last run and is not now. Usually sold. |

### Which dealer websites work

The Actor reads a dealer site through whatever structured data that site publishes, so coverage follows the platform rather than the brand.

- **Reads well:** dealers whose listing pages carry the ASC/GA4 automotive data layer, schema.org `Vehicle`, `Car`, `Product` or `ItemList` markup, `data-vin` card attributes, or an embedded inventory JSON blob. In practice that is most of the market, because Google's rich results require schema.org markup and the OEMs require the ASC data layer.
- **Falls back to the sitemap** when a listing grid is rendered entirely in the browser. Slower, and it needs `fetchDetails` to get prices, but it reads sites that would otherwise return nothing.
- **Reports clearly and charges nothing** when a dealer site renders inventory purely client-side with no sitemap, or sits behind a bot wall that refuses the run. You get a warning naming the dealer and the platform, not a silently empty dataset.

Every run logs the platform it detected and how it found the inventory, so coverage across a portfolio of dealers is auditable rather than a guess.

### How much does it cost?

Pay per event. You are charged for the vehicles you actually receive:

- **Vehicle scraped**, per vehicle row returned.
- **Detail page fetched**, only when `fetchDetails` is on and the vehicle was actually missing something.
- **Change detected**, only on runs that have a previous snapshot to compare against, and only for `new`, `price_drop`, `price_increase` and `removed`.

A dealer whose site could not be read produces no rows and costs nothing beyond the run itself.

### Is it legal to scrape dealer websites?

The Actor reads only publicly available pages that any visitor can open, and collects no personal data. Public data collection is generally lawful, but you are responsible for how you use what you collect, including any local rules on competitor monitoring and database rights. If you are unsure, take legal advice.

### Support

Found a dealer site that does not read? Send the URL and it gets looked at: **youssefarhan24@gmail.com**. Need a different marketplace or portal covered? [Suggest it here](https://automationbyexperts.com/apify).

# Actor input Schema

## `dealerUrls` (type: `array`):

The dealership websites to read, one per line. Paste the homepage (https://www.examplemotors.com) and the inventory page is found automatically, or paste an inventory URL directly to scrape exactly that search. Works with DealerOn, Dealer.com, Dealer Inspire, DealerFire, Sincro, Dealer eProcess, Fox Dealer and most other dealer website platforms.

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

Limit the scrape to one part of the lot. "Everything" tries the all-inventory page first and falls back to used, new and certified in turn.

## `maxVehiclesPerDealer` (type: `integer`):

Stop after this many vehicles from each dealer. A typical franchise dealer lists 100 to 400 vehicles.

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

Open each vehicle's own page to fill in anything the listing page left out, such as mileage, engine, transmission and the full description. Only vehicles that are actually missing something are fetched, so dealers whose listing pages already carry full data cost nothing extra.

## `trackChanges` (type: `boolean`):

Compare this run against the previous one and label every vehicle new, price\_drop, price\_increase, unchanged or removed. Turn this on and schedule the Actor to watch a competitor's lot. The first run is the baseline, so everything reads as new and no change is charged for.

## `monitorKey` (type: `string`):

Names the history that change tracking compares against. Keep it the same across runs to keep watching the same dealers, or use a different name to track a second, separate watchlist on the same account.

## `maxPagesPerDealer` (type: `integer`):

Safety cap on how deep to page through each dealer's search results. Paging stops early on its own as soon as a page returns no new vehicles.

## `concurrency` (type: `integer`):

How many dealer websites to read at the same time. Raise it for long lists; lower it if sites start refusing requests.

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

Optional. Defaults to Apify Proxy residential with a US exit, which is what these US sites require: a non-US address is refused with HTTP 403. Change it only if you know you need a different proxy or country.

## Actor input object example

```json
{
  "dealerUrls": [
    "https://www.toyotaofdowntownla.com",
    "https://www.mbofsmithtown.com"
  ],
  "condition": "all",
  "maxVehiclesPerDealer": 200,
  "fetchDetails": false,
  "trackChanges": false,
  "monitorKey": "dealer-inventory",
  "maxPagesPerDealer": 20,
  "concurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `inventory` (type: `string`):

Every vehicle found, with VIN, price, mileage, trim, the dealer it belongs to and whether it is new, cheaper, dearer or gone since the last run.

# 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 = {
    "dealerUrls": [
        "https://www.toyotaofdowntownla.com",
        "https://www.mbofsmithtown.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fayoussef/dealer-inventory-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 = { "dealerUrls": [
        "https://www.toyotaofdowntownla.com",
        "https://www.mbofsmithtown.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fayoussef/dealer-inventory-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 '{
  "dealerUrls": [
    "https://www.toyotaofdowntownla.com",
    "https://www.mbofsmithtown.com"
  ]
}' |
apify call fayoussef/dealer-inventory-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fayoussef/dealer-inventory-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/VtZ780MMpRSRasvqT/builds/xDdxLLjcaiVQXVym3/openapi.json
