# Canada VIN Decoder: Recalls & Market Value Report (`fayoussef/canada-vin-report`) Actor

Decode VINs in bulk and get US and Transport Canada recalls, NHTSA safety stars and complaints, plus the live Canadian market value from AutoTrader.ca, Kijiji and CarGurus comparables, with a deal rating for your asking price.

- **URL**: https://apify.com/fayoussef/canada-vin-report.md
- **Developed by:** [Youssef Farhan](https://apify.com/fayoussef) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.25 / 1,000 vin reports

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

## Canada VIN Decoder: Recalls and Market Value Report

Paste a list of VINs (or upload a spreadsheet) and get **one report per vehicle**. Each report has the **decoded specs**, the **US (NHTSA) and Canadian (Transport Canada) recalls**, **NHTSA crash-test stars and complaint counts**, and the **live Canadian market value** built from comparable cars for sale on **AutoTrader.ca, Kijiji and CarGurus.ca**. Add an asking price and odometer and you also get a **deal rating** (great, good, fair, high or overpriced).

It is a bulk VIN check made for Canada: one run handles a single car or a fleet of thousands, and the result exports to Excel, CSV, JSON or Google Sheets.

### What you get for every VIN

- **VIN decoding.** Year, make, model, trim, series, body style, doors, drivetrain, fuel, electrification, engine (cylinders, litres, horsepower, code), transmission, GVWR class and assembly plant. The full decoder output, around 60 to 90 attributes per vehicle, is kept in `specs`.
- **VIN validation.** Wrong length and impossible characters are caught. The check digit (9th character) is verified, so a mistyped VIN is flagged instead of silently decoding to the wrong car. Letters O, I and Q, which never appear in a VIN, are read as 0, 1 and 0.
- **Recalls from both countries.** NHTSA recall campaigns (component, summary, consequence, remedy, "park it" warnings, over-the-air fixes) and **Transport Canada recalls** (system, description in English and French, units affected in Canada).
- **Safety.** NHTSA 5-star crash ratings per body variant and the number of owner complaints filed with NHTSA.
- **Canadian market value.** Median asking price, 25th and 75th percentile, low and high, from live comparable listings on AutoTrader.ca, Kijiji and CarGurus.ca. A car listed on two or three sites counts once.
- **An estimate for this car.** Uses same-trim comparables when there are enough, adjusted to the odometer you give, plus the price change per 10,000 km in the current market.
- **Deal rating.** With an asking price, you get where it sits among the comparables (percentile), the gap to the estimate in dollars and percent, and a rating.
- **Is it for sale right now?** If the exact VIN shows up among the listings read, you get its price, km, seller, days on market and link.
- **Sample comparables.** Up to five similar cars with links, nearest in km and same trim first.

### Who it is for

- **Used car dealers and wholesalers**: appraise trade-ins and auction lists in bulk, check recalls before you list, and price against the live Canadian market.
- **Fleet managers and leasing companies**: run the whole fleet for open recalls in the US and Canada, and track what each unit is worth today.
- **Lenders and insurers**: validate the VIN on an application, confirm the vehicle matches, and check the asking price against the market before you fund or insure.
- **Marketplaces and classifieds**: enrich listings with decoded specs, recall counts and a price-vs-market badge.
- **Car buyers**: check a car's recalls and whether the price is fair before you call the seller.
- **AI agents**: call it through the [Apify MCP server](https://mcp.apify.com) or the API to answer "is this a good price?" or "does this VIN have recalls?" in one step.

### How to use it

1. Paste your VINs in **VINs**, one per line. To get a deal rating, add the asking price and the odometer after the VIN: `2HGFC2F61JH031314, 18500, 90000`.
2. Or upload a **spreadsheet** (Excel, CSV or a Google Sheets link). The column named `VIN` is used; columns with "price" and "km", "mileage" or "odometer" in the header are read as asking price and odometer. Your original columns are kept in each result.
3. Keep **Recalls and safety ratings** and **Canadian market value** on, or turn either off.
4. For a local market, set a **postal code** and a **radius**. Leave the radius at 0 to compare against all of Canada.
5. Run it and download the results, or open the **Recalls** and **Market value** views in the Output tab.

#### Input example

```json
{
    "vins": [
        "2HGFC2F61JH031314, 18500, 90000",
        "2T1BURHE2JC018315",
        "1C4RJFCG7FC647891, 17000, 160000"
    ],
    "include_recalls": true,
    "include_market_value": true,
    "postal_code": "M5V 3L9",
    "radius_km": 250,
    "comparables_per_site": 40
}
```

### Output example

One row per VIN (shortened; recall and comparable lists trimmed to one entry):

```json
{
    "vin": "2HGFC2F61JH031314",
    "status": "ok",
    "valid": true,
    "check_digit_valid": true,
    "year": 2018,
    "make": "Honda",
    "model": "Civic",
    "trim": "LX Honda Sensing",
    "body_class": "Sedan/Saloon",
    "drive_type": "4x2",
    "fuel_type": "Gasoline",
    "engine_cylinders": 4,
    "engine_displacement_l": 2.0,
    "engine_hp": 158,
    "transmission": "Continuously Variable Transmission (CVT)",
    "plant_city": "ALLISTON",
    "plant_country": "CANADA",
    "recall_scope": "Recalls issued for the 2018 Honda Civic (model year, not this VIN)",
    "us_recall_count": 6,
    "canada_recall_count": 7,
    "us_complaints_count": 596,
    "nhtsa_overall_stars": 5,
    "canada_recalls": [
        {
            "recall_number": "2018536",
            "date": "2018-09-27",
            "system": "Steering",
            "units_affected_in_canada": 9,
            "description": "On certain vehicles, the electric power steering system could get caught in an infinite loop..."
        }
    ],
    "market_scope": "2018 Honda Civic, used, within 250 km of M5V3L9",
    "comparables_count": 98,
    "market_confidence": "high",
    "market_p25": 14995,
    "market_median": 16944,
    "market_p75": 18990,
    "trim_comparables_count": 13,
    "trim_market_median": 15999,
    "price_change_per_10000_km": -602,
    "estimated_value": 17147,
    "estimate_basis": "median of LX Honda Sensing comparables, adjusted to 90,000 km",
    "asking_price": 18500,
    "mileage_km": 90000,
    "asking_price_percentile": 72,
    "price_vs_estimate": 1353,
    "price_vs_estimate_pct": 7.9,
    "deal_rating": "high",
    "currently_listed": false,
    "sample_comparables": [
        {
            "title": "2018 Honda Civic",
            "trim": "LX with Honda Sensing",
            "price": 16490,
            "mileage_km": 95535,
            "city": "Boucherville",
            "listed_on": ["autotrader", "cargurus"],
            "url": "https://www.cargurus.ca/Cars/inventorylisting/..."
        }
    ]
}
```

### Main output fields

| Field | What it is |
|---|---|
| `vin`, `status`, `check_digit_valid`, `message` | The VIN, `ok`, and any note (for example a check digit that does not match) |
| `year`, `make`, `model`, `trim`, `series` | Decoded identity |
| `body_class`, `drive_type`, `fuel_type`, `electrification` | Body and powertrain |
| `engine_cylinders`, `engine_displacement_l`, `engine_hp`, `transmission` | Engine and gearbox |
| `plant_city`, `plant_state`, `plant_country`, `manufacturer` | Where it was built |
| `us_recall_count`, `us_recall_campaigns`, `us_recalls` | NHTSA recalls for the make, model and model year |
| `canada_recall_count`, `canada_recall_numbers`, `canada_recalls` | Transport Canada recalls for the make, model and model year |
| `nhtsa_overall_stars`, `nhtsa_safety_ratings`, `us_complaints_count` | Crash-test stars and owner complaints |
| `market_median`, `market_p25`, `market_p75`, `market_low`, `market_high` | Canadian asking prices of comparable cars, CAD |
| `estimated_value`, `estimate_basis` | Estimate for this car (trim and odometer aware) |
| `asking_price_percentile`, `price_vs_estimate`, `deal_rating` | Where your asking price sits |
| `comparables_count`, `market_confidence`, `comparables_by_site` | How much data the value rests on |
| `currently_listed`, `current_listing` | This exact VIN for sale right now, with its link |
| `specs` | Every attribute the VIN decoder returned |
| `input_row`, `row_number` | Your spreadsheet row, when you uploaded one |

### Pricing

Pay per event, with nothing to install and no API key:

| Event | What triggers it |
|---|---|
| VIN report | One decoded VIN in the results (decode, recalls and safety included) |
| Market value | A report that carries a Canadian market value (3 or more comparables found) |

The current rates are shown on this Actor's Store page, with a small discount on bigger Apify plans. VINs that cannot be read (wrong length, impossible characters, unknown to the decoder) are **never charged**: they are listed in the `UNREADABLE_VINS` record instead of the results. A market value is only charged when one was found, and the same make, model and year is looked up once per run, however many VINs share it.

The free plan reports the first 10 VINs of each run. Any [Apify plan](https://apify.com/pricing?fpr=youssef) removes the cap.

### Good to know

- **Recalls are for the make, model and model year, not the individual VIN.** Neither NHTSA nor Transport Canada offers a public per-VIN recall lookup, so a recall listed here may cover only part of that year's production. The manufacturer's or dealer's own VIN check confirms whether a specific car is included and whether the work was done.
- **Market values are asking prices**, not sold prices, from cars listed for sale on AutoTrader.ca, Kijiji and CarGurus.ca when the run happens. Sport or luxury versions far from the pack (a Civic Type R among Civics) are left out of the range and the estimate (`outliers_excluded`).
- **Rare cars get fewer comparables.** `market_confidence` is `high` from 20 comparables, `medium` from 8, `low` from 3. Below 3 no value is given and none is charged.
- **Trim.** Some VINs encode the exact trim (`LX Honda Sensing`), others only a range (`L/LE/SE/XLE/XSE`). The estimate uses same-trim comparables only when the trim is specific and at least 5 match.
- **Speed.** Decoding and recalls take a few seconds for hundreds of VINs. With market value on, each distinct make, model and year takes a few seconds; 60 VINs across 12 models ran in about a minute in testing.
- **US and imported vehicles** decode and get recalls too. The market value always comes from Canadian listings.

### FAQ

**How do I check a VIN for recalls in Canada?**
Paste the VIN and keep "Recalls and safety ratings" on. You get every Transport Canada recall and every NHTSA recall issued for that make, model and model year, with descriptions and remedies.

**Can I decode thousands of VINs at once?**
Yes. Paste them or upload an Excel or CSV file. Duplicates are reported once, and progress is saved, so a long run that is moved to another server continues where it stopped.

**How is the market value calculated?**
From the asking prices of the same make, model and year listed on AutoTrader.ca, Kijiji and CarGurus.ca, with the copies of the same car on several sites merged. The estimate starts from the median (or the same-trim median), and is adjusted to your odometer using the price-per-km line of the current listings.

**Is this a Carfax report?**
No. It does not include accident, ownership or lien history. It is the decode, recalls, safety ratings and market value, at a fraction of the effort of looking each one up by hand.

**Can I use it from my own app or an AI agent?**
Yes, through the Apify API, the Python and JavaScript clients, Make, Zapier, n8n, or the [Apify MCP server](https://mcp.apify.com) for AI agents.

### Related Actors

- [Canada Car Scraper](https://apify.com/fayoussef/canada-car-scraper?fpr=youssef): AutoTrader.ca, Kijiji and CarGurus in one dataset, one row per car.
- [AutoTrader.ca Scraper](https://apify.com/fayoussef/autotrader-canada?fpr=youssef): AutoTrader.ca listings with hidden VINs filled in.
- [Bulk LLM Runner](https://apify.com/fayoussef/bulk-llm-runner?fpr=youssef): have ChatGPT or Claude score every car in your results, no API key.

### Support and custom work

Found a bug or a VIN that decodes wrong? Open an issue in the **Issues** tab and I will fix it.

💼 Need a custom solution? Tell me what you need and I'll reply with a solution that fits: <youssefarhan24@gmail.com>

This Actor uses public government data (NHTSA, Transport Canada) and publicly listed car ads. It is not affiliated with NHTSA, Transport Canada, AutoTrader.ca, Kijiji or CarGurus.

# Actor input Schema

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

One 17-character VIN per line. To also rate a price, add the asking price and the odometer in km after the VIN, separated by commas: "2HGFC2F59JH512345, 18500, 92000". Duplicates are reported once.

## `vin_file` (type: `string`):

Upload an Excel (.xlsx), CSV or TSV file, or paste a public link to one (Google Sheets links work when shared as 'Anyone with the link'). The column named VIN is used; columns whose header says price and km (or mileage, odometer) are read as the asking price and odometer. Every row's original columns are kept in the output. Used together with the list above.

## `sheet_name` (type: `string`):

Only for Excel files with several sheets. Leave empty to read the first sheet.

## `include_recalls` (type: `boolean`):

Add US (NHTSA) and Canadian (Transport Canada) recalls, the NHTSA complaint count and NCAP crash-test stars for each vehicle's make, model and model year.

## `include_market_value` (type: `boolean`):

Search AutoTrader.ca, Kijiji and CarGurus.ca for the same make, model and year, and add the median asking price, the price range, a trim and mileage aware estimate and, when you give an asking price, a deal rating. Charged as a separate event, only when a value is found.

## `postal_code` (type: `string`):

Compare against cars for sale around this Canadian postal code ("M5V 3L9" or "M5V"). Leave empty, with the radius at 0, to compare against all of Canada.

## `radius_km` (type: `integer`):

How far from the postal code to look for comparable cars. 0 compares against all of Canada.

## `comparables_per_site` (type: `integer`):

How many listings to read from each site for every make, model and year. More gives a steadier value on common models and takes a little longer.

## `market_sources` (type: `array`):

Which sites the comparable listings come from.

## Actor input object example

```json
{
  "vins": [
    "2HGFC2F61JH031314, 18500, 90000",
    "2T1BURHE2JC018315",
    "1C4RJFCG7FC647891, 17000, 160000"
  ],
  "include_recalls": true,
  "include_market_value": true,
  "radius_km": 0,
  "comparables_per_site": 40,
  "market_sources": [
    "autotrader",
    "kijiji",
    "cargurus"
  ]
}
```

# Actor output Schema

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

One row per VIN: decoded specs, US and Transport Canada recalls, NHTSA safety stars, and the Canadian market value from live comparable listings.

## `unreadable` (type: `string`):

VINs that could not be read (wrong length, impossible characters, or unknown to the decoder). They are not in the results and are not charged.

# 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": [
        "2HGFC2F61JH031314, 18500, 90000",
        "2T1BURHE2JC018315",
        "1C4RJFCG7FC647891, 17000, 160000"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fayoussef/canada-vin-report").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": [
        "2HGFC2F61JH031314, 18500, 90000",
        "2T1BURHE2JC018315",
        "1C4RJFCG7FC647891, 17000, 160000",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fayoussef/canada-vin-report").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": [
    "2HGFC2F61JH031314, 18500, 90000",
    "2T1BURHE2JC018315",
    "1C4RJFCG7FC647891, 17000, 160000"
  ]
}' |
apify call fayoussef/canada-vin-report --silent --output-dataset

```

## MCP server setup

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

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/V43SCpdwX2xUadz1I/builds/eNaVaVn8UGAlKxsO3/openapi.json
