DEV Community

24hTrack
24hTrack

Posted on Fully Autonomous

Why your shipment-tracking logic breaks on cross-border parcels

If you are building order pages, delivery ETAs, "where is my order" emails or a support bot, you almost certainly modelled a shipment as one carrier, one number, a handful of scans. That model holds for domestic parcels and quietly falls apart the moment the parcel crosses a border.

Here is the short version: a cross-border parcel is normally two carriers and around twenty events, and the origin carrier stops reporting halfway through. Every downstream bug — stale statuses, false "stuck" alerts, angry support tickets — comes from that one mismatch.

How many events should you expect?

Average tracking events per shipment, from parcels tracked on 24hTrack between 2026-03-20 and 2026-08-19:

Carrier Typical route Avg. events
Royal Mail Domestic UK 4.4
UPS Mostly domestic 4.8
Evri Domestic UK 8.5
USPS Domestic US 10.2
Cainiao Cross-border 18.1
Yanwen Express Cross-border 18.8
China Post Cross-border 21.6
India Post Cross-border 23.4

Roughly 4–5 events domestic, 18–22 cross-border. If your UI renders a timeline, it needs to collapse gracefully at twenty rows, not five. If you diff event lists to detect change, you are doing it ~4× more often than you sized for.

The bug that actually bites: the handover

An international parcel is handed to a different company for the last leg. The origin carrier no longer has the parcel, so it stops adding scans — usually after something unhelpfully vague like handed over to local partner.

If you poll the origin carrier only, this is what your system sees:

day 0   label created
day 2   collected
day 4   export customs cleared
day 5   departed on airline
day 9   arrived at destination
day 11  handed over to local partner    <-- last event, forever
day 25  (still nothing)
Enter fullscreen mode Exit fullscreen mode

Your code concludes: stalled 14 days, raise an exception, email the customer. Reality: it was delivered on day 14 — those scans just live on the local courier's system, sometimes under a different number.

Two rules that prevent most of this:

  1. Treat "no updates" as meaningful only after a destination-country scan. Silence over an ocean or in a customs queue is expected and produces no scans at all. Silence after the parcel is demonstrably in the buyer's country is the signal worth alerting on.
  2. Never hardcode one global staleness threshold. Which brings us to the second table.

Stop using a single "late" threshold

Median and 80th-percentile days from first carrier scan to delivery scan, same dataset:

Carrier Median 80th pct Spread
Cainiao 7.2 12.1 1.7×
USPS 9.4 12.7 1.4×
China Post 11.0 17.8 1.6×
AliExpress 12.4 16.3 1.3×
Yanwen Express 12.9 29.3 2.3×
YunExpress 13.3 19.0 1.4×
FXYL 22.8 26.8 1.2×

A flat if (days > 14) alert() fires on a completely healthy Yanwen parcel — one in five of them is still in transit at day 29 — while being far too patient for a domestic UPS shipment whose median is 4 days.

Use a per-carrier threshold at roughly the 80th percentile, and keep the median around to phrase the message: "typically about 13 days, and one in five takes longer" is a support reply that ends the conversation. "Your parcel is delayed" starts three more.

Also note the clock starts at the first carrier scan, not checkout. Sellers who sit on a label for four days before handing it over will blow any ETA you compute from order date.

Statuses are not a ladder

One more thing that breaks state machines: carriers do not emit a monotonic sequence. You will see Out for Delivery followed by In Transit the next morning (failed attempt, back to depot), customs entered twice (export and import), and the same physical event worded differently by each leg. Model status as "latest known state", not as a stage counter that only increments.

Getting both legs without building it

If you would rather not maintain carrier detection and two-leg stitching yourself, that is the problem 24hTrack solves: paste any tracking number and the carrier is detected automatically, with the full scan history in one timeline, free and with no sign-up. It covers 3,200+ carriers and follows the parcel past the local-courier handover.

For programmatic use there is a REST API with webhooks, and an MCP server (npm i 24htrack-mcp) so an AI assistant like Claude or Cursor can look up a parcel directly — see the tracking API guide. The alternatives worth comparing are 17TRACK, AfterShip, ParcelsApp and TrackingMore, which differ mainly in free tier and webhook model.

FAQ

How many tracking events does a cross-border parcel produce?
Around 18–22 on average, against 4–5 for a domestic parcel. A long event list is good visibility, not a sign of trouble.

Why does tracking stop updating mid-journey?
The origin carrier handed the parcel to a local courier and no longer has it, so its feed ends. The remaining scans exist on the other carrier's system.

What is a sensible "package is late" threshold?
Per-carrier, at about the 80th percentile of transit time, and only counted after a destination-country scan.

Can I get both legs from one tracking number?
Usually yes — a universal tracker such as 24hTrack detects the carrier from the number and stitches the legs into one timeline.


Written by the team behind 24hTrack. Figures come from real shipments tracked on the platform between 2026-03-20 and 2026-08-19 (transit time = first carrier scan to delivery scan, outliers under 6 hours and over 90 days excluded); the dataset is published as CC BY at package-tracking-guide. Drafted with AI assistance and reviewed by a human before publishing.

Top comments (0)