DEV Community

Vin Lookup
Vin Lookup

Posted on

Showing Airbag Location Fields from vPIC Without Inventing Safety Grades

NHTSA vPIC often returns airbag-location style fields on DecodeVinValues payloads: catalog tokens for front, side, curtain, knee, and similar locations when the pattern includes them. That is useful on a free VIN decode card. The trap is turning those strings into a safety grade -- "5-star equivalent," "fully loaded airbags," "safer than average for this class" -- that location fields never asserted.

This post is about honest display: show airbag location fields when vPIC provides them, refuse grade inventing, and allow a clean "not provided" state when every related field is empty. Keep location catalog labels separate from crash-test scores, recall status, and brochure safety packages.

What airbag location fields are (and are not)

DecodeVinValues-style rows may include fields such as AirBagLocFront, AirBagLocSide, AirBagLocCurtain, AirBagLocKnee, and related location keys depending on the vPIC version and vehicle pattern. They answer a narrow question: which airbag-location labels did the decode associate with this VIN pattern?

They do not answer:

  • NHTSA or IIHS star ratings for this exact vehicle
  • Whether airbags are present, functional, or never deployed on the unit for sale
  • Whether a prior crash replaced modules correctly
  • Seat-belt pretensioner or advanced restraint package marketing names
  • A numeric "safety score" you invented by counting non-empty location fields

Empty location fields do not mean "no airbags" in a way that authorizes a scary badge, and a full set of location tokens does not mean "top safety pick." It means vPIC did or did not give you those catalog strings. Do not fill gaps from Make/Model/Year folklore or from a static airbag chart keyed only by body class.

Normalize empties, do not invent grades

Treat blank, "Not Applicable", "N/A", and similar tokens as missing. Do not rewrite "1st Row (Driver and Passenger)" into "dual front airbags -- 5-star ready" or append "fully loaded" because a brochure listed that combination for a different trim year.

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

export type AirbagLocKey =
  | "AirBagLocFront"
  | "AirBagLocSide"
  | "AirBagLocCurtain"
  | "AirBagLocKnee";

export type AirbagLocView = {
  rows: { key: AirbagLocKey; label: string }[];
  source: "vpic" | "missing";
};

const KEYS: AirbagLocKey[] = [
  "AirBagLocFront",
  "AirBagLocSide",
  "AirBagLocCurtain",
  "AirBagLocKnee",
];

export function viewAirbagLocs(
  fields: Partial<Record<AirbagLocKey, string | null>>,
): AirbagLocView {
  const rows: AirbagLocView["rows"] = [];
  for (const key of KEYS) {
    const raw = (fields[key] ?? "").trim();
    if (!raw || EMPTY.has(raw.toLowerCase())) continue;
    rows.push({ key, label: raw });
  }
  return {
    rows,
    source: rows.length ? "vpic" : "missing",
  };
}

export function airbagLocLines(view: AirbagLocView): string[] {
  if (view.source === "missing") {
    return [
      "Airbag locations: not provided by vPIC for this VIN",
    ];
  }
  const lines = view.rows.map(
    (r) => `${r.key} (vPIC): ${r.label}`,
  );
  lines.push(
    "Catalog location labels only -- not a crash-test grade or inspection",
  );
  return lines;
}
Enter fullscreen mode Exit fullscreen mode

The footnote matters. Buyers scanning a decode will over-read any airbag row as a safety rating. If vPIC said a front location string, show that string with sourcing. If every location field is blank, say "not provided" -- no greyed "standard dual front" placeholder and no invented star count from how many keys were filled.

Forbidden upgrades

Product pressure often asks for:

  1. Counting non-empty location fields into a 1-5 "safety score"
  2. Mapping location tokens into IIHS or NHTSA star language
  3. Defaulting blank locations to "Driver and Passenger" so the card looks complete
  4. Merging airbag rows with BodyClass into "safest crossover in class"
  5. Turning location strings into lifestyle copy ("family-safe," "worry-free commute")

Refuse those. If you show crash-test data from another sourced API, show it on its own labeled section with its own provenance. Never invent grades inside the airbag location mapper.

export function assertNoAirbagGrading(moduleSource: string): void {
  const banned = [
    /5[- ]?star/i,
    /safety score/i,
    /top safety pick/i,
    /safer than/i,
    /fully loaded airbags/i,
    /family-safe/i,
  ];
  for (const re of banned) {
    if (re.test(moduleSource)) {
      throw new Error(`airbag module must not invent grades: ${re}`);
    }
  }
}

export type CardRow = { label: string; value: string };

export function cardRows(
  fields: Partial<Record<AirbagLocKey, string | null>> & {
    BodyClass?: string | null;
  },
): CardRow[] {
  const view = viewAirbagLocs(fields);
  const out: CardRow[] = [];
  if (view.source === "missing") {
    out.push({
      label: "Airbag locations",
      value: "not provided",
    });
  } else {
    for (const r of view.rows) {
      out.push({ label: r.key, value: r.label });
    }
  }
  const body = (fields.BodyClass ?? "").trim();
  if (body && !EMPTY.has(body.toLowerCase())) {
    out.push({ label: "Body class", value: body });
  }
  return out;
}
Enter fullscreen mode Exit fullscreen mode

Keep BodyClass on its own row. Never concatenate "SUV + curtain airbags" into a marketing safety claim inside the decode card renderer.

UI copy that stays honest

Prefer:

  • "AirBagLocFront (vPIC): 1st Row (Driver and Passenger)"
  • "Airbag locations: not provided by vPIC for this VIN"
  • A short footnote: catalog labels, not a crash test

Avoid:

  • "Safety rating: Excellent (4 airbag zones)"
  • "Fully equipped airbag package verified"
  • Grey placeholders that look like real location data when fields were empty

If product wants a separate "Learn about airbags" help link, that is fine -- as long as it does not pretend the VIN decode produced a grade.

Quick checks

import assert from "node:assert/strict";

assert.equal(
  viewAirbagLocs({}).source,
  "missing",
);
assert.deepEqual(
  airbagLocLines(viewAirbagLocs({})),
  ["Airbag locations: not provided by vPIC for this VIN"],
);

const populated = viewAirbagLocs({
  AirBagLocFront: "1st Row (Driver and Passenger)",
  AirBagLocSide: "1st Row (Driver and Passenger)",
  AirBagLocCurtain: "",
  AirBagLocKnee: "Not Applicable",
});
assert.equal(populated.rows.length, 2);
assert.ok(
  airbagLocLines(populated).some((l) =>
    /not a crash-test grade/i.test(l),
  ),
);
assert.ok(
  !airbagLocLines(populated).some((l) =>
    /5[- ]?star|safety score|fully loaded/i.test(l),
  ),
);

const rows = cardRows({
  AirBagLocFront: "",
  BodyClass: "Sedan/Saloon",
});
assert.ok(
  rows.some(
    (r) =>
      r.label.includes("Airbag") && r.value === "not provided",
  ),
);
assert.ok(rows.some((r) => r.label.includes("Body class")));
assert.ok(!rows.some((r) => /star|safer than/i.test(r.value)));
Enter fullscreen mode Exit fullscreen mode

Add a review rule: the airbag location module must not contain star-rating or "fully loaded" marketing phrases except in tests that forbid them. For chips, show the catalog location with the field name -- never upgrade a blank into "standard dual front."

Takeaway

Airbag location fields from vPIC are catalog labels. Display them with clear sourcing, allow "not provided," and never use a count of filled keys as a safety grade. Your free VIN UI stays trustworthy when airbag locations are either real vPIC values with a modest footnote -- or absent -- and crash-test 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)