DEV Community

Vin Lookup
Vin Lookup

Posted on

Displaying ElectrificationLevel from vPIC Without Inventing EV Range

NHTSA vPIC often returns an ElectrificationLevel field on DecodeVinValues-style payloads: catalog phrases such as "Strong HEV (Hybrid Electric Vehicle)", "BEV (Battery Electric Vehicle)", "PHEV (Plug-in Hybrid Electric Vehicle)", or "Mild HEV (Hybrid Electric Vehicle)". That string is useful on a free VIN decode card. The trap is turning it into an EV range pitch -- "300+ mile range," "all-electric commute," "zero gas forever" -- that the electrification level field never asserted.

This post is about honest display: show the electrification level when vPIC provides it, refuse range inventing, and allow a clean "not provided" state when the field is empty. Pair related powertrain fields only as separate rows, never as a merged marketing slogan.

What ElectrificationLevel is (and is not)

ElectrificationLevel is a catalog / manufacturer attribute associated with the VIN decode. It answers a narrow question: which electrification category did the decode associate with this vehicle pattern?

It does not answer:

  • Usable battery capacity (kWh) or EPA / WLTP range in miles or kilometers
  • Whether the used car still has the same pack health as when certified
  • Charge time, DC fast-charge capability, or home Level 2 requirements
  • Fuel economy for hybrids, or "gas-free" lifestyle copy for BEVs
  • A safe default when the field is blank ("probably hybrid" is still fiction)

Empty ElectrificationLevel does not mean "ICE only" or "mild hybrid." It means vPIC did not give you a value. Do not invent a default from make/model tables, from a Model Year chart, or from a brochure PDF keyed by trim.

Normalize empties, do not invent range

Treat blank, "Not Applicable", "N/A", and similar tokens as missing. Do not rewrite an electrification token into "250 mi EPA" or append a pack size because a sibling VIN looked similar last week.

const EMPTY = new Set([
  "",
  "not applicable",
  "n/a",
  "na",
  "null",
  "none",
  "unknown",
]);

export type ElectrificationView = {
  label: string | null;
  source: "vpic" | "missing";
};

export function viewElectrificationLevel(fields: {
  ElectrificationLevel?: string | null;
}): ElectrificationView {
  const raw = (fields.ElectrificationLevel ?? "").trim();
  if (!raw || EMPTY.has(raw.toLowerCase())) {
    return { label: null, source: "missing" };
  }
  // Keep the catalog token; do not coerce into range / kWh claims.
  return { label: raw, source: "vpic" };
}

export function electrificationLines(view: ElectrificationView): string[] {
  if (view.source === "missing" || !view.label) {
    return ["Electrification level: not provided by vPIC for this VIN"];
  }
  return [
    `Electrification (vPIC): ${view.label}`,
    "Catalog category only -- not battery range or charge speed",
  ];
}
Enter fullscreen mode Exit fullscreen mode

The footnote matters. Buyers and bots both over-read powertrain labels. A second line that names the source and the limit keeps the UI honest without burying the useful value.

Forbidden upgrades

Product pressure often asks for:

  1. Mapping "BEV" into "300+ mile range" badges from a static chart
  2. Inferring pack kWh from Model Year + Make when vPIC never returned capacity
  3. Showing OEM configurator range numbers next to ElectrificationLevel as if they were decode fields
  4. Merging ElectrificationLevel with FuelTypePrimary into "Zero Emission Commuter"
  5. Defaulting blank ElectrificationLevel to "ICE" so the card never looks incomplete

Refuse those. If you show fuel type, engine model, or battery fields from another sourced attribute, show each on its own row. Never invent EPA range inside the decode mapper when vPIC did not supply it.

export function assertNoEvRangeMarketing(moduleSource: string): void {
  const banned = [
    /\d+\s*\+?\s*mile/i,
    /\d+\s*mi\b.*range/i,
    /kwh\s*pack/i,
    /zero\s*emission\s*commuter/i,
    /gas[-\s]?free\s+forever/i,
  ];
  for (const re of banned) {
    if (re.test(moduleSource)) {
      throw new Error(
        `Electrification display must not invent EV range claims: ${re}`,
      );
    }
  }
}

export function cardRows(fields: {
  ElectrificationLevel?: string | null;
  FuelTypePrimary?: string | null;
}): { label: string; value: string }[] {
  const elec = viewElectrificationLevel(fields);
  const fuel = (fields.FuelTypePrimary ?? "").trim();
  const rows: { label: string; value: string }[] = [];

  if (elec.source === "vpic" && elec.label) {
    rows.push({ label: "Electrification (vPIC)", value: elec.label });
  } else {
    rows.push({ label: "Electrification (vPIC)", value: "not provided" });
  }

  if (fuel && !EMPTY.has(fuel.toLowerCase())) {
    rows.push({ label: "Fuel type (vPIC)", value: fuel });
  }

  return rows;
}
Enter fullscreen mode Exit fullscreen mode

Separate rows keep attribution clear. A single "Powertrain" chip that secretly combines ElectrificationLevel and FuelTypePrimary is how marketing sneaks past review.

Small tests that lock honesty

import assert from "node:assert/strict";

assert.equal(
  viewElectrificationLevel({
    ElectrificationLevel: "BEV (Battery Electric Vehicle)",
  }).source,
  "vpic",
);
assert.equal(
  viewElectrificationLevel({ ElectrificationLevel: "N/A" }).source,
  "missing",
);
assert.equal(viewElectrificationLevel({ ElectrificationLevel: "" }).source, "missing");

assert.ok(
  electrificationLines(
    viewElectrificationLevel({
      ElectrificationLevel: "PHEV (Plug-in Hybrid Electric Vehicle)",
    }),
  ).some((l) => /not battery range/i.test(l)),
);
assert.ok(
  !electrificationLines(
    viewElectrificationLevel({
      ElectrificationLevel: "BEV (Battery Electric Vehicle)",
    }),
  ).some((l) => /mile|kWh|gas-free/i.test(l)),
);

const rows = cardRows({
  ElectrificationLevel: "Strong HEV (Hybrid Electric Vehicle)",
  FuelTypePrimary: "Gasoline",
});
assert.equal(rows.length, 2);
assert.ok(rows[0].label.includes("Electrification"));
assert.ok(rows[1].label.includes("Fuel type"));
assert.ok(!rows.some((r) => /Zero Emission|300\+/i.test(r.value)));
Enter fullscreen mode Exit fullscreen mode

Add a review rule: the electrification module must not contain range or kWh marketing phrases except in tests that forbid them. For chips, show the catalog level with an "Electrification" label -- never upgrade a blank into "ICE" or "Standard Hybrid."

Takeaway

ElectrificationLevel is a catalog category. Display it with clear sourcing, allow "not provided," and never use it as a key into invented EV range or pack claims. Your free VIN UI stays trustworthy when electrification is either a real vPIC value with a modest footnote -- or absent -- and range marketing lives somewhere else, clearly labeled, or not at all.

I maintain VIN Lookup, a free VIN decode based on NHTSA data.

Top comments (0)