Order Tracking
The public /order-tracking page, where customers look up an order and see its full history, carrier scans and a map.
Order Tracking
Customers check an order at /order-tracking without signing in. There are two ways to look one up:
| Lookup | What it shows |
|---|---|
| Order number + the phone number on the order | Everything: the full order history, the shipment, the map, the items and the ship-to city |
| Tracking number alone | The shipment only, at /track/<number>: carrier, scans and map. No emails, notes or items, because tracking numbers are printed on boxes and shared freely |
The phone can match any phone on the order: the guest phone, the account phone, or the shipping or billing address phone. Formatting doesn't matter, but all ten digits must match. A wrong phone and a missing order return the same message, so the form can't be used to find out which order numbers exist. Lookups are rate-limited to 10 per IP every 10 minutes.
A successful lookup goes to /order-tracking/<orderNumber>?token=…. The token is the same order access token checkout already uses (lib/orders/access-token.ts), so the link keeps working and can be shared with someone else in the household. The page is noindex.
Order history
Newest first, built by lib/order-tracking/timeline.ts from:
- Order received, from the order's creation time.
- Payment received, for each payment that was paid.
- Status changes (for example Status: Processing), from the audit log the admin status dialog writes. Only the new status is shown, never the admin note.
- Notes and delays staff post with Post Customer Update on the admin order page. These are stored in
OrderCustomerUpdateand kept apart fromOrder.adminNotes, which stays private. - Emails from the customer, from the inbound email sweep (see Customer Email Triage): anything linked to the order, plus anything from the order's email address since the order was placed. The page shows the subject and the first line the customer wrote.
- Emails we sent, from the email log, when the subject names the order number.
- Shipped, carrier scans (with city and state) and delivered.
Shipment, map and live updates
Both tracking pages open with a map of where the salsa is (components/order-tracking/ShipmentMap.tsx, built with Leaflet on OpenStreetMap tiles; no Google, no API key, no per-request charge):
- A salsa bowl marks where the package was last seen. Until the carrier scans it, that is Jose Madrid Salsa headquarters, 601 Putnam Ave, Zanesville, OH. The caption says whether the order is still being packed or is waiting for pickup.
- A red pin marks the destination, on the order page only. The tracking-number page leaves it out, because anyone holding a tracking number can open that page.
- A blue line traces the route so far: headquarters, then each place the carrier scanned the package, in order. Repeated scans in one place collapse into one stop. Once delivered, the line ends at the destination and the bowl moves there.
Carriers report a city, state and zip, not coordinates, so each scan is placed at that zip or city. Places are geocoded with OpenStreetMap's Nominatim (lib/order-tracking/geocode.ts), which is free but allows one request a second, so every answer, including "no match", is cached forever in the geocoded_places table and a place is only ever sent to the geocoder once. Because the page is rendered on the server, each render spends at most about three seconds on uncached lookups (and stops after the first failure); places that don't fit are placed on a later refresh, so a slow geocoder delays stops on the map, never the page. Headquarters is geocoded the same way, with hard-coded coordinates as a fallback. If the table is missing (the migration has not been applied), the map still draws headquarters and skips the geocoder rather than calling it on every view.
Carrier scans arrive through the EasyPost tracker.updated webhook (app/api/webhooks/easypost). Labels bought through EasyPost already have a tracker. A tracking number entered by hand gets one the first time its tracking page is viewed: the page registers an EasyPost tracker, saves the current scans, and the webhook keeps the order up to date from then on. This needs SHIPPING_API_KEY with EasyPost as the shipping provider.
Both tracking pages refresh themselves every minute while the tab is open, and stop once the order is delivered, cancelled or refunded.
Text alerts
The opt-in form is built but hidden until ORDER_SMS_ALERTS_ENABLED=true. Each opt-in is stored in OrderSmsSubscription with the exact consent text, time and IP, as carriers and the TCPA require. Sending isn't wired up yet; turn the flag on only once an SMS provider is connected.
How is this guide?
Last updated on