How to Build E-Commerce Shipping Notifications
Customers expect to know exactly where their package is at all times. In fact, 93% of online shoppers say shipping tracking is important to their overall shopping experience. In this tutorial, we’ll build a complete shipping notification system using WhereParcel’s API.
What We’ll Build
By the end of this tutorial, you’ll have:
- Automatic tracking registration when orders ship
- Real-time status updates via webhooks
- Email and SMS notifications at key delivery milestones
- A customer-facing tracking page
Architecture Overview
Order Shipped → Register Tracking → WhereParcel API
↓
Webhook Events
↓
Your Notification Service
↓ ↓
Email SMS
Step 1: Register Tracking When Orders Ship
When your fulfillment system marks an order as shipped, register the tracking number with WhereParcel:
async function registerTracking(order) {
const response = 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, trackingNumber: order.trackingNumber }],
webhook: {
url: 'https://yourapp.com/webhooks/tracking',
events: ['status_changed', 'delivered', 'exception'],
},
}),
});
return response.json();
}
Step 2: Set Up the Webhook Endpoint
Create an endpoint to receive tracking updates:
app.post('/webhooks/tracking', async (req, res) => {
// Verify webhook signature
const signature = req.headers['x-webhook-signature'];
if (!verifySignature(req.body, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Respond immediately
res.status(200).json({ received: true });
// Process the event
const { event, data } = req.body;
await handleTrackingEvent(event, data);
});
Step 3: Handle Different Event Types
Map tracking events to customer notifications:
async function handleTrackingEvent(event, data) {
const order = await findOrderByTracking(data.trackingNumber);
if (!order) return;
switch (data.status) {
case 'picked_up':
await sendNotification(order.customer, {
title: 'Your order has been picked up!',
body: `Your package is on its way from ${data.location}.`,
});
break;
case 'in_transit':
await sendNotification(order.customer, {
title: 'Your package is in transit',
body: `Last seen at ${data.location}.`,
});
break;
case 'out_for_delivery':
await sendNotification(order.customer, {
title: 'Out for delivery!',
body: 'Your package will arrive today.',
});
break;
case 'delivered':
await sendNotification(order.customer, {
title: 'Package delivered!',
body: `Delivered at ${data.location}.`,
});
break;
case 'exception':
await sendNotification(order.customer, {
title: 'Delivery update',
body: `There's an update on your package: ${data.description}`,
});
break;
}
}
Step 4: Build a Tracking Page
Create a customer-facing tracking page that fetches the latest status:
app.get('/track/:trackingNumber', async (req, res) => {
const { trackingNumber } = req.params;
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: 'auto', trackingNumber }],
}),
}
);
const result = await tracking.json();
res.render('tracking', { tracking: result.data });
});
Step 5: Add Notification Preferences
Let customers choose how they want to be notified:
const notificationPreferences = {
email: true, // Always on by default
sms: false, // Opt-in
push: false, // Opt-in
milestones: [ // Which events to notify
'picked_up',
'out_for_delivery',
'delivered',
'exception',
],
};
Best Practices
-
Don’t over-notify — Customers don’t need an update for every sorting facility. Focus on key milestones: picked up, out for delivery, delivered, and exceptions.
-
Include tracking links — Every notification should link to your tracking page where customers can see the full timeline.
-
Handle carrier delays — If a package hasn’t moved in 48+ hours, proactively notify the customer rather than leaving them wondering.
-
Time zone awareness — Send notifications during the recipient’s business hours when possible.
-
Batch international updates — International shipments can have many events. Batch them into daily summaries rather than sending individual notifications.
Next Steps
- Set up webhook retry handling for reliability
- Learn about cross-border tracking for international orders
- Explore the full API documentation for advanced features