DEV Community

Vin Lookup
Vin Lookup

Posted on

Displaying TransmissionStyle from vPIC Without Inventing Gear Counts

NHTSA vPIC often returns a TransmissionStyle field on DecodeVinValues-style payloads: strings like "Automatic", "Manual", "Continuously Variable Transmission (CVT)", or longer catalog phrases. That label is useful on a free VIN decode card. The trap is dressing it up as a gearbox pitch -- "6-speed," "8DCT," "smooth 10-speed" -- that the API never asserted.

This post is about honest display: pass through the catalog string, refuse invented gear counts, and allow a clean "not provided" state when the field is empty.

What TransmissionStyle is (and is not)

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

It does not answer:

  • How many forward gears the unit has
  • Whether the fluid is due, the clutch is worn, or the CVT belt is healthy
  • Whether a dealer option package swapped the transmission after the VIN was stamped
  • Shift quality, tow mode behavior, or paddle-shift availability
  • Whether "Automatic" here means a traditional planetary box, a dual-clutch, or something else

Empty TransmissionStyle does not mean "probably automatic." It means vPIC did not give you a value. Do not invent a default from make/model folklore or from a Wikipedia gearbox table keyed by trim.

Normalize empties, do not invent ratios

Treat blank, "Not Applicable", "N/A", and similar tokens as missing. Do not rewrite "Automatic" into "6-Speed Automatic" or append a gear count because a sibling field looked similar on another VIN.

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

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

export function viewTransmissionStyle(fields: {
  TransmissionStyle?: string | null;
  TransmissionSpeeds?: string | null;
}): TransmissionView {
  const raw = (fields.TransmissionStyle ?? "").trim();
  if (!raw || EMPTY.has(raw.toLowerCase())) {
    return { label: null, source: "missing" };
  }
  // Do not merge TransmissionSpeeds into the label unless product
  // shows speeds as a separate, sourced row -- never invent counts.
  return { label: raw, source: "vpic" };
}

export function transmissionLines(view: TransmissionView): string[] {
  if (view.source === "missing" || !view.label) {
    return ["Transmission style: not provided by decode."];
  }
  return [
    `Transmission style: ${view.label}`,
    "Catalog label from decode -- not a gear count or shop diagnosis.",
  ];
}
Enter fullscreen mode Exit fullscreen mode

If vPIC also exposes TransmissionSpeeds (or a similar field), show it as its own row with the same empty rules. Never concatenate "Automatic" + guessed "6" into one marketing chip. When speeds are missing, leave the speeds row empty -- do not fill from trim name regexes like /(\d)[- ]?speed/i.

UI patterns that stay honest

  1. Sourced or missing. Every transmission row either quotes a non-empty vPIC string or says "not provided."
  2. No synonym upgrades. Do not map "Automatic" to "Smart Auto" or "CVT" to "Seamless e-CVT" unless that exact phrase came from the API.
  3. Separate speeds. If you show speeds, label the source field explicitly (TransmissionSpeeds) so support can see which column failed.
  4. No redline copy. Avoid "buttery shifts," "race-ready DCT," or "bulletproof 10-speed" next to catalog data.
  5. Tests forbid inventions. Assert that display helpers never emit digit-speed phrases unless the digit appeared in a sourced field.
import assert from "node:assert/strict";

assert.deepEqual(
  transmissionLines(viewTransmissionStyle({ TransmissionStyle: "" })),
  ["Transmission style: not provided by decode."],
);

assert.ok(
  transmissionLines(
    viewTransmissionStyle({ TransmissionStyle: "Automatic" }),
  ).some((l) => /Automatic/.test(l)),
);

assert.ok(
  !transmissionLines(
    viewTransmissionStyle({ TransmissionStyle: "Automatic" }),
  ).some((l) => /\d[\s-]*speed/i.test(l)),
);

assert.ok(
  !transmissionLines(
    viewTransmissionStyle({
      TransmissionStyle: "Continuously Variable Transmission (CVT)",
    }),
  ).some((l) => /e-cvt|seamless|bulletproof/i.test(l)),
);
Enter fullscreen mode Exit fullscreen mode

Add a review rule: the transmission display module must not contain hardcoded gear counts except inside tests that forbid inventing them.

Copy that stays catalog-shaped

When you need a short card subtitle, reuse the vPIC string. Do not paraphrase into "smooth automatic drive" or "manual for enthusiasts." Paraphrase is where marketing sneaks in without a code review noticing.

If product wants a one-word chip, whitelist only tokens that already appear in the raw field (for example taking the first word when it is Automatic, Manual, or CVT). Never map the chip through a synonym table that upgrades "Automatic" to "10AT."

Document the rule in the component README: TransmissionStyle rows are sourced or missing -- never inferred from trim names, package codes, or forum gearbox cheat sheets.

Takeaway

TransmissionStyle is a catalog label. Display it with clear sourcing, allow "not provided," and never use it as a key into invented gear counts. Your free VIN UI stays trustworthy when transmission style is either a real vPIC string with a modest footnote -- or absent.

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

Top comments (0)