Building a Branded Tracking Page for Your Store

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: