VIN Decoder & Recalls
Decode VINs in bulk and get open US safety recalls on the same row: make, model, year, trim, engine, plant, airbags, plus recall component and remedy.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
vins,includeRecalls,maxItems(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.0009 per VIN decoded = $0.9 per 1,000
| You are charged for | When | Price |
|---|---|---|
| VIN decoded | One vehicle decoded from its VIN, with any open safety recalls. VINs that cannot be decoded are never charged. | $0.0009 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-09-20, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
vins | One or more 17-character Vehicle Identification Numbers. Up to 1,000 per run. Dashes and spaces are stripped, letter case does not matter, and duplicates are dropped before anything is charged. A VIN identifies a vehicle, not a person - this Actor looks up no owner, registration or title data. | array |
includeRecalls | On by default. Each decoded vehicle gets its open US safety recall campaigns attached - component, summary, consequence and the manufacturer's remedy. Recall lookups are cached per make, model and year inside the run, so a list of the same few models costs very little extra time. Turn it off if you only want the specification decode; the price per VIN is the same either way. | boolean |
maxItems | A hard stop on how many of the VINs above are decoded, so a long pasted list cannot run away with your budget. Keep it low while you are testing - you pay per decoded vehicle. Hard ceiling 1,000 per run. | integer |
proxyUrls | Leave this empty for a normal run. Fill it in only if you want the traffic to leave through proxy servers you already pay for, one URL per line, in the form http://user:pass@host:port. | array |
What you get
A structured dataset — each result includes fields like:
vinmakemodelmodelYeartrimbodyClassvehicleTypedriveTypefuelTypePrimaryrecallLookuprecallCountExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
Related tools in Developer & Research Tools
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
GitHub Scraper
Search GitHub repos and users: stars, forks, language, topics, licence, plus user bio, company and followers. No token needed. $0.90 per 1,000 rows.
Stack Overflow / Stack Exchange Scraper
Search Stack Overflow and Stack Exchange by keyword or tag. Score, answer count, views, reputation and body text. $2 per 1,000 questions.
Package Registry Scraper (npm + PyPI)
Get npm and PyPI package metadata as JSON. Version, license, author, repo, keywords and npm monthly downloads. $2 per 1,000 packages.
arXiv Scraper
Search arXiv papers by title, author, abstract or category. Get full abstracts, authors, categories, DOI, dates and PDF links. $2 per 1,000 papers.
OpenAlex Scholarly Works Scraper
Search 250M+ OpenAlex papers with no API key. Get titles, authors, venue, year, citations, DOI, OA links and full abstracts. $2.00 per 1,000 papers.
Crossref Scholarly Works Scraper
Search 150M+ papers on Crossref: DOI, title, authors, journal, publisher, date, citations and abstract. No API key. $1.00 per 1,000 works.
Where this tool sits
- Categories
- Developer & Research Tools
VIN Decoder & Recalls API (NHTSA)
Paste VINs, get vehicles back. Each 17-character VIN becomes one row carrying what the US federal vehicle record says the car is (make, model, year, trim, engine, drivetrain, assembly plant, airbags, ABS, stability control), with every open US safety recall for that make, model and year attached to the same row, including what the fault is, what it can do, and the fix the manufacturer has to provide free.
The awkward part first, because it decides whether this is the right purchase: this is the federal specification and recall record, not a vehicle history report. It cannot tell you whether a car was crashed, flooded, stolen, clocked or salvaged, and it holds nothing at all about whoever owns it. If that is what you need, you need a history report, and no amount of VIN decoding will substitute for one.
- Up to 1,000 VINs per run, decoded 50 at a time in a single request rather than one at a time.
- No API key, no account, no cookies, no browser. The source is a free US government service.
- A VIN that does not decode is a free row that says why, not a charged row full of blanks.
- Recall lookups are cached inside the run, so 400 VINs across a handful of models cost a handful of lookups.
- Runs with empty input return a labelled sample row, free, so you can see the shape first.
Price
$0.90 per 1,000 vehicles, plus a $0.0006 start fee per run (one per run, whatever the row count).
This is a flat rate on every plan, free or paid. There are no volume tiers, no minimum spend, no subscription and no add-on fees. What you read here is what you pay on day one and on day four hundred.
| Vehicles | Total cost |
|---|---|
| 100 | $0.0906 |
| 1,000 | $0.9006 |
| 10,000 | $9.0006 |
| 100,000 | $90.0006 |
Rows that are not charged, such as the sample row, an invalid VIN or a vehicle NHTSA has no record of, do not appear in these totals at all.
What is actually charged
- One
vin-decodedevent per vehicle row written to the dataset. Nothing else is metered per row. - Free: the sample row an empty run returns, and every diagnostic row: a blocked target, a dead URL, a search that matched nothing. Those rows all carry
"charged": false. - A VIN that is not 17 characters, or that carries letters no VIN contains, is rejected before it reaches the network and charged nothing.
- A VIN the federal record has no vehicle for, which is common for cars never sold in the United States, is a free diagnostic row rather than a charge.
- Duplicate VINs in your list are collapsed before anything is looked up, so pasting the same VIN twice bills once.
- If the recall service cannot be reached at all, the decoded vehicle is still handed over, but free, with a row saying the recall half is missing.
- A run that finds nothing costs the start fee and nothing more.
- Rows never leave the dataset without a charge, and are never charged without a row.
Input
{
"vins": [
"1HGCM82633A004352",
"JTDKARFU2J3064306",
"3GCUKREC5JG123456"
],
"includeRecalls": true,
"maxItems": 25
}
| Field | What it does |
|---|---|
vins | The VINs, as a list. Dashes, spaces and lower case are all fine; they are cleaned before anything is sent. Up to 1,000 per run. |
includeRecalls | On by default. Turn it off for a specification-only decode, which is faster on long lists. The price per vehicle does not change either way. |
maxItems | A hard stop on how many of your VINs get decoded, so a long pasted list cannot run away with the bill. Default 25, ceiling 1,000. |
proxyUrls | Leave empty. Fill it in only if you want the traffic to leave through proxy servers you already pay for, as http://user:pass@host:port. |
Run it with empty input and you get one clearly labelled sample row, free, so you can see the output shape before you spend anything.
Output
One row per vehicle. A real row from a real run:
{
"ok": true,
"charged": true,
"recordType": "vehicle",
"vin": "JTDKARFU2J3064306",
"make": "TOYOTA",
"model": "Prius",
"modelYear": 2018,
"trim": "Two Eco/Three/Three Touring/Four/Four Touring",
"bodyClass": "Hatchback/Liftback/Notchback",
"vehicleType": "PASSENGER CAR",
"driveType": "4x2",
"fuelTypePrimary": "Gasoline",
"recallLookup": "ok",
"recallCount": 1,
"recalls": [
{
"campaignNumber": "18V579000",
"reportReceivedDate": "2018-09-05",
"component": "ELECTRICAL SYSTEM:WIRING",
"summary": "Toyota Motor Engineering & Manufacturing (Toyota) is recalling certain 2016-2018 Toyota Prius vehicles. A portion of the engine wire harness connected to the hybrid Power Control Unit (PCU), could contact the cover at this connection and wear, causing an electrical short circuit.",
"consequence": "An electrical short can increase the risk of a fire.",
"remedy": "Toyota will notify owners, and dealers will inspect the engine wire harness assembly and replace it if damage is found. A protective sleeve or protective tape will be included to prevent any future damage. These repairs will be performed free of charge. The recall began October 30, 2018. Owners may contact Toyota customer service at 1-888-270-9371. Toyota's number for this recall is J0T.",
"notes": "Owners may also contact the National Highway Traffic Safety Administration Vehicle Safety Hotline at 1-888-327-4236 (TTY 1-800-424-9153), or go to www.safercar.gov.",
"manufacturer": "Toyota Motor Engineering & Manufacturing",
"parkIt": false,
"parkOutSide": false,
"overTheAirUpdate": false
}
],
"series": "ZVW50L/ZVW51L",
"doors": 5,
"engineCylinders": 4,
"displacementL": 1.8,
"engineHorsepower": 96,
"electrificationLevel": "Strong HEV (Hybrid Electric Vehicle)",
"transmissionStyle": "Continuously Variable Transmission (CVT)",
"transmissionSpeeds": null,
"manufacturer": "TOYOTA MOTOR CORPORATION",
"plantCountry": "JAPAN",
"plantCity": "TOYOTA CITY",
"plantState": "AICHI",
"gvwr": "Class 1: 6,000 lb or less (2,722 kg or less)",
"abs": "Standard",
"esc": "Standard",
"tpms": "Direct",
"airBagLocFront": "1st Row (Driver and Passenger)",
"airBagLocSide": "1st Row (Driver and Passenger)",
"airBagLocCurtain": "All Rows",
"seatBeltsAll": "Manual",
"recallModelMatched": "Prius",
"nhtsaErrorCodes": "1",
"nhtsaErrorText": "1 - Check Digit (9th position) does not calculate properly",
"vehicleDescriptor": "JTDKARFU*J3",
"scrapedAt": "2026-09-20T08:30:44.584Z"
}
Field notes
recallLookup: the one field to read before trustingrecallCount.okmeans the recall service answered and the campaigns below are what it returned.nonemeans it answered and this vehicle is not in its recall index.unavailablemeans the count is unknown rather than zero, for one of two reasons: the decode came back without a model name, so there is nothing to match on, or the two federal endpoints disagreed, one listing the model as recalled while the other returns nothing for it.skippedmeans you turned recalls off. Never read a zero here as a clean bill of health without checking this field first.recallCount: how many campaigns are attached. Only meaningful whenrecallLookupisokornone.recalls: the full campaign text, with its number, date reported, component, a plain-English summary of the fault, its consequence, and the remedy the manufacturer owes you.parkItandparkOutSideare the federal "stop driving it" and "do not park it indoors" flags.recallModelMatched: the model name the recall service actually matched. Usually the same asmodel; on trucks it is often more specific, because the decode says "Silverado" and the recall index files them as "SILVERADO 1500", "2500" and "3500" separately.modelYear: the model year, which is not the calendar year the car was built.nhtsaErrorCodes: whatever the decoder flagged. Code 1, "check digit does not calculate", is extremely common on perfectly real VINs and does not mean the decode is wrong.trim: often a slash-separated list of the trims that share one VIN pattern, because a VIN does not always narrow to a single trim.engineHorsepower: present for most petrol and hybrid vehicles, usually absent on electric ones.series: the manufacturer series or chassis code, where the record has one.
Every real row carries "charged": true. Sample rows carry "_sample": true and diagnostic rows carry "_diagnostic": true with an errorCode you can filter on, and neither is ever billed.
How it works
- VINs go to the federal decoder in batches of fifty in one request. Sending them one at a time measured roughly five times slower on the same twenty VINs, and the Actor is priced on what it costs to run, so the batch is the whole design rather than a nicety.
- Every decode is checked against what came back, not against the HTTP status. The decoder answers 200 for gibberish too, with an empty make and an error code buried in the body, so a row only counts as a vehicle when there is actually a make and a model year in it.
- Recalls are looked up per make, model and year, and cached for the rest of the run. A fleet list with two hundred Silverados and a hundred F-150s is two lookups, not three hundred.
- When a lookup comes back empty, the federal recall index is consulted for the exact model names it files that make and year under, and the closest of those is retried, preferring the one matching the VIN's own series, so a 1500's recalls never land on a 3500.
- Requests go out one at a time. The recall service refuses an address that pushes it, and refuses it for minutes, so the run stays deliberately slow rather than fast and blocked.
What people use it for
- Dealers and wholesalers running an inbound list of VINs before the cars are listed, so an open airbag or fuel-pump campaign turns up before a customer finds it.
- Fleet and rental operators checking a whole fleet on a schedule and diffing
recallCountagainst last week to see only what is new. - Insurance and claims teams normalising a book of VINs into make, model, year, body class and safety equipment for rating, without typing any of it.
- Anyone building a car marketplace or a listing feed who needs specifications filled in from the VIN alone rather than from whatever the seller typed.
- Researchers and journalists pulling the recall record for a model year across a list of real vehicles instead of clicking through one lookup form at a time.
What a VIN does and does not tell you here
A VIN identifies a vehicle, not a person. This Actor looks up nothing about an owner, a registration, a title or an address, and there is no input that would let it. What it returns is the manufacturer's own description of how that car left the factory, as filed with the US regulator, plus the safety campaigns raised against that make, model and year since.
Two consequences worth knowing before you buy:
- Recalls are matched at make, model and year, because that is the level the public federal recall service works at. A campaign that only covers part of a model year, whether a range of build dates, one plant or one engine, will still appear on every vehicle of that model year. Read the
summary; it names the range. - Whether a specific car has actually had its recall work done is not public data. Only the manufacturer knows that, and you get it from their own VIN lookup or a franchised dealer.
recallCountis "campaigns that apply", never "repairs outstanding".
Reading the output
Every run writes three kinds of row, and they are easy to tell apart:
- Real rows carry
"charged": trueand"recordType": "vehicle". One billed event each, and the count of these rows always equals the number of events you were billed for. - The sample row carries
"_sample": trueand"charged": false. There is exactly one, it only appears when you ran with no VINs, and it exists so you can see the output shape before spending anything. - Diagnostic rows carry
"_diagnostic": true,"charged": falseand anerrorCodeyou can switch on:BAD_INPUTwhen a value was not a 17-character VIN,NO_RESULTSwhen the federal record holds no vehicle for it,RECALL_LOOKUP_FAILEDwhen the vehicle decoded but the recall service could not be reached,NETWORKwhen the decoder itself could not be reached,TIME_BUDGETwhen the run ran out of time before reaching a VIN.
One thing to expect on a long list of bad VINs: the first fifty failures each get their own row, and the rest are collapsed into a single row with a skipped array naming every remaining VIN and its reason. Nothing is hidden, but the row count will be lower than the number of VINs you sent. And if the run gets through 150 VINs in a row without producing a single vehicle, it stops and says so rather than grinding through the rest of a list that is clearly not VINs.
If you only want the data, filter on charged == true. The dataset is its own invoice.
Limitations
- United States only. This is the US federal vehicle record, so a car never certified for sale in the US, which covers most European and Japanese domestic-market vehicles, decodes partially or not at all, and has no recall record here.
- Not a vehicle history report. No accident history, no title or salvage brand, no odometer readings, no theft record, no ownership or service history. None of that is in the source.
- No owner or registration data of any kind, by design and by law.
- Pre-1981 VINs are not 17 characters and are rejected. The standardised VIN only starts with the 1981 model year.
- Recalls come from the public federal service, which matches at make, model and year. It cannot tell you whether a particular car falls inside a campaign's build-date range, and it cannot tell you whether the work has been done.
- The two federal recall endpoints sometimes disagree: one lists a model as having campaigns while the lookup returns nothing for it. Measured across 45 common US vehicles, 40 returned recalls and 5 hit that gap. Those rows say
recallLookup: "unavailable"rather than claiming zero recalls, so you can tell an unknown from a clean sheet. - How completely a VIN decodes depends on what the manufacturer filed. Older and low-volume vehicles come back with more empty fields than a recent mass-market one, and no amount of re-running changes that.
- Manufacturer-specific recalls and service campaigns that were never filed federally do not appear. Neither do recalls issued outside the United States.
- The hard ceiling is 1,000 VINs per run. Split longer lists across runs.
- Because the recall service throttles hard, long lists of wildly different vehicles take minutes rather than seconds. A list that is mostly the same few models is much faster.
Questions
Is this a vehicle history report?
No, and it cannot be turned into one. This is the federal specification decode plus the federal recall record. Accidents, titles, odometer readings and ownership are not in the source and are not returned. If a car's past is what you need, buy a history report.
Can I look up who owns a vehicle?
No. A VIN identifies a car, not a person, and nothing here touches registration or owner records. There is no input field that would let you, and there will not be one.
What happens if a VIN is wrong or made up?
You get one free diagnostic row saying which it was: not 17 characters, characters that are not valid in a VIN, or no vehicle on file. The run carries on to your other VINs. You are never billed for a VIN that did not produce a vehicle.
Why does a row say the check digit does not calculate?
That is error code 1 from the decoder and it is very common, including on VINs read straight off a real windscreen. It means the ninth character did not match the arithmetic, usually because of a transcription slip, and the rest of the VIN still decodes. Treat it as a hint to re-read the VIN, not as a failure.
Does recallCount of 0 mean the car is clean?
Only when recallLookup says none. If it says unavailable, the federal service returned nothing for a model its own index lists as recalled, so the honest answer is "unknown" and the row says so instead of pretending it is zero.
Can I run this on a schedule?
Yes. Nothing is held between runs, so the same VIN list on a schedule is safe. Diff on recallCount and the campaign numbers in recalls to see only what is new.
Do I need a proxy or an API key?
Neither. The source is a free US government service and the run brings its own egress. The proxy field exists only for callers who specifically want traffic leaving through servers they already own.
How do I get exactly the rows I paid for?
Filter the dataset on "charged": true. Sample and diagnostic rows are always false, and the number of charged rows always equals the number of billed events.