# Vehicle Safety Report by VIN: Recalls, Complaints, NCAP (`accountable_eel/vehicle-safety-report-lookup`) Actor

VIN recall lookup and vin safety report from official NHTSA data. One VIN in, one row out: decoded make, model and year, every recall campaign with its remedy, vehicle complaint history by VIN with a recent sample, and the NCAP safety rating by VIN. No API key. A VIN that fails to decode is free.

- **URL**: https://apify.com/accountable\_eel/vehicle-safety-report-lookup.md
- **Developed by:** [Adrian Voss](https://apify.com/accountable_eel) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 vin decodeds

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?

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

## Vehicle Safety Report by VIN: Recalls, Complaints and NCAP Crash Ratings

One VIN in, one row out: what the US government knows about that vehicle's safety record. The VIN
is decoded with NHTSA's official vPIC database, and the resulting make, model and year are checked
against NHTSA's recall campaigns, its owner-complaint database, and its NCAP 5-star crash-test
programme. No API key, no account, no proxy.

### Who it's for

- **Used-car buyers and marketplaces** who need to know, before money changes hands, whether a car
  has an unrepaired recall on it, how often its model year has been complained about, and how it
  scored in a crash test.
- **Dealers and wholesalers** running a VIN list through a check before they list or bid on it.
- **Fleet and insurance teams** sweeping a whole fleet's VINs for a new do-not-drive recall.
- **Anyone already using a VIN decoder** who found that a decode alone answers the easy half of the
  question. The specs are on the window sticker; the recall history is not.

### What you get

One flat row per VIN, never a nested blob you have to unpack:

| What | Columns |
| --- | --- |
| The vehicle | `vin`, `make`, `model`, `modelYear`, `manufacturer`, `vehicleType`, `bodyClass` |
| Recalls | `recallCount`, `recalls` (every campaign in full), `recallStatus` |
| Owner complaints | `complaintCount` (NHTSA's own total), `sampledComplaints`, `complaintStatus` |
| Crash-test ratings | `ncapOverallRating`, `ncapFrontCrashRating`, `ncapSideCrashRating`, `ncapRolloverRating`, `ncapVehicleId`, `ncapVehicleDescription`, `ncapModelMatched`, `ncapVariantsFound`, `safetyRatingStatus` |
| Honest gaps | `investigationsNote`, `sourcesChecked`, `sourcesFound` |

`recalls` is the full list, not a sample: each entry carries the NHTSA campaign number, the affected
component, NHTSA's own summary, consequence and remedy text, the date the report was received, and
the two do-not-drive flags (`parkItAway`, `parkOutside`).

`sampledComplaints` **is** a sample, and says so. A single common model year can carry thousands of
complaints (a 2003 Honda Accord has 2,013 of them), so the row returns the most recently filed ones,
newest first, capped at the number you choose. `complaintCount` is always NHTSA's own total for the
vehicle, never the size of that sample.

### What this is not

**This is not a Carfax-style vehicle history report.** It carries no odometer readings, no accident
records, no title status, no branded-title or salvage check, no ownership or registration history,
and no service records. Those come from state DMV records and commercial data suppliers, and this
actor has no access to any of them. If that is what you need, buy a report from a provider licensed
to sell one.

What this actor gives you is the other thing: **official US federal safety data, free at source, for
the vehicle as a model** — recalls, owner complaints and crash-test ratings, keyed by the make,
model and year your VIN decodes to.

**Investigations are deliberately not included.** NHTSA's Office of Defects Investigation publishes
its open investigations only as a bulk flat file, not as a live route anything can query per
vehicle. Rather than ship an always-empty `investigations: []` that would read as "this vehicle has
none", every row carries a short `investigationsNote` saying plainly that they are not covered here.

### The four NHTSA sources

The VIN decode comes first and is not optional: NHTSA's recall, complaint and crash-test routes are
all keyed by **make, model and model year**, never by VIN. The decode is what produces them.

1. **vPIC VIN decode** — resolves the VIN to a make, model, year, manufacturer, vehicle type and
   body style. If a VIN does not decode cleanly, it is a genuine miss: the other three sources have
   nothing to be looked up with, so they are never called and nothing is charged.
2. **Recall campaigns** — every NHTSA recall covering that make, model and year.
3. **Owner complaints** — the total NHTSA holds, plus your sample of the most recent ones.
4. **NCAP crash-test ratings** — the 5-star overall, frontal, side and rollover ratings.

Each of the last three is independent. One of them failing or returning nothing never fails the row
and never affects the other two, and each one's own `*Status` column says exactly what happened.

#### A real subtlety in the crash-test data

NHTSA's crash-test catalogue does not use the same model names as its VIN decoder. A 2013 Ford
F-150 decodes as model `F-150`, but NHTSA's crash-test programme lists that year's trucks as
`F-150 REGULAR CAB`, `F-150 SUPER CREW` and `F-150 SUPERCAB`. A lookup that insisted on an exact
name would report "no crash-test data" for a vehicle NHTSA plainly tested. So this actor tries the
exact name first, and only if that comes back empty does it consult the catalogue for that year and
make and match on the body-style-qualified names. The entry it actually used is reported as
`ncapModelMatched`, so a star rating never arrives without its provenance.

NHTSA also often holds **several separately tested variants** for one make, model and year: 2-door
versus 4-door, side-airbag versus not, rear-wheel drive versus all-wheel drive. A 2003 Honda Accord
has four. **This actor reports the first, and never averages them** — averaging a 4-star coupe with
a 5-star sedan would invent a rating NHTSA never gave to any car. `ncapVariantsFound` tells you how
many exist and `ncapVehicleDescription` tells you which one the stars on your row belong to, so you
can look the others up when the difference matters.

### What a run costs, and how to control it

Billing is per source that answered, never one flat fee per VIN:

- A VIN that **does not decode** costs nothing at all. Nothing else was even looked up.
- A VIN that decodes charges the decode, plus one event for each of the other three sources that
  answered.
- **Zero is an answer and it is charged.** A vehicle with no recalls on record, no complaints on
  record, or no crash test on record has been checked, and the clean result is the thing you were
  asking for. Only a source that genuinely failed to respond, or one you switched off, is free.

The three **Include** checkboxes are the real cost control. Unticking "Include owner complaints"
means the complaint route is never called and never billed for any VIN in the run. Hiding a column
under "Which columns do you want?" is presentation only and does not change what a run costs; the
input says so rather than implying a saving that is not there.

### How to use Vehicle Safety Report by VIN

1. **In the Apify Console.** Open the actor page and click **Start** — the `vins` field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
2. **Via the API.** Call it directly with a POST request — no Console needed once you have an API token:
   ```bash
   curl "https://api.apify.com/v2/acts/accountable_eel~vehicle-safety-report-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"vins":["1HGCM82633A004352","1FTFW1ET9DFC10312"]}'
   ```
3. **On a schedule.** Save this actor as an Apify **Task** with the input you want, then add a **Schedule** (hourly, daily, weekly) so it runs on its own — no server of your own required.

### Input

```json
{
  "vins": [
    "1HGCM82633A004352",
    "1FTFW1ET9DFC10312"
  ]
}
```

One 17-character VIN per line. Each VIN is decoded with NHTSA's official vPIC database, then its make, model and year are checked against NHTSA's recall, owner-complaint and NCAP crash-test records, and the whole safety record comes back as ONE row. Accepted formats: 1HGCM82633A004352, 1FTFW1ET9DFC10312.

### Output

One row per VIN, for example:

| query | found | status | vin | make | model | modelYear | manufacturer | vehicleType | bodyClass | recallCount | recalls | recallStatus | complaintCount | sampledComplaints | complaintStatus | ncapOverallRating | ncapFrontCrashRating | ncapSideCrashRating | ncapRolloverRating | ncapVehicleId | ncapVehicleDescription | ncapModelMatched | ncapVariantsFound | safetyRatingStatus | sourcesChecked | sourcesFound | scrapedAt |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 1HGCM82633A004352 | True | OK | 1HGCM82633A004352 | HONDA | Accord | 2003 | AMERICAN HONDA MOTOR CO., INC. | PASSENGER CAR | Coupe | 24 | \[{"campaignNumber": "19V182000", "component": "AIR BAGS:FRONTAL:DRIVER SIDE:INFLATOR MODULE", "summary": "Honda (American Honda Motor Co.) is recalling specific 2003 Acura 3.2CL, 2013-2016 ILX, 201... | OK | 2013 | \[{"odiNumber": 11746949, "components": "AIR BAGS", "crash": true, "fire": false, "summary": "The vehicle was rear-ended on I-5 in Seattle Washington.  The impact drove the subject car into the car ... | OK | Not Rated | Not Rated | Not Rated | Not Rated | 4739 | 2003 Honda Accord 2-DR. w/SAB | Accord | 4 | OK | 4 | 4 | 2026-09-30T23:50:58.457Z |
| 1FTFW1ET9DFC10312 | True | OK | 1FTFW1ET9DFC10312 | FORD | F-150 | 2013 | FORD MOTOR COMPANY | TRUCK | Pickup | 3 | \[{"campaignNumber": "19V075000", "component": "POWER TRAIN:AUTOMATIC TRANSMISSION:CONTROL MODULE (TCM/PCM/TECM)", "summary": "Ford Motor Company (Ford) is recalling certain 2011-2013 F-150 vehicles... | OK |  |  | REQUEST\_FAILED | 4 | 4 | 5 | 3 | 7340 | 2013 Ford F-150 Regular Cab PU/RC 4x4 | F-150 REGULAR CAB | 2 | OK | 4 | 3 | 2026-09-30T23:50:58.507Z |

A VIN that does not decode comes back as a row with `"found": false`, a `message` carrying NHTSA's
own reason (most often that the check digit in the 9th position does not compute), and no charge.

### Example runs

Three inputs that need no credentials of any kind and return rows as they stand. Paste one into the
Input tab and press Start.

**1. The full safety record for two vehicles**

```json
{
  "vins": ["1HGCM82633A004352", "1FTFW1ET9DFC10312"]
}
```

**2. Recalls only, for a fleet sweep**

```json
{
  "vins": ["1HGCM82633A004352", "1FTFW1ET9DFC10312"],
  "includeComplaints": false,
  "includeSafetyRatings": false
}
```

**3. Deep complaint history for one vehicle**

```json
{
  "vins": ["1HGCM82633A004352"],
  "includeRecalls": false,
  "includeSafetyRatings": false,
  "maxComplaints": 100
}
```

### Pricing

Pay-per-event, one event per source that answered. A VIN that does not decode charges nothing
at all, and a source that fails to respond is free. Live per-event prices are shown on the actor
page's pricing panel, which is always the authority.

Concretely: a VIN that decodes and gets answers from all three other sources is billed four events.
A VIN you ran with complaints switched off is billed three. A VIN that does not decode is billed
nothing.

### Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

```bash
curl "https://api.apify.com/v2/acts/accountable_eel~vehicle-safety-report-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"vins":["1HGCM82633A004352","1FTFW1ET9DFC10312"]}'
```

**n8n.** Add an HTTP Request node: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~vehicle-safety-report-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body Content Type `JSON`, JSON Body `{"vins":["1HGCM82633A004352","1FTFW1ET9DFC10312"]}` (swap in an expression from an earlier node for a real value).

**Clay.** Add an "HTTP API" column: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~vehicle-safety-report-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body `{"vins":["{{VIN}}"]}`, mapping the row's VIN into the `vins` array.

**MCP.** In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "vin safety report: recalls complaints ncap rating" — the agent will find and run this actor.

### vs. the alternatives

| | This actor | A plain VIN decoder | A paid vehicle history report |
| --- | --- | --- | --- |
| Decoded make, model, year, body style | Yes | Yes | Yes |
| Recall campaigns with remedy text | Yes | No | Yes |
| Owner complaint history | Yes | No | Rarely |
| NCAP crash-test star ratings | Yes | No | Sometimes |
| Accident, odometer and title history | **No** | No | Yes |
| Cost per VIN | Cents | Cents | Dollars |
| API key needed | No | Usually no | Yes, and a licence |

The honest summary: if you want to know whether a specific car was crashed and what its odometer
said at each owner change, this is not that product. If you want to know whether the model is
subject to an unrepaired recall, what owners keep reporting about it, and how it scored in a crash
test, this returns all three in one row for a fraction of a cent.

### Limits, stated plainly

- **Recalls, complaints and ratings are per make/model/year, not per individual car.** NHTSA's own
  APIs work that way. A recall campaign covering your model year covers your VIN only if your VIN
  falls in the affected range, and this data cannot tell you whether *your* car's recall was already
  repaired. For that, use NHTSA's own VIN-level recall page or a dealer.
- **US vehicles only.** NHTSA is a US federal agency, and its records cover vehicles sold in the US
  market. A VIN for a car never sold in the US may decode and still have nothing behind it.
- **A VIN with a bad check digit is rejected.** vPIC returns a make and model for many invalid VINs
  while flagging the check digit as wrong; those are treated as misses, not as vehicles, and are
  never charged. Most invented or mistyped VINs fail this way.
- **Crash-test ratings are reported for the first tested variant**, not averaged. See the subtlety
  above.
- **"Not Rated" is NHTSA's wording, not a missing value.** It means NHTSA tested the vehicle in some
  categories but did not issue a rating in that one, and it is passed through verbatim.
- **Investigations are not included**, for the reason given above.

### Data & privacy

Everything this actor returns is public US federal government data, published by the National
Highway Traffic Safety Administration and free at source. It reads nothing that is not already
public, holds no personal data about vehicle owners, and does not look up registration, insurance or
ownership records, which are not available to it.

One thing worth knowing: NHTSA's owner-complaint records sometimes include a **partial VIN** and a
free-text narrative written by the complainant, which may mention a location or a dealer by name.
Those fields come through as NHTSA published them. If you are redistributing rows, treat the
complaint summaries as third-party text rather than as your own.

### FAQ

**Will this tell me if a recall on my car was already fixed?**
No. NHTSA's per-VIN recall-completion lookup is a separate, VIN-level service. This actor works at
the make/model/year level, which tells you which campaigns *could* apply.

**Why does a car with 2,013 complaints only show 20 of them?**
Because a dump of 2,013 complaint narratives in a spreadsheet cell is not a usable answer.
`complaintCount` always reports the real total; raise "Complaints to sample per VIN" up to 100 if
you need a deeper sample.

**Why is `ncapOverallRating` "Not Rated" on a car that clearly has star ratings?**
NHTSA issues an overall rating only when it has run the full test battery. Older vehicles often have
frontal and side ratings but no overall score. The individual ratings on the same row are the real
answer for those.

**Why does the model on my crash-test row not match the model in the decode?**
Because NHTSA's crash-test catalogue uses body-style-qualified names. `ncapModelMatched` shows the
catalogue entry used; see the subtlety section above.

**Do I need a proxy?**
No. All four routes are free, unauthenticated US government APIs that answer a plain request.

**What happens to a VIN that isn't 17 characters?**
It is passed to NHTSA as given. vPIC attempts a partial decode and reports what it can; if the
result is not a clean decode, the row is a free miss carrying NHTSA's own explanation.

### Related actors

- **NHTSA VIN Decoder** — the decode on its own, when the specs are all you need.
- **AutoScout24 Listing Lookup** and **Otomoto Listing Lookup** — the listing side of a used-car
  check, for the European marketplaces.

# Actor input Schema

## `vins` (type: `array`):

One 17-character VIN per line. Each VIN is decoded with NHTSA's official vPIC database, then its make, model and year are checked against NHTSA's recall, owner-complaint and NCAP crash-test records, and the whole safety record comes back as ONE row. Accepted formats: 1HGCM82633A004352, 1FTFW1ET9DFC10312. You're only charged for the ones we actually find — a miss costs nothing.

## `testRun` (type: `boolean`):

Turn this on to test your input on a small sample before running the full list. Turn it off to process everything.

## `onlyFound` (type: `boolean`):

Only keep rows where something was actually found. Misses are always free, whether or not you show them here.

## `includeKeywords` (type: `array`):

Optional. Only keep results that mention at least one of these words (e.g. a job title, a city, a product name). Leave empty to keep everything.

## `excludeKeywords` (type: `array`):

Optional. Drop any result that mentions one of these words. Leave empty to skip nothing.

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

Optional. Stop the run once this many results have been found — useful for a quick, cheap sample. Leave blank for no limit.

## `includeRecalls` (type: `boolean`):

Check NHTSA's recall database for this vehicle and return every campaign in full, with its component, consequence, remedy and do-not-drive flags. Turn this off to skip the recall check entirely, which also means you are not billed for it.

## `includeComplaints` (type: `boolean`):

Check NHTSA's owner-complaint database and return the total count plus a sample of the most recent ones. Turn this off to skip the complaint check entirely, which also means you are not billed for it.

## `includeSafetyRatings` (type: `boolean`):

Look this vehicle up in NHTSA's 5-star crash-test programme and return the overall, frontal, side and rollover star ratings. Turn this off to skip the crash-test lookup entirely, which also means you are not billed for it.

## `maxComplaints` (type: `integer`):

How many of the most recently filed complaints to return in full. The total count is always NHTSA's own, however small this sample is, because a common model can have thousands and a full dump of them is not a readable answer. Changing this does not change what a run costs.

## `columns` (type: `array`):

Choose which pieces of information to include in each result row. All are included by default.

## `maxConcurrency` (type: `integer`):

Parallel requests. Keep conservative — this target has no browser fallback, so getting blocked costs more than slow-and-steady.

## Actor input object example

```json
{
  "vins": [
    "1HGCM82633A004352",
    "1FTFW1ET9DFC10312"
  ],
  "testRun": false,
  "onlyFound": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "includeRecalls": true,
  "includeComplaints": true,
  "includeSafetyRatings": true,
  "maxComplaints": 20,
  "columns": [
    "vin",
    "make",
    "model",
    "modelYear",
    "manufacturer",
    "vehicleType",
    "bodyClass",
    "recallCount",
    "recalls",
    "recallStatus",
    "complaintCount",
    "sampledComplaints",
    "complaintStatus",
    "ncapOverallRating",
    "ncapFrontCrashRating",
    "ncapSideCrashRating",
    "ncapRolloverRating",
    "ncapVehicleId",
    "ncapVehicleDescription",
    "ncapModelMatched",
    "ncapVariantsFound",
    "safetyRatingStatus",
    "vinDecodeStatus",
    "investigationsNote",
    "sourcesChecked",
    "sourcesFound"
  ],
  "maxConcurrency": 3
}
```

# Actor output Schema

## `results` (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 = {
    "vins": [
        "1HGCM82633A004352",
        "1FTFW1ET9DFC10312"
    ],
    "includeKeywords": [],
    "excludeKeywords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("accountable_eel/vehicle-safety-report-lookup").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 = {
    "vins": [
        "1HGCM82633A004352",
        "1FTFW1ET9DFC10312",
    ],
    "includeKeywords": [],
    "excludeKeywords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("accountable_eel/vehicle-safety-report-lookup").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 '{
  "vins": [
    "1HGCM82633A004352",
    "1FTFW1ET9DFC10312"
  ],
  "includeKeywords": [],
  "excludeKeywords": []
}' |
apify call accountable_eel/vehicle-safety-report-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,accountable_eel/vehicle-safety-report-lookup"
        }
    }
}
```

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/yZ6TQZ87lAbJg9YIa/builds/P2AXst6eLildbigfR/openapi.json
