Articles · How toUpdated October 2026

Order tracking is a status field and a push. The Lock Screen version stops after eight hours.

Put a status on the order, and when the status changes have the server send a push to the devices that care. That is the whole feature, and the rest of this page is detail hung off those two moves. The detail that catches people out is the glanceable version. Apple documents a Live Activity as running for up to eight hours, so the tracker that follows a van down your street is not the same feature as the one that follows a parcel across a weekend. Every claim about Expo and Apple below comes from their own documentation, read on 23 October 2026. If the app itself does not exist yet, start at make an app.

What follows is the status model worth copying, what Expo documents for the push, what it now documents for the Lock Screen, and the eight hour ceiling that decides which of the two you reach for. One thing changed recently enough that most of the advice online is still wrong about it, and it is the Lock Screen half.

Start here

The short version

Build the status change first, and let everything hang off it.

The valuable object is the transition, not the screen. One place on the server writes a new status to an order and records when it happened. Everything a customer sees is a reader of that: the push body, the order screen, the row in their history, the Lock Screen activity while the van is out. Get the transition in one function and you can add a presentation later without touching the shop.

Get it in four places and you will ship a status that pushed nobody. That is the usual failure here, and it is not a mobile problem at all. It happens on the server, weeks before anyone opens a phone.

What does order tracking actually need?

Less than people build. A status on the order, from a short closed list. A row per transition with the time it happened, because the question a customer asks is when something shipped and you cannot answer that from a single mutable field. A device token stored against the customer. One server function that writes the new status and sends the message. An order number short enough to read down a phone line. That is the working set, and a shop running on those five things will beat one with a status machine nobody understands.

Two decisions are worth making before you write any of it. The first is who owns the status. If a carrier knows more about the parcel than your database does, then your statuses are a cache of theirs and you need a job that reconciles them, not a form a human updates. The second is what the customer is allowed to see. Internal statuses leak embarrassment. A warehouse has a reason to distinguish picked from packed from staged, and a customer reading all three learns only that nothing is moving.

Then the question is which statuses deserve to interrupt somebody. Not all of them do, and a shop that pushes on every transition teaches people to turn notifications off before the second order. The picker below is the shape of that conversation.

Plan yours

What to send at each status

Tick the statuses your orders really go through. Most shops have five or six and invent four more that nobody ever sets. The notes say what each one is worth sending, and whether it belongs on the Lock Screen at all.

Nothing ticked yet. If you are not sure which statuses you have, the answer is whichever ones a customer has phoned up to ask about.

How do you send a push when the order status changes?

Expo documents two routes, and the thing to know early is that they do not share a transport. The ordinary notification goes through Expo. The Lock Screen update does not.

For the ordinary notification, the device gets an ExpoPushToken through expo-notifications and your server posts the message to the Expo Push Service. Expo's page on sending notifications with that service, which carries a last modified date of 13 October 2026 and which we read on 23 October 2026, gives the endpoint as exp.host/--/api/v2/push/send and says the request body may be a single message object or an array of up to 100 message objects, as long as they are all for the same project. The response is a push ticket, and Expo is blunt that a ticket status of ok means the message reached Expo's servers rather than the person. You take the ticket id, come back for a push receipt, and act on what it says. Expo recommends waiting 15 minutes, notes receipts are cleared after 24 hours, and tells you that a receipt whose details error is DeviceNotRegistered means you stop sending to that token until it registers again.

The Lock Screen update is a different animal. Expo's expo-widgets reference documents it going straight to Apple Push Notification service: an apns-push-type header of liveactivity, an apns-topic of your bundle identifier followed by .push-type.liveactivity, and an aps payload carrying an event of start, update or end, a timestamp, and a content-state. For expo-widgets specifically, that content-state has to set a name matching the one you passed to createLiveActivity and a props field holding a JSON string of the activity props. Expo documents apns-priority 10 for an update you want immediately and 5 for a lower priority one, and notes that the date fields are Unix timestamps in seconds.

Two tokens, not one. The app-wide push-to-start token comes from addPushToStartTokenListener and lets your server start an activity remotely, which Expo documents as needing iOS 17.2 or later. Each running activity then has its own token, from getPushToken on the instance or an addPushTokenListener subscription, and that is the one an update goes to. Expo also notes that on iOS 18 or later you can include input-push-token set to 1 in the aps payload to have APNs hand back a fresh per-activity token for future updates.

Expo SDK reference, Widgets (expo-widgets), v58.0.0 reference, read 23 October 2026

Can the order sit on the Lock Screen without native code?

Yes, and this is the part worth re-reading if you looked into it a year ago. Expo ships expo-widgets, described in the v58.0.0 SDK reference as a library for building Android and iOS home screen widgets and iOS Live Activities using Expo UI components, without writing native code. The layout is Expo UI rather than hand written Swift: SwiftUI components on iOS, Jetpack Compose on Android. You call createLiveActivity once with a component marked by the 'widget' directive, and it returns a layout object with a region per presentation: banner for the Lock Screen, bannerSmall for CarPlay and watchOS, compactLeading, compactTrailing and minimal for the Dynamic Island, and the expanded regions for when somebody holds it.

The nicest thing about that page, if you are building this exact feature, is that Expo's own worked example is a delivery. The props are an eta in minutes and a status string. The statuses it walks through are the ones a courier app would use, from on the way, through almost there and arriving soon, to delivered. The expanded bottom region prints a driver name and an order number. The sample in the documentation is more or less your screen already, which is not something you can say about most features.

What to plan around, all of it from the same page. The widget runtime is isolated: code inside a widget marked component gets no React hooks, no app state and no asynchronous work, and may use only Expo UI components. Live Activities are iOS only here, along with timelines and configurable widgets, and on Android you use updateSnapshot to change what a widget shows. The library is not available in the Expo Go app, so Expo tells you to use a development build. createLiveActivity registers the activity at runtime and the library's own built-in Live Activity target renders it, so you must not add a widgets entry for it in the app config, because an entry without supportedFamilies generates an invalid widget target that fails to build. Remote updates need the config plugin option enablePushNotifications set to true, which adds the aps-environment entitlement on iOS, and frequentUpdates if you want the NSSupportsLiveActivitiesFrequentUpdates flag.

One behaviour here will bite you in testing. A Live Activity can outlive the app process that started it, so after a relaunch your code has no handle on the thing still glowing on the Lock Screen. Expo documents getInstances on the factory for exactly that: fetch the activities of that type that are currently active and update or end them. Without it you get a stale delivery that nobody can dismiss, which is the single worst outcome available in this feature.

Expo SDK reference, Widgets (expo-widgets), Live Activities section, read 23 October 2026

How long can a Live Activity run?

Eight hours, and Apple puts a number on every part of it. Its ActivityKit article says a Live Activity can be active for up to eight hours unless its app or a person ends it before that limit. After the eight hour limit the system automatically ends it and immediately removes it from the Dynamic Island. It then remains on the Lock Screen until a person removes it or for up to four additional hours, whichever comes first, so the maximum time a Live Activity stays on the Lock Screen is 12 hours. The same page adds that an ended activity with the default dismissal policy is cleared automatically four hours after it ended, and that although you can hand the after variant any date you like, the system clears the activity on that date or four hours after it ended, whichever comes first. Read on 23 October 2026.

Read that as the feature's scope rather than a defect. Next day delivery does not fit in eight hours and was never going to. What fits is the leg somebody would actually watch, which is the kitchen to the door or the hour around a delivery slot. The rest of the journey belongs to a push notification and an order screen, and trying to stretch one activity across it produces a Lock Screen card that silently dies in a warehouse overnight.

Two more limits from the same Apple page, both of which shape the design. Static and dynamic data for a Live Activity, including the data in ActivityKit updates and ActivityKit push notifications, cannot exceed a combined size of 4 KB. And each Live Activity runs in its own sandbox and, unlike a widget, cannot access the network or receive location updates. So the Lock Screen never refreshes itself. Every figure on it arrived from your app or from a push, which is why ActivityKit has a stale date: at the date you set, the activity state changes to stale and the view can admit that what it is showing is old. For a delivery, set it a little past the next update you expect, so a phone in a lift says so instead of lying.

Apple, ActivityKit, Displaying live data with Live Activities, read 23 October 2026

A push, a Live Activity and the order screen, side by side

Three surfaces, each good at a different span of time. The push owns the moment, the Live Activity owns the next few hours, the order screen owns the rest. Most order tracking that feels good uses all three and most that feels bad has picked one.

The jobA push notificationA Live ActivityThe order screen
Shows up without the app openYesYesNo
Still readable an hour after it arrivedNoYesNo
Can cover an order that takes two daysYesNo, eight hours and the system ends itYes
Can fetch the current status by itselfNoNo, it is sandboxed with no network accessYes
Documented size or batch ceilingUp to 100 messages in one request to the Expo Push Service4 KB for static and dynamic data combinedNo
Documented by Expo on AndroidYesNo, Live Activities are iOS only in expo-widgetsYes
Needs a native target inside the buildNoYes, though expo-widgets ships that target for youNo

Apple, ActivityKit, duration and asset constraints, read 23 October 2026

What it takes to ship this

The order list is the screen customers open, and it is mostly ordinary work. Two patterns carry it. A swipe on a row to mark one collected or to archive an old order, which is the subject of add swipe actions. And a list that rearranges itself under the reader as things move, which is the same problem people meet when they add leaderboards, and worth solving once.

Newly is an AI app builder for this kind of job. You describe the app in plain English and it writes a real React Native and Expo project that you own, with two way GitHub sync, so a library like expo-widgets installs the normal way and lives in your repository rather than behind somebody's feature flag. It uploads iOS builds to TestFlight, publishes to Google Play internal testing and builds a standalone Android APK. It costs $25 a month and there is no free tier. It will not press submit on the App Store for you, because Apple requires the owner of an app's content to submit it, so that step stays yours. How it goes is in publish to app store.

One thing not to build, to finish. Do not start the Live Activity when the order is placed. The eight hour clock starts when you call start, and on an order that ships tomorrow you will spend the whole allowance in a warehouse and have nothing left for the street. Start it when the order goes out for delivery. Update it when the eta moves. End it on delivery with a final state. Let a plain push cover everything before that, and the feature will behave the way people expect it to from the apps they already use.

Questions people ask about order tracking in an app

Expo documents two routes and they do not share a transport. For an ordinary notification you get an ExpoPushToken on the device with expo-notifications, then your server posts the message to the Expo Push Service. Expo's page on sending notifications with that service, last modified 13 October 2026 and read on 23 October 2026, gives the endpoint as exp.host/--/api/v2/push/send and says the body may be a single message object or an array of up to 100 message objects for the same project. For a Lock Screen Live Activity the push does not go through Expo's service at all. The expo-widgets reference documents sending it straight to Apple Push Notification service with an apns-push-type header of liveactivity, an apns-topic of your bundle identifier followed by .push-type.liveactivity, and an aps payload carrying an event of start, update or end.

Write down the statuses. The app can follow them.

List the statuses an order really goes through, mark the ones worth interrupting somebody for, and note which leg of the journey takes under eight hours. That list is the brief for the whole feature, and it fits on the back of a delivery note.

Start building