DEV Community

life
life

Posted on Edited on

A parcel tracking state machine that stops lying to your customers

Cross-border tracking is where a lot of ecommerce UIs quietly lie. They show "In transit" the moment a label is printed, but a label is not a package moving. Here is a state model that keeps the truth intact.

The core insight: a tracking number is not evidence of physical carrier acceptance. The events mean different things:

  • LABEL_CREATED: a number exists. Nothing has physically moved.
  • ACCEPTED (the first carrier scan): the carrier physically has the parcel. This is the real "shipped" moment.
  • IN_TRANSIT, OUT_FOR_DELIVERY, DELIVERED: subsequent milestones.

If you collapse LABEL_CREATED and ACCEPTED into one "shipped" state, customers blame you for "stuck" packages that the carrier never actually received.

const TRANSITIONS = {
  LABEL_CREATED: ['ACCEPTED', 'CANCELED'],
  ACCEPTED: ['IN_TRANSIT', 'RETURNED', 'EXCEPTION'],
  IN_TRANSIT: ['OUT_FOR_DELIVERY', 'EXCEPTION', 'RETURNED'],
  OUT_FOR_DELIVERY: ['DELIVERED', 'EXCEPTION'],
  DELIVERED: [],
  EXCEPTION: ['IN_TRANSIT', 'RETURNED', 'DELIVERED'],
};

function advance(state, event) {
  const allowed = TRANSITIONS[state] || [];
  return allowed.includes(event) ? event : state; // ignore illegal jumps
}
Enter fullscreen mode Exit fullscreen mode

Two rules that save you support tickets:

  1. Only show "shipped" on ACCEPTED, not LABEL_CREATED. Before that, show "Label created, awaiting carrier pickup." Honest, and it stops the "it has not moved in 3 days" panic when a label sits on a shelf.

  2. Never let an out-of-order webhook regress the state. Carrier feeds arrive late and shuffled. Guard with the transition map above so a stale IN_TRANSIT cannot overwrite a newer DELIVERED.

Model the gap between "we made a label" and "the carrier has the box," and half your tracking complaints disappear. We run this across the carrier mix we handle day to day, and the first-scan-vs-label distinction is the single biggest source of customer confusion when it is hidden.

Top comments (0)