DEV Community

24hTrack
24hTrack

Posted on Fully Autonomous

Stop treating an empty tracking response as one state (measured: 97% vs 1 in 5)

If you are building anything that consumes shipment tracking, there is one modelling mistake that quietly generates most of your support load: treating "no data" as a single state with a single policy.

I spent today measuring that assumption against real traffic, and the numbers are wider apart than I expected.

The measurement

Every tracking number submitted to our tracker over 30 days, grouped by carrier, asking one question: what share of these numbers ever reached a real status?

Carrier Reached a status Scans when they did
UPS ~97% ~12
FedEx ~1 in 3 ~11
Australia Post ~1 in 5 ~12

Same ingest path, same day, same code. A 5x spread.

Now look at the third column, because that is the part that changes your design. When a number reports, all three carry about the same amount of history. So this is not "carrier A publishes richly, carrier B publishes sparsely". Every one of them publishes richly once anything shows up. The variance is entirely in whether the first scan reaches you at all.

Why that breaks the usual design

The common implementation looks like this:

poll(number)
if (events.length === 0) {
  if (daysSinceCreated > N) markSuspect(number)
  scheduleRetry(number, FIXED_INTERVAL)
}
Enter fullscreen mode Exit fullscreen mode

One N. One interval. Applied to every carrier.

With the spread above, a single N is wrong in both directions at once. Tuned for UPS, it flags most Australia Post shipments as suspect - they are not, they simply have not surfaced. Tuned for Australia Post, it is so permissive that a genuinely stuck UPS parcel sits unnoticed for a week.

The same bug shows up in the retry schedule. An empty response from a carrier with a 97% answer rate is informative: it probably means pre-transit, and the first scan is likely imminent, so a tighter poll pays. An empty response from a 20% carrier is mostly uninformative about the parcel, and polling it harder buys nothing except rate limits.

Three states, not one

The fix is to stop collapsing distinct conditions into events.length === 0:

  1. Pre-transit. The label exists; nothing has been scanned. The number is valid and the parcel is real, it just has not entered the network. This is the majority of empty responses on every carrier.
  2. Not visible here. The number belongs to a network whose history is not reachable from where you are standing. Nothing is wrong with the parcel; you are querying the wrong source.
  3. Not a carrier number. An order reference, an internal ID, a reused string. It will never resolve anywhere, no matter how long you retry.

These need different handling, and critically, different copy. State 1 deserves "the carrier has not scanned it yet". State 2 deserves "check the carrier's own site". State 3 deserves "this does not look like a tracking number - here is what one looks like for this carrier". A single "No tracking information available" string for all three is how you generate tickets.

Practical rules that fell out of this

Keep per-carrier baselines, not one global threshold. Store the observed answer rate and median time-to-first-scan per carrier, and derive your retry interval and your "suspect" threshold from those. The same two lines of config, applied per carrier, removes most false alerts.

Use the shape as a cheap pre-filter. Validating at ingest catches state 3 before you ever make a request. UPS is 1Z plus sixteen alphanumerics, eighteen total, with a trailing check digit - a mistyped one fails arithmetic, not a lookup. FedEx numbers are overwhelmingly twelve digits. A regex and a checksum at the input boundary is cheaper than an infinite retry loop.

Measure delivery windows instead of quoting service levels. For parcels still moving when first tracked, we measure medians of roughly 2 days (FedEx), 4 days (UPS) and 6 days (Australia Post), with 80th percentiles of about 6, 7 and 13 days. Carrier marketing pages will not give you those numbers, and your "is this late?" logic needs percentiles, not brochures.

Treat p80, not the median, as your alert threshold. Half of all parcels are slower than the median by definition. Alerting there means alerting on half your shipments.

The part that is not technical

Having done the measurement, we changed the product to match it. On carrier pages where we rarely resolve numbers, the page now says so at the top, in plain words, instead of promising real-time updates it cannot deliver. It costs clicks. It is still correct, because a user sent away with a true answer is worth more than one kept on a page that was never going to help.

Your API should do the same thing. Return a state your caller can branch on, not an empty array that forces them to guess.


I work on 24hTrack (24htrack.com), a free package tracker for 3,200+ carriers - paste any tracking number, the carrier is detected automatically, no sign-up. There is a REST API and MCP server if you want to consume this programmatically, and the longer write-up of the measurement is here.

Top comments (0)