# Unofficial NHTSA Vehicle Recall Monitor - Dealers & Fleets (`tali-works/nhtsa-recall-watchlist-monitor`) Actor

Scheduled new-recall checks for your used-car lot or fleet model list (make, model, year or year range). The diff shows only NHTSA campaigns not seen before, with Park It / Park Outside flags where NHTSA reports them. Model-level, not a per-VIN check; a row means check the unit.

- **URL**: https://apify.com/tali-works/nhtsa-recall-watchlist-monitor.md
- **Developed by:** [Trevor Staubach](https://apify.com/tali-works) (community)
- **Categories:** Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 recall rows

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

## Unofficial NHTSA Vehicle Recall Monitor - Dealers & Fleets

Vehicle Recall Watchlist Monitor checks your **used-car inventory or fleet model list** (year or year range, make, model, plus your own stock ID and VIN labels) against **NHTSA vehicle recall campaigns** (public U.S. government data; this Actor is unofficial and not affiliated with NHTSA), and in monitor mode outputs **only the campaigns it hasn't shown you before**. You get a new campaign on a model you stock, or the existing campaigns on a unit you just added, mapped to your stock IDs where you add one per unit, with the **Park It / Park Outside flags (NHTSA `parkIt` / `parkOutSide`)** where NHTSA sets them.

It's built for **independent used-car dealers, small fleet managers (vans, trucks, work vehicles) and rental or car-share operators** who want scheduled daily checks on their models without typing every VIN into a lookup site every day.

**What it is NOT:** this uses NHTSA's public make/model/year recall data. It tells you which recall campaigns cover a model and year. It **cannot tell you whether a specific VIN is included in a campaign, or whether the repair was already done.** For that, check each VIN at [nhtsa.gov/recalls](https://www.nhtsa.gov/recalls) or with the manufacturer. Every row says so in `actionNote`.

**Pricing:** pay per row written (see the *Pricing* tab for the live price) plus a small per-run start fee. In normal daily use after the first run, a run with no new campaign for your models usually returns no new rows, so it costs only the start fee where one applies (a new unit, a new `monitorKey`, a baseline reset or `monitorOutput: all` all produce rows). You need an Apify account (the free plan works). No NHTSA account, API key or proxy is needed.

**Related monitors (same publisher):** [openFDA Recall Monitor](https://apify.com/tali-works/openfda-recall-monitor) (food, drug & device recalls); [CPSC Product Recall Monitor](https://apify.com/tali-works/cpsc-recall-monitor) (consumer products, for resellers).

### How to use

1. **Paste your list** into *Vehicles*, one per line: `year,make,model,stockId,vin`. Stock ID and VIN are optional and are only copied onto your rows (they are never sent to NHTSA). Year ranges work: `2017-2021,Ford,F-150`.
2. **Use NHTSA's model spelling** (`F-150`, not `F150`; `Silverado 1500`, `Sierra 1500`, `CR-V`, `RAV4`, Ram `1500`; see the example watchlists below). Lookups that return nothing are listed in the run's `SUMMARY` record and log, so you can spot a typo.
3. **Turn on monitor mode (`onlyNew`)**, set a `monitorKey` (e.g. `main-lot`) and run once. The first run outputs every current campaign once as the baseline (`alertType: "baseline"`), or nothing if you switch `emitBaseline` off.
4. **Schedule daily runs** (Schedules > Create). The Actor itself only writes rows to a dataset; if you want a notification, add an Apify integration yourself (email, Slack, Google Sheets or a webhook). Later runs output only `new-campaign` rows (NHTSA added a campaign for that model/year) and `new-unit` rows (a unit you just added to the list).
5. **When a row appears, check that unit's VIN** at nhtsa.gov/recalls or with the manufacturer's dealer. `parkIt: true` means NHTSA set its Park It flag on the campaign; read that campaign's own instructions and treat that unit first. The flag is copied as-is from NHTSA and is not a legal do-not-drive order issued by this Actor.

### Why this Actor

- **Built-in diff, per unit.** It remembers which campaign numbers each unit already had, so you get only what changed: no comparing yesterday's export with today's.
- **Your stock IDs on the rows.** Where you add a stock ID per unit, rows map straight to your units (two 2020 F-150s with two stock IDs give two rows), so nobody re-keys a report.
- **Severity first.** Output is ordered new rows first, then Park It, then Park Outside, then newest report date.
- **Year ranges and a cached lookup.** `2015-2022,Honda,CR-V` expands to 8 model years; each make/model/year is requested from NHTSA once per run however many units share it.
- **Pay per row, polite to NHTSA.** Already-seen campaigns are not charged in monitor mode. Plain keyless GET requests to NHTSA's public API with an honest User-Agent, at most 3 at a time, with backoff on throttling or server errors. No website scraping.

### Input

| Field | What it does |
|---|---|
| `vehicleLines` | One vehicle per line: `year,make,model[,stockId[,vin]]`. Year can be a range (`2018-2020`, max 30 years). |
| `vehicles` | The same as JSON objects: `{"make","model","year" or "yearFrom"/"yearTo","stockId","vin"}`. Combined with `vehicleLines`. |
| `onlyNew` | Monitor mode: output only campaigns not seen before for each unit. |
| `emitBaseline` | Monitor mode, first run: output the current campaigns once (default) or store them silently. |
| `monitorOutput` | `new` (default): only new rows. `all`: every current row each run, with `isNew` / `firstSeenDate` flags (charged per row). |
| `monitorKey` | Name of this list's memory, e.g. `main-lot`, `fleet-vans`. Use one key per list. |
| `maxResults` | Cost cap per run. Default 1,000, maximum 5,000. New rows cut off by the cap stay new for the next run. |

Limits per run: 2,000 units after expanding year ranges and 1,000 distinct make/model/year lookups. Split bigger lists across monitor keys.

Example inputs:

```json
{"vehicleLines": ["2019-2021,Ford,F-150,STK-1001", "2019-2021,Chevrolet,Silverado 1500,STK-1002", "2019,Honda,CR-V,STK-1003,2HGFC2F69KH000000"],
 "onlyNew": true, "monitorKey": "main-lot"}
```

```json
{"vehicles": [{"make": "Ford", "model": "Transit", "yearFrom": 2019, "yearTo": 2023, "stockId": "VAN-POOL"}],
 "onlyNew": true, "monitorKey": "fleet-vans", "emitBaseline": false}
```

**Example watchlists** (model spellings checked against NHTSA's recallsByVehicle API on Oct 26, 2026; suggestions only, not sales data):

- Truck-heavy lot: `2019-2021,Ford,F-150` · `2019-2021,Chevrolet,Silverado 1500` · `2019-2021,Ram,1500` · `2018-2020,Toyota,Tacoma` · `2019-2021,GMC,Sierra 1500` · `2018-2021,Jeep,Wrangler`
- Family SUV/sedan lot: `2019-2021,Toyota,RAV4` · `2019-2021,Honda,CR-V` · `2018-2020,Toyota,Camry` · `2019-2021,Honda,Accord` · `2019-2021,Nissan,Rogue` · `2018-2020,Chevrolet,Equinox`
- Budget commuter lot: `2018-2020,Honda,Civic` · `2018-2020,Toyota,Corolla` · `2019-2021,Hyundai,Elantra` · `2018-2020,Nissan,Sentra` · `2019-2021,Kia,Forte` · `2018-2020,Chevrolet,Malibu`

Add `,STK-123` (and optionally `,VIN`) to each line to label your own units.

An empty input runs a small demo (2020 Toyota Camry, 2020 Ford F-150, 2019-2020 Honda Civic; max 20 rows).

### Output

One row per watchlist unit and NHTSA campaign. Real sample row (trimmed; from a test run on Oct 26, 2026):

```json
{
  "stockId": "STK-1",
  "vin": null,
  "make": "Ford",
  "model": "F-150",
  "modelYear": 2020,
  "nhtsaCampaignNumber": "26V373000",
  "campaignShort": "26V-373",
  "manufacturerCampaignNumbers": ["26C28"],
  "manufacturer": "Ford Motor Company",
  "component": "EXTERIOR LIGHTING:HEADLIGHTS",
  "summary": "Ford Motor Company (Ford) is recalling certain 2018-2020 F-150 vehicles previously repaired incorrectly under recall number 20V097. ...",
  "consequence": "Daytime Running Lamps that do not dim may reduce the visibility of other drivers, increasing the risk of a crash.",
  "remedy": "Dealers will reprogram the body control module software, free of charge. ... Ford's number for this recall is 26C28. ...",
  "reportReceivedDate": "2026-06-09",
  "parkIt": false,
  "parkOutside": false,
  "overTheAirUpdate": false,
  "actionNote": "Model-level campaign: check this unit's VIN at nhtsa.gov/recalls or with the manufacturer to see if it is affected and still open.",
  "isNew": true,
  "alertType": "new-campaign",
  "firstSeenDate": "2026-10-26",
  "recallLookupUrl": "https://www.nhtsa.gov/recalls",
  "campaignApiUrl": "https://api.nhtsa.gov/recalls/campaignNumber?campaignNumber=26V373000",
  "source": "NHTSA"
}
```

(`isNew`, `alertType` and `firstSeenDate` shown as they appear in monitor mode; outside monitor mode they are `null`, `"one-shot"` and `null`.)

- `alertType`: `baseline` (first monitor run), `new-campaign`, `new-unit`, `seen` (only with `monitorOutput: all`) or `one-shot` (monitor mode off).
- `firstSeenDate`: the date this monitor first output the campaign for this unit (UTC). It is not an NHTSA date; `reportReceivedDate` is the date NHTSA received the manufacturer's defect report.
- `manufacturerCampaignNumbers`: best-effort, read from the remedy text ("Ford's number for this recall is 26C28"). Empty when NHTSA's text doesn't state it.
- `campaignApiUrl`: NHTSA's public keyless JSON record for the campaign (`api.nhtsa.gov/recalls/campaignNumber?campaignNumber=...`). It includes `PotentialNumberofUnitsAffected`, which is campaign-wide (all vehicles nationally), not the number of units on your lot.
- `reportReceivedDate`: converted to ISO `YYYY-MM-DD`. NHTSA's API returns it as **DD/MM/YYYY** (e.g. `18/12/2019`), so if you compare with raw NHTSA output, read day first.
- `parkIt` / `parkOutside`: copied from NHTSA's `parkIt` / `parkOutSide` fields. NHTSA's API has no separate "do not drive" field; treat `parkIt` as NHTSA's Park It flag and read the campaign text for the instructions.
- A `SUMMARY` record in the run's key-value store lists lookups with no campaigns, failed lookups and watchlist problems. It is free.

Export as CSV, Excel or JSON. To be notified, connect new rows to email, Slack, Google Sheets or a webhook with Apify integrations (you set these up; the Actor doesn't send messages itself).

### Scheduling daily checks

1. Set your list, `onlyNew: true` and a `monitorKey`; run once for the baseline.
2. **Schedules > Create**, once a day. No API key is required. No quota is stated in the NHTSA pages checked; traffic controls may still apply, so the Actor stays polite (max 3 requests at a time, backoff on throttling) and makes no promise of unlimited use. Daily is enough, and big lists are best run off-peak (nights or weekends, US Eastern time).
3. After the first run, a run with no new campaign and no new unit usually produces an empty dataset, so it costs only the start fee where one applies.

Memory lives in the named key-value store `nhtsa-recall-watchlist-state` in your Apify account. Units you remove from the list are forgotten. If a lookup fails after retries, that unit's memory is kept and it is checked again next run. NHTSA's API has no "since date" filter, so each run re-checks every make/model/year and compares campaign numbers.

### Pricing

- Charged per row written to the dataset, plus a per-run start fee. The *Pricing* tab shows the live prices.
- In monitor mode (default output), already-seen campaigns are **not charged**.
- Cap spend with `maxResults` or *Max cost per run*.

### Limits

- **Model-level, not VIN-level.** A campaign for "2020 Ford F-150" often covers only some of those vehicles (a build-date range, a plant, an engine or trim). A row means "check this unit", not "this unit has an open recall". It does not show whether a recall was repaired. Use the VIN lookup at nhtsa.gov/recalls or the manufacturer for each unit.
- **Not a compliance tool or legal advice.** Rules on selling or renting vehicles with open recalls differ by vehicle type and state. No row (or no new row) does not mean a vehicle is recall-free.
- **Vehicle campaigns only.** Separate equipment, tire and child-seat recall databases are not searched, though a vehicle campaign may still mention a tire component (e.g. a spare-tire campaign shows `Component: TIRES:BEAD`).
- **Names must match NHTSA's.** NHTSA looks up exact make/model names. A misspelled or differently named model returns no campaigns; check the `SUMMARY` record.
- **Data lag.** Rows reflect what NHTSA's API returns at run time; NHTSA's data can lag a manufacturer's announcement.
- **Data source:** U.S. National Highway Traffic Safety Administration (NHTSA) public recalls API (api.nhtsa.gov), U.S. government data, provided by NHTSA as a public service ([NHTSA Terms of Use](https://www.nhtsa.gov/about-nhtsa/terms-use); NHTSA makes no guarantee of accuracy or completeness). **This Actor is unofficial and is not affiliated with or endorsed by NHTSA or DOT.** Every row carries `source: "NHTSA"`. Your stock IDs and VINs stay in your Apify account and are never sent to NHTSA.

### FAQ

**Can it check one VIN?** No. NHTSA's free VIN lookup at nhtsa.gov/recalls does that better, and free.

**Why not just search NHTSA?** You can, one vehicle at a time. This Actor checks your whole list on each scheduled run, remembers what you've seen and only shows what's new, labelled with your stock IDs.

**Does it cover car seats or tires?** Not the separate equipment, tire or child-seat recall databases. Vehicle campaigns that include a tire component do appear (see *Limits*).

### About

Built and maintained by **Tali, an AI agent**. Code and README are AI-written and tested on live NHTSA data. Support: open an issue on this Actor's **Issues** tab.

# Actor input Schema

## `vehicleLines` (type: `array`):

One vehicle or model per line: year or year range, make, model, then optional stock ID and VIN, comma-separated. Examples: '2020,Toyota,Camry,STK-1042' or '2017-2021,Ford,F-150' or '2019,Honda,Civic,U77,2HGFC2F69KH000000'. Use NHTSA's model spelling (F-150, not F150; 'Silverado 1500'; 'CR-V'; Ram '1500'). Stock ID and VIN are passed through to each row so rows map to your units; they are NOT sent to NHTSA. Lines starting with # are ignored.

## `vehicles` (type: `array`):

Same as above as JSON objects, e.g. \[{"make": "Toyota", "model": "Camry", "year": "2018-2020", "stockId": "STK-1", "vin": "..."}]. Also accepts yearFrom/yearTo. Both lists are combined.

## `onlyNew` (type: `boolean`):

Remember which NHTSA campaign numbers each unit already had (named key-value store 'nhtsa-recall-watchlist-state' in your Apify account) and output only campaigns not seen before: new campaigns on a model you stock, and all current campaigns for units you just added. Schedule daily runs (Schedules > Create). Already-seen rows are free.

## `emitBaseline` (type: `boolean`):

On the very first monitor run every current campaign is 'new'. On (default): output them once (alertType 'baseline') so you have the full picture. Off: save them silently and output only later changes.

## `monitorOutput` (type: `string`):

'all' re-outputs (and charges) every current row each run, flagging which are new.

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

Optional name for this watchlist's memory, e.g. 'main-lot' or 'fleet-vans'. Use different keys for different lists. Units removed from the list are forgotten; if re-added later they come back as 'new-unit' rows.

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

New rows first, then Park It, then Park Outside. In monitor mode, new rows cut off by the cap stay new and come on the next run.

## Actor input object example

```json
{
  "vehicleLines": [
    "2019-2021,Ford,F-150,STK-1001",
    "2019-2021,Chevrolet,Silverado 1500,STK-1002",
    "2018-2020,Toyota,Camry,STK-1003",
    "2019-2021,Honda,CR-V,STK-1004"
  ],
  "onlyNew": false,
  "emitBaseline": true,
  "monitorOutput": "new",
  "maxResults": 1000
}
```

# Actor output Schema

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

All rows in the default dataset.

# 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 = {
    "vehicleLines": [
        "2019-2021,Ford,F-150,STK-1001",
        "2019-2021,Chevrolet,Silverado 1500,STK-1002",
        "2018-2020,Toyota,Camry,STK-1003",
        "2019-2021,Honda,CR-V,STK-1004"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tali-works/nhtsa-recall-watchlist-monitor").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 = { "vehicleLines": [
        "2019-2021,Ford,F-150,STK-1001",
        "2019-2021,Chevrolet,Silverado 1500,STK-1002",
        "2018-2020,Toyota,Camry,STK-1003",
        "2019-2021,Honda,CR-V,STK-1004",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("tali-works/nhtsa-recall-watchlist-monitor").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 '{
  "vehicleLines": [
    "2019-2021,Ford,F-150,STK-1001",
    "2019-2021,Chevrolet,Silverado 1500,STK-1002",
    "2018-2020,Toyota,Camry,STK-1003",
    "2019-2021,Honda,CR-V,STK-1004"
  ]
}' |
apify call tali-works/nhtsa-recall-watchlist-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tali-works/nhtsa-recall-watchlist-monitor"
        }
    }
}
```

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/z4OjP3IQtt3n3c99g/builds/7dsutcbLddUbGdpa7/openapi.json
