# NHTSA VIN Decoder: Bulk Make, Model, Year & Specs (vPIC) (`fecklesspleb/nhtsa-vin-decoder`) Actor

Decode VINs in bulk with the free NHTSA vPIC API: make, model, model year, trim, body, engine, fuel/EV type, plant and other non-empty vPIC specs. Full VINs or partial VIN patterns, batches of 50, model-year hints, clean/partial/failed status. $0.001 per VIN. Unofficial.

- **URL**: https://apify.com/fecklesspleb/nhtsa-vin-decoder.md
- **Developed by:** [Scott Williams](https://apify.com/fecklesspleb) (community)
- **Categories:** Developer tools, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 decoded vins

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

## VIN Decoder: Bulk NHTSA VIN Lookup for Make, Model, Year and Specs

Decode vehicle identification numbers (VINs) in bulk with the free NHTSA vPIC API (Product Information Catalog), run by the U.S. Department of Transportation. For each VIN you get the make, model, model year, trim and series, plus:

- vehicle type and body class, and doors
- engine: cylinders, litres and horsepower
- fuel type, and the EV or hybrid level
- drive type, transmission, and GVWR class
- the plant where it was built
- every other non-empty vPIC value for that VIN in a `specs` object. Examples are airbag locations, engine model and configuration, valve train, driver-assistance systems, battery, wheelbase and axles, when NHTSA has them. How many depends on the vehicle: in our tests of 8 VINs and VIN patterns, `specCount` was between 5 and 15.

Unofficial. This Actor is not affiliated with or endorsed by NHTSA.

### Licence and privacy

- **Data licence.** NHTSA's terms of use say: "Information presented on this web site is considered public information and may be distributed or copied."
- **Your VINs go to NHTSA.** NHTSA's terms also say that information submitted to the site becomes the property of NHTSA/DOT.
- **No owner data.** The output describes the vehicle *model*. It never contains owner names, addresses, plates or vehicle history.
- **A full VIN can count as personal data** in some places (for example under GDPR) when it can be linked to an owner. Only submit VINs you are allowed to process.
- **The default input is safe.** The sample input uses VIN *patterns* whose serial number is cut off or replaced by `*`, so they never identify a single vehicle.

### Input: VINs and VIN patterns

| Field | Default | Meaning |
|---|---|---|
| `vins` | 6 sample VIN patterns | One VIN per line. Accepts full 17-character VINs, or partial patterns with `*` for unknown positions (8 to 17 characters). Add `,YEAR` to give a model-year hint, for example `5UXWX7C5*BA,2011`. Spaces and dashes are removed. Duplicates are decoded once. Entries with I, O or Q, or with other invalid characters, are rejected and listed in `RUN_SUMMARY`; they are not charged. |
| `modelYear` | none | Model-year hint for every VIN that has no `,YEAR` of its own. |
| `skipUndecoded` | false | When on, VINs that NHTSA cannot decode (no make) are not saved and not charged. |
| `includeSpecs` | true | Adds the `specs` object. |
| `maxItems` | 1000 (max 10,000) | Maximum number of VINs to decode per run. The input list itself can hold up to 20,000 entries; entries beyond `maxItems` are counted in `RUN_SUMMARY` and not decoded or charged. |

With empty input `{}`, the Actor decodes **6 sample VIN patterns** (BMW, Tesla, Honda, Ford, Toyota and Volkswagen) for **$0.006**.

### Output: decoded VIN fields

There is one dataset item per VIN. The fields are:

- `vin` and `isFullVin`.
- `modelYearHint`.
- `decodeStatus`. This is `clean` (NHTSA error code 0), `partial` (decoded with warnings, such as an incomplete VIN or a wrong check digit) or `failed` (no make found).
- `errorCodes`, `errorText`, `additionalErrorText`, `suggestedVin` and `possibleValues`.
- `make`, `makeId`, `model`, `modelId`, `modelYear`, `trim` and `series`.
- `vehicleType`, `bodyClass` and `doors`.
- `manufacturer`, `manufacturerId`, `plantCountry`, `plantState` and `plantCity`.
- `engineCylinders`, `displacementL` and `engineHp`.
- `fuelTypePrimary`, `fuelTypeSecondary`, `electrificationLevel` and `batteryKwh`.
- `driveType`, `transmissionStyle`, `transmissionSpeeds` and `gvwrClass`.
- `specs` and `specCount`.
- `source`, `licenceNote` and `scrapedAt`.

Empty values and vPIC's "Not Applicable" are returned as `null`, or left out of `specs`.

This is a real item from a test run of the default input on 30 October 2026, for the VIN pattern `1HGCM82633A` (the serial number is cut off, hence error 6, "Incomplete VIN"):

```json
{
  "vin": "1HGCM82633A",
  "isFullVin": false,
  "modelYearHint": null,
  "decodeStatus": "partial",
  "errorCodes": [6],
  "errorText": "6 - Incomplete VIN",
  "additionalErrorText": null,
  "suggestedVin": null,
  "possibleValues": null,
  "make": "HONDA",
  "makeId": 474,
  "model": "Accord",
  "modelId": 1861,
  "modelYear": 2003,
  "trim": "EX-V6",
  "series": null,
  "vehicleType": "PASSENGER CAR",
  "bodyClass": "Coupe",
  "doors": 2,
  "manufacturer": "AMERICAN HONDA MOTOR CO., INC.",
  "manufacturerId": 988,
  "plantCountry": "UNITED STATES (USA)",
  "plantState": "OHIO",
  "plantCity": "MARYSVILLE",
  "engineCylinders": 6,
  "displacementL": 2.998832712,
  "engineHp": 240.0,
  "fuelTypePrimary": "Gasoline",
  "fuelTypeSecondary": null,
  "electrificationLevel": null,
  "batteryKwh": null,
  "driveType": null,
  "transmissionStyle": "Automatic",
  "transmissionSpeeds": 5,
  "gvwrClass": "Class 1C: 4,001 - 5,000 lb (1,814 - 2,268 kg)",
  "specs": {
    "AirBagLocCurtain": "1st and 2nd Rows",
    "AirBagLocFront": "1st Row (Driver and Passenger)",
    "AirBagLocSide": "1st Row (Driver and Passenger)",
    "DisplacementCC": "2998.832712",
    "DisplacementCI": "183",
    "EngineConfiguration": "V-Shaped",
    "EngineModel": "J30A4",
    "GVWR_to": "Class 1: 6,000 lb or less (2,722 kg or less)",
    "OtherRestraintSystemInfo": "Seat Belt (Rr center position)",
    "SeatBeltsAll": "Manual",
    "ValveTrainDesign": "Single Overhead Cam (SOHC)",
    "VehicleDescriptor": "1HGCM826*3A"
  },
  "specCount": 12,
  "source": "NHTSA vPIC DecodeVINValuesBatch",
  "licenceNote": "Decoded by the NHTSA vPIC API (U.S. DOT). NHTSA terms of use: \"Information presented on this web site is considered public information and may be distributed or copied.\" Unofficial; not affiliated with or endorsed by NHTSA.",
  "scrapedAt": "2026-10-31T01:33:24+00:00"
}
```

A run summary is saved to the key-value store as `RUN_SUMMARY`. It counts rejected entries, duplicates, entries over `maxItems`, status totals and requests.

### Pricing

Pricing is pay per event: **$0.001 per VIN** in the dataset ($1 per 1,000 VINs), with **no start fee** and no other events.

- Rejected entries and duplicates are never charged.
- VINs that NHTSA could not decode (`decodeStatus: "failed"`) are saved and charged, unless `skipUndecoded` is on. Then they are neither saved nor charged.
- The run stops cleanly at your maximum cost per run.

Example costs:

- `{}`: $0.006.
- 1,000 VINs: $1.00.
- 10,000 VINs (one run's maximum): $10.00.

### Use it from n8n, Make or Zapier

Run the Actor through the Apify API, using Apify's Make, Zapier or n8n integrations or a plain HTTP request to the Apify API. Pass `{"vins": [...]}` and read the dataset items. For example, decode the VINs from a new spreadsheet row or inventory feed, and write make, model, year and trim back. The Apify Console's API tab for this Actor shows the exact endpoint URLs.

### How it works

1. Reads `robots.txt` on vpic.nhtsa.dot.gov. It currently returns 404, which means no rules.
2. Sends VINs to `DecodeVINValuesBatch` with POST, in batches of up to 50 (the documented maximum).
3. Makes one request at a time, at most 1 per second, with a clear User-Agent.
4. On 429 or 5xx, honours `Retry-After` and backs off, up to 5 tries.
5. Stops cleanly on 403 or on any response that is not JSON (vPIC uses automated rate control). It never tries to get around a block.
6. Matches each result to its VIN, by position, or by VIN if the order differs.

### Limits

- **Coverage.** vPIC covers vehicles made for the U.S. market. Other VINs often decode only partially, or show error 7 ("Manufacturer is not registered with NHTSA").
- **Missing values.** NHTSA says a missing value means it has no data, not that the vehicle lacks the feature.
- **No history.** There is no recall, theft, accident or ownership data.
- **Volume.** Up to 10,000 VINs per run.

### FAQ

**Is this the official NHTSA VIN decoder?** No. The Actor calls NHTSA's free public vPIC API for you, in batches, and returns tidy records. It is not affiliated with NHTSA.

**Can I decode a partial VIN?** Yes. Give 8 to 17 characters, with `*` for unknown positions. Results are usually `partial`, with NHTSA error 6 ("Incomplete VIN").

**What does `decodeStatus: "partial"` mean?** NHTSA decoded the VIN but returned a warning, for example an incomplete VIN or a wrong check digit. See `errorCodes` and `errorText`, and `suggestedVin` when NHTSA offers one.

**Does it give recalls, owner, title or accident history?** No. It describes the vehicle model only.

**Why are some fields `null`?** NHTSA has no value for that VIN. A missing value doesn't mean the vehicle lacks the feature.

# Changelog

This Actor's version history is a separate document: https://apify.com/fecklesspleb/nhtsa-vin-decoder/changelog.md

# Actor input Schema

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

One VIN per line. Full 17-character VINs or partial VIN patterns with \* for unknown positions (e.g. 5UXWX7C5*BA). Add a model year after a comma to help older or partial VINs: 5UXWX7C5*BA,2011. Spaces and dashes are removed; duplicates are decoded once. Empty = 6 sample VIN patterns.

## `modelYear` (type: `integer`):

Optional. Used for every VIN without its own ',YEAR'. Leave empty unless you know the year: vPIC reads it from the VIN's 10th character.

## `skipUndecoded` (type: `boolean`):

If on, VINs for which NHTSA returns no make (decode status 'failed') are not saved and not charged. They are counted in RUN_SUMMARY.

## `includeSpecs` (type: `boolean`):

Adds a 'specs' object with every other non-empty vPIC variable (for example airbags, ADAS, battery, axles, wheelbase, when NHTSA has them). Most VINs have only about 5-15 such fields filled; vPIC leaves most of its variables empty. Off = core fields only.

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

Decode at most this many VINs (after removing invalid entries and duplicates). Each decoded VIN is one charged result.

## Actor input object example

```json
{
  "vins": [
    "5UXWX7C5*BA,2011",
    "5YJSA3DS*EF",
    "1HGCM82633A",
    "1FTFW1ET*DF",
    "JTDKN3DU*A1,2010",
    "3VWF17AT*FM"
  ],
  "skipUndecoded": false,
  "includeSpecs": true,
  "maxItems": 1000
}
```

# Actor output Schema

## `vins` (type: `string`):

No description

## `summary` (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": [
        "5UXWX7C5*BA,2011",
        "5YJSA3DS*EF",
        "1HGCM82633A",
        "1FTFW1ET*DF",
        "JTDKN3DU*A1,2010",
        "3VWF17AT*FM"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fecklesspleb/nhtsa-vin-decoder").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": [
        "5UXWX7C5*BA,2011",
        "5YJSA3DS*EF",
        "1HGCM82633A",
        "1FTFW1ET*DF",
        "JTDKN3DU*A1,2010",
        "3VWF17AT*FM",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fecklesspleb/nhtsa-vin-decoder").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": [
    "5UXWX7C5*BA,2011",
    "5YJSA3DS*EF",
    "1HGCM82633A",
    "1FTFW1ET*DF",
    "JTDKN3DU*A1,2010",
    "3VWF17AT*FM"
  ]
}' |
apify call fecklesspleb/nhtsa-vin-decoder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fecklesspleb/nhtsa-vin-decoder"
        }
    }
}
```

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/qk1V5XVjfTBNKfcSF/builds/pzadKZs4nl65JdP1d/openapi.json
