Developer guides

Build a private order tracking page in Next.js

For teams building a customer account or order-status page in Next.js.

By Trace · Reviewed

The important boundary in an order tracking page is between the browser and the merchant account. Your Trace API key grants access to your account, so the buyer must never receive it. A tracking number or an order reference is also not an authorization credential.

Resolve the signed-in buyer and their order on your server, then retrieve the matching stored shipment. Trace owns the shipment record inside your Trace account; your application owns the mapping from that record to a particular buyer.

Put authorization before the upstream call

A Server Component or server route should resolve the buyer session, load an order owned by that buyer and then obtain the saved Trace shipment ID. Check ownership in the database query itself. A client-supplied shipment ID must not select arbitrary records using your merchant key.

Architecture sketch · adapt to your own session and database

Browser requests an order page
  → server verifies the customer session
  → database finds order WHERE owner = current customer
  → server reads the mapped Trace shipment ID
  → GET /v1/shipments/:id using a server-only API key
  → allowlisted status and event fields render to the buyer

Avoid cross-customer caching

Authenticated shipment data must not use a shared public page cache. Choose private response caching or no-store for the customer route and its upstream request; review framework and CDN behavior together. A cache key based only on /tracking is unsafe when the response contains a specific order.

Static marketing guides can be indexed. Customer order routes should be excluded from indexing and protected by authentication. Robots directives are not access control: a request that knows the URL must still fail authorization when it belongs to another buyer.

Render stored evidence and refresh deliberately

Reading a shipment record is different from making a new tracking lookup. A newly created record may still await its first verified observation. Render that state explicitly, along with the last verification time and any monitoring error, rather than treating record creation as shipment movement.

A customer refresh button should be rate limited in your application and should not start an unbounded loop of live requests. Source failures, quota postponement and a genuinely unchanged carrier timeline deserve different messages. Preserve the last verified snapshot with its age when appropriate.

Exercise the account boundary with two buyers

Use two test buyers with separate orders and try substituting one order ID into the other session. Repeat with the underlying shipment ID, an expired session and a logged-out request. Inspect the browser bundle and network responses for secrets.

  • Buyer A cannot read buyer B’s order even when the order reference is known.
  • Shared caches do not replay an authenticated response to another session.
  • An unavailable carrier leaves an honest status message, not a fabricated delivery.
  • A null UTC scan time renders as source-local text rather than a guessed instant.

Common questions

Can I use a NEXT_PUBLIC_ variable for the Trace API key?

No. Keep the key in a server-only environment variable. Public variables can be included in browser JavaScript.

References & next steps

Implementation details were checked against Trace’s current API. External product details may change; verify the linked documentation before deciding.