# How OpenPilot Performs Vehicle Fingerprinting to Identify Unknown Car CAN Bus Configurations

> Learn how OpenPilot performs vehicle fingerprinting by analyzing CAN bus traffic to identify unknown car configurations. Discover the deterministic method used to match patterns and resolve ambiguities.

- Repository: [comma.ai/openpilot](https://github.com/commaai/openpilot)
- Tags: how-to-guide
- Published: 2026-03-05

---

**OpenPilot identifies vehicles by capturing a deterministic fingerprint of CAN bus traffic—recording message IDs, bus numbers, and payload lengths—then matching this pattern against a static database of known configurations, with firmware queries resolving any remaining ambiguities.**

OpenPilot, the open-source driving automation system maintained by commaai, relies on precise vehicle identification to interface with diverse automotive networks. Understanding how openpilot vehicle fingerprinting works is essential for developers porting new cars or debugging CAN bus integrations. The system employs a multi-stage identification process that analyzes raw CAN traffic during vehicle startup to determine the exact make and model.

## Stage 1: Collecting Raw CAN Messages

When a route is replayed or a live vehicle connects, OpenPilot reads every CAN frame for a short window—typically a few seconds during the startup sequence. For each message, the system records the **CAN ID**, the **bus** it arrived on, and the **payload length**. This data is organized into a nested dictionary structure: `fingerprint[bus][msg_id] = length`.

The implementation resides in [`selfdrive/debug/fingerprint_from_route.py`](https://github.com/commaai/openpilot/blob/main/selfdrive/debug/fingerprint_from_route.py), which processes recorded drives, and [`selfdrive/debug/get_fingerprint.py`](https://github.com/commaai/openpilot/blob/main/selfdrive/debug/get_fingerprint.py), a minimal CLI tool for dumping fingerprints from live devices. During normal operation, the startup sequence in [`selfdrive/car/card.py`](https://github.com/commaai/openpilot/blob/main/selfdrive/car/card.py) triggers this collection and stores the result in `CarParams`.

## Stage 2: Matching Against Known Fingerprints

The collected fingerprint dictionary is compared against the static database of known vehicle fingerprints located in the **opendbc** submodule at [`opendbc/car/fingerprints.py`](https://github.com/commaai/openpilot/blob/main/opendbc/car/fingerprints.py). Each entry in the `FINGERPRINTS` dictionary maps a specific car model name to the exact pattern of CAN IDs and lengths observed on its bus.

The matching algorithm first attempts an **exact match**. If no exact match is found, the system falls back to a **fuzzy match** that tolerates missing or extra messages. This fallback mechanism allows OpenPilot to recognize vehicles even when certain CAN messages are intermittently absent due to vehicle state variations.

## Stage 3: Firmware-Based Refinement

Some vehicles share identical CAN traffic patterns, making pure CAN fingerprinting ambiguous. To resolve these conflicts, OpenPilot implements **firmware (FW) fingerprinting** by querying the vehicle's ECUs for firmware version strings (`car_fw`). 

The [`tools/car_porting/auto_fingerprint.py`](https://github.com/commaai/openpilot/blob/main/tools/car_porting/auto_fingerprint.py) script merges this firmware data with the CAN fingerprint to create a complete vehicle identifier. Additionally, the `MIGRATION` table in [`opendbc/car/fingerprints.py`](https://github.com/commaai/openpilot/blob/main/opendbc/car/fingerprints.py) handles historic name changes and model identifier updates, ensuring backward compatibility with older vehicle definitions.

## Handling Unknown Vehicle Configurations

If the collected CAN traffic does not match any entry in the fingerprint database, OpenPilot treats the vehicle as **unknown**. In this state, the system runs in a read-only "stock-mode" that prevents active control but logs the unmatched fingerprint for future analysis. These logged fingerprints are later reviewed for inclusion in the database to expand vehicle support.

## Practical Code Examples

To obtain a CAN fingerprint from a replayed route:

```python
from selfdrive.debug.fingerprint_from_route import get_fingerprint

lr = ...  # LogReader instance for the target route

fingerprint = get_fingerprint(lr)

# Returns: {bus: {msg_id: length}}

```

To match a fingerprint against the known vehicle database:

```python
from opendbc.car.fingerprints import FINGERPRINTS, MIGRATION

def match_fingerprint(fp):
    for car, known_fp in FINGERPRINTS.items():
        if fp == known_fp:
            return car
    # Fallback fuzzy match logic would follow here

    return None

car_model = match_fingerprint(fingerprint)
if car_model:
    print(f"Detected car: {car_model}")
else:
    print("Unknown vehicle – logged for future support")

```

To generate a full fingerprint combining CAN data and firmware versions:

```python
from tools.car_porting.auto_fingerprint import auto_fingerprint

fp, fw = auto_fingerprint(route_path="path_to_route")
print("CAN fingerprint:", fp)
print("FW fingerprint:", fw)

```

## Summary

- OpenPilot builds a **deterministic CAN fingerprint** by recording message IDs, bus numbers, and payload lengths during vehicle startup.
- The fingerprint is matched against the static `FINGERPRINTS` database in [`opendbc/car/fingerprints.py`](https://github.com/commaai/openpilot/blob/main/opendbc/car/fingerprints.py) using exact matching with fuzzy fallback.
- **Firmware fingerprinting** (`car_fw`) resolves ambiguities when multiple vehicles share identical CAN patterns.
- Unknown vehicles trigger read-only "stock-mode" and log their fingerprints for future database expansion.
- Key implementation files include [`selfdrive/debug/fingerprint_from_route.py`](https://github.com/commaai/openpilot/blob/main/selfdrive/debug/fingerprint_from_route.py), [`selfdrive/debug/get_fingerprint.py`](https://github.com/commaai/openpilot/blob/main/selfdrive/debug/get_fingerprint.py), and [`tools/car_porting/auto_fingerprint.py`](https://github.com/commaai/openpilot/blob/main/tools/car_porting/auto_fingerprint.py).

## Frequently Asked Questions

### What happens if OpenPilot cannot fingerprint my vehicle?

If no match is found in the fingerprint database, OpenPilot enters a read-only "stock-mode" that prevents active driving assistance but logs the unknown CAN traffic. This data is used by developers to add support for new vehicle models in future releases.

### How does fuzzy fingerprinting differ from exact matching?

Exact matching requires every CAN ID and length in the collected fingerprint to match a database entry perfectly. Fuzzy matching tolerates discrepancies such as missing or extra messages, allowing vehicle identification even when certain ECUs are offline or transmit intermittently.

### Where are vehicle fingerprints stored in the OpenPilot codebase?

Known fingerprints are stored in the external **opendbc** submodule at [`opendbc/car/fingerprints.py`](https://github.com/commaai/openpilot/blob/main/opendbc/car/fingerprints.py). This file contains the `FINGERPRINTS` dictionary mapping vehicle models to their CAN patterns, along with the `MIGRATION` table for handling identifier updates.

### Can firmware fingerprinting alone identify a vehicle without CAN data?

No, firmware fingerprinting serves as a refinement layer rather than a primary identification method. The system first attempts CAN-based fingerprinting, then uses ECU firmware versions (`car_fw`) to resolve ambiguities when multiple vehicles share identical CAN bus configurations.