Every time a customer clicks a carrier’s tracking link, they leave your site. That’s a missed opportunity for engagement, branding, and reducing support load. A branded tracking page keeps customers on your domain and provides a better experience. Let’s build one.

Why Build a Branded Tracking Page?

The Problem with Carrier Tracking Pages

When you send customers to the carrier’s tracking page:

  • They leave your brand experience
  • They see the carrier’s ads, not your promotions
  • They can’t easily contact your support team
  • If tracking looks confusing, they blame you — not the carrier

The Benefits of a Branded Page

BenefitImpact
Keep customers on your site+15% repeat page views
Reduce support tickets-40% tracking inquiries
Upsell opportunitiesShow related products
Brand consistencyProfessional experience
Data collectionTrack customer engagement

Architecture

Customer clicks tracking link
         ↓
Your branded tracking page
         ↓
JavaScript fetches tracking data from your API
         ↓
Your API calls WhereParcel → Returns standardized data
         ↓
Render tracking timeline + brand elements

Step 1: Backend API Endpoint

Create an API endpoint that proxies WhereParcel requests:

// routes/tracking.js
const express = require('express');
const router = express.Router();

router.get('/api/track/:trackingNumber', async (req, res) => {
  const { trackingNumber } = req.params;

  try {
    // Look up order by tracking number
    const order = await db.orders.findByTracking(trackingNumber);

    // Fetch tracking data from WhereParcel
    const tracking = await fetch('https://api.whereparcel.com/v2/track', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.WHEREPARCEL_API_KEY}:${process.env.WHEREPARCEL_SECRET_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        trackingItems: [{ carrier: order?.carrier || 'auto', trackingNumber }],
      }),
    }).then(r => r.json());

    res.json({
      order: order ? {
        id: order.id,
        items: order.items.map(i => ({
          name: i.name,
          image: i.imageUrl,
          quantity: i.quantity,
        })),
      } : null,
      tracking: tracking.data,
    });
  } catch (error) {
    res.status(500).json({ error: 'Unable to fetch tracking data' });
  }
});

module.exports = router;

Step 2: Tracking Page HTML

Create the tracking page structure:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Track Your Order | YourStore</title>
  <style>
    /* See Step 4 for full styles */
  </style>
</head>
<body>
  <header class="tracking-header">
    <a href="/" class="logo">
      <img src="/logo.svg" alt="YourStore" />
    </a>
    <a href="/support" class="support-link">Need help?</a>
  </header>

  <main class="tracking-container">
    <!-- Search form (if no tracking number in URL) -->
    <div id="search-section" class="search-section">
      <h1>Track Your Order</h1>
      <form id="tracking-form">
        <input
          type="text"
          id="tracking-input"
          placeholder="Enter your tracking number"
          required
        />
        <button type="submit">Track</button>
      </form>
    </div>

    <!-- Results -->
    <div id="results-section" class="results-section" style="display:none">
      <div id="status-banner" class="status-banner"></div>
      <div id="order-items" class="order-items"></div>
      <div id="tracking-timeline" class="tracking-timeline"></div>
    </div>

    <!-- Loading state -->
    <div id="loading" class="loading" style="display:none">
      <div class="spinner"></div>
      <p>Fetching tracking information...</p>
    </div>
  </main>

  <footer class="tracking-footer">
    <p>&copy; 2026 YourStore. All rights reserved.</p>
  </footer>

  <script src="/tracking.js"></script>
</body>
</html>

Step 3: Frontend JavaScript

Fetch and render tracking data:

// public/tracking.js

const STATUS_CONFIG = {
  pending: { label: 'Pending', icon: 'clock', color: '#6b7280' },
  info_received: { label: 'Info Received', icon: 'file', color: '#3b82f6' },
  picked_up: { label: 'Picked Up', icon: 'package', color: '#3b82f6' },
  in_transit: { label: 'In Transit', icon: 'truck', color: '#f59e0b' },
  out_for_delivery: { label: 'Out for Delivery', icon: 'map-pin', color: '#8b5cf6' },
  delivered: { label: 'Delivered', icon: 'check-circle', color: '#10b981' },
  exception: { label: 'Exception', icon: 'alert', color: '#ef4444' },
};

// Check URL for tracking number
const urlParams = new URLSearchParams(window.location.search);
const trackingNumber = urlParams.get('tn');

if (trackingNumber) {
  document.getElementById('tracking-input').value = trackingNumber;
  fetchTracking(trackingNumber);
}

// Form submission
document.getElementById('tracking-form').addEventListener('submit', (e) => {
  e.preventDefault();
  const tn = document.getElementById('tracking-input').value.trim();
  if (tn) {
    // Update URL without reload
    window.history.pushState({}, '', `?tn=${tn}`);
    fetchTracking(tn);
  }
});

async function fetchTracking(trackingNumber) {
  const loading = document.getElementById('loading');
  const results = document.getElementById('results-section');
  const search = document.getElementById('search-section');

  loading.style.display = 'flex';
  results.style.display = 'none';

  try {
    const response = await fetch(`/api/track/${trackingNumber}`);
    const data = await response.json();

    if (!response.ok) throw new Error(data.error);

    renderResults(data);
    results.style.display = 'block';
  } catch (error) {
    results.innerHTML = `
      <div class="error-message">
        <h2>Unable to find tracking information</h2>
        <p>Please check your tracking number and try again.</p>
      </div>
    `;
    results.style.display = 'block';
  } finally {
    loading.style.display = 'none';
  }
}

function renderResults(data) {
  const { tracking, order } = data;
  const config = STATUS_CONFIG[tracking.status] || STATUS_CONFIG.pending;

  // Status banner
  document.getElementById('status-banner').innerHTML = `
    <div class="status-icon" style="background: ${config.color}20; color: ${config.color}">
      ${config.label}
    </div>
    <h2>${getStatusMessage(tracking.status)}</h2>
    ${tracking.estimatedDelivery
      ? `<p class="eta">Estimated delivery: ${formatDate(tracking.estimatedDelivery)}</p>`
      : ''}
  `;

  // Order items (if available)
  if (order?.items?.length) {
    document.getElementById('order-items').innerHTML = `
      <h3>Your Items</h3>
      <div class="items-grid">
        ${order.items.map(item => `
          <div class="item-card">
            <img src="${item.image}" alt="${item.name}" />
            <span>${item.name}</span>
            <span class="qty">x${item.quantity}</span>
          </div>
        `).join('')}
      </div>
    `;
  }

  // Timeline
  document.getElementById('tracking-timeline').innerHTML = `
    <h3>Tracking History</h3>
    <div class="timeline">
      ${tracking.events.map((event, i) => `
        <div class="timeline-event ${i === 0 ? 'latest' : ''}">
          <div class="timeline-dot"></div>
          <div class="timeline-content">
            <div class="event-time">${formatDateTime(event.timestamp)}</div>
            <div class="event-status">${event.description}</div>
            ${event.location ? `<div class="event-location">${event.location}</div>` : ''}
          </div>
        </div>
      `).join('')}
    </div>
  `;
}

function getStatusMessage(status) {
  const messages = {
    pending: 'Your order is being prepared',
    picked_up: 'Your package has been picked up',
    in_transit: 'Your package is on its way',
    out_for_delivery: 'Your package is out for delivery today!',
    delivered: 'Your package has been delivered',
    exception: 'There is an issue with your delivery',
  };
  return messages[status] || 'Tracking your package';
}

function formatDate(dateStr) {
  return new Date(dateStr).toLocaleDateString('en-US', {
    weekday: 'long', month: 'long', day: 'numeric',
  });
}

function formatDateTime(dateStr) {
  return new Date(dateStr).toLocaleString('en-US', {
    month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit',
  });
}

Step 4: Styling

Make it match your brand:

:root {
  --brand-primary: #4f46e5;
  --brand-secondary: #818cf8;
  --text-primary: #1f2937;
  --text-secondary: #6b7280;
  --bg-primary: #ffffff;
  --bg-secondary: #f9fafb;
  --border: #e5e7eb;
}

.tracking-container {
  max-width: 640px;
  margin: 0 auto;
  padding: 2rem 1rem;
}

.status-banner {
  text-align: center;
  padding: 2rem;
  background: var(--bg-secondary);
  border-radius: 12px;
  margin-bottom: 2rem;
}

.status-icon {
  display: inline-block;
  padding: 0.5rem 1rem;
  border-radius: 9999px;
  font-weight: 600;
  font-size: 0.875rem;
  margin-bottom: 0.75rem;
}

.timeline {
  position: relative;
  padding-left: 2rem;
}

.timeline::before {
  content: '';
  position: absolute;
  left: 7px;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--border);
}

.timeline-event {
  position: relative;
  padding-bottom: 1.5rem;
}

.timeline-dot {
  position: absolute;
  left: -2rem;
  top: 4px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--border);
  border: 3px solid var(--bg-primary);
}

.timeline-event.latest .timeline-dot {
  background: var(--brand-primary);
}

.event-time {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.event-status {
  font-weight: 500;
  color: var(--text-primary);
}

.event-location {
  font-size: 0.875rem;
  color: var(--text-secondary);
}

Step 5: Add Engagement Elements

Maximize the value of your tracking page:

function renderRecommendations(order) {
  if (!order) return;

  return `
    <section class="recommendations">
      <h3>You might also like</h3>
      <div class="product-grid">
        ${getRelatedProducts(order.items).map(product => `
          <a href="${product.url}" class="product-card">
            <img src="${product.image}" alt="${product.name}" />
            <span class="product-name">${product.name}</span>
            <span class="product-price">${product.price}</span>
          </a>
        `).join('')}
      </div>
    </section>
  `;
}

Collect Feedback

After delivery, ask for feedback:

if (tracking.status === 'delivered') {
  resultsHTML += `
    <section class="feedback-section">
      <h3>How was your delivery experience?</h3>
      <div class="rating-buttons">
        <button onclick="submitRating(5)">Excellent</button>
        <button onclick="submitRating(4)">Good</button>
        <button onclick="submitRating(3)">Average</button>
        <button onclick="submitRating(2)">Poor</button>
      </div>
    </section>
  `;
}

SEO Benefits

A branded tracking page also provides SEO benefits:

  • Increased time on site — Customers check tracking multiple times
  • Lower bounce rate — Customers stay on your domain
  • Internal linking — Link to products, blog posts, and support pages
  • Brand authority — Professional tracking experience builds trust

Summary

A branded tracking page is one of the highest-ROI projects you can build. It reduces support tickets, keeps customers engaged, creates upsell opportunities, and provides a professional experience. With WhereParcel’s API providing the tracking data, you can focus entirely on the frontend experience.

Key resources: