{% comment %}
Track Your Order Page Template - Add this as a page in your Shopify admin
{% endcomment %}
{% comment %}
Backend Code for Tracking Proxy Endpoint - Create as a Shopify App
{% endcomment %}
{% comment %}
// tracking-proxy.js - This file is part of a Shopify app that you'll need to create
// This endpoint acts as a proxy between your store and shipping carriers
const express = require('express');
const router = express.Router();
const axios = require('axios');
// This is where you'll integrate with carrier APIs to get real-time tracking information
// Each carrier has its own API format and authentication requirements
// Map of supported carriers and their API configurations
const carrierAPIs = {
'usps': {
fetchTracking: async (trackingNumber) => {
// Replace with your USPS Web Tools API credentials
const uspsUserId = process.env.USPS_USER_ID;
const xml = `
`;
try {
const response = await axios.get('https://secure.shippingapis.com/ShippingAPI.dll', {
params: {
API: 'TrackV2',
XML: xml
}
});
// Parse XML response and convert to standardized format
// This is simplified - you'll need an XML parser in reality
return {
status: 'In Transit', // Extract from response
status_message: 'Your package is on its way',
events: [
// Parse events from the response
{
timestamp: '2023-05-01T09:30:00',
status: 'In Transit',
description: 'Package arrived at USPS facility',
location: 'Distribution Center, NY'
},
// More events...
]
};
} catch (error) {
console.error('USPS API error:', error);
throw new Error('Failed to fetch USPS tracking information');
}
}
},
'fedex': {
fetchTracking: async (trackingNumber) => {
// FedEx requires OAuth authentication
// First get an access token
try {
const authResponse = await axios.post('https://apis.fedex.com/oauth/token', {
grant_type: 'client_credentials',
client_id: process.env.FEDEX_CLIENT_ID,
client_secret: process.env.FEDEX_CLIENT_SECRET
}, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
const token = authResponse.data.access_token;
// Now make the tracking request
const trackingResponse = await axios.post('https://apis.fedex.com/track/v1/trackingnumbers', {
includeDetailedScans: true,
trackingInfo: [
{
trackingNumberInfo: {
trackingNumber: trackingNumber
}
}
]
}, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
// Convert FedEx response to standardized format
const trackData = trackingResponse.data.output.completeTrackResults[0].trackResults[0];
return {
status: trackData.latestStatusDetail.description,
status_message: trackData.serviceDetail.description,
events: trackData.scanEvents.map(event => ({
timestamp: event.date,
status: event.eventDescription,
description: event.exceptionDescription || '',
location: event.scanLocation.city + ', ' + event.scanLocation.stateOrProvinceCode
}))
};
} catch (error) {
console.error('FedEx API error:', error);
throw new Error('Failed to fetch FedEx tracking information');
}
}
},
'ups': {
fetchTracking: async (trackingNumber) => {
// UPS API implementation
try {
// UPS requires OAuth authentication
const authResponse = await axios.post('https://onlinetools.ups.com/security/v1/oauth/token',
'grant_type=client_credentials', {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${Buffer.from(
`${process.env.UPS_CLIENT_ID}:${process.env.UPS_CLIENT_SECRET}`
).toString('base64')}`
}
});
const token = authResponse.data.access_token;
// Make tracking request
const trackingResponse = await axios.get(
`https://onlinetools.ups.com/api/track/v1/details/${trackingNumber}`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Process the UPS response
const shipment = trackingResponse.data.trackResponse.shipment[0];
return {
status: shipment.currentStatus.description,
status_message: shipment.currentStatus.statusCode,
events: shipment.package[0].activity.map(activity => ({
timestamp: activity.date + 'T' + activity.time,
status: activity.status.description,
description: activity.status.description,
location: activity.location.address.city +
(activity.location.address.stateProvince ?
', ' + activity.location.address.stateProvince : '')
}))
};
} catch (error) {
console.error('UPS API error:', error);
throw new Error('Failed to fetch UPS tracking information');
}
}
},
// Add more carriers as needed
};
// Helper function to identify the carrier from name
const getCarrierHandler = (carrierName) => {
if (!carrierName) return null;
const name = carrierName.toLowerCase();
if (name.includes('usps') || name.includes('postal')) return carrierAPIs.usps;
if (name.includes('fedex')) return carrierAPIs.fedex;
if (name.includes('ups')) return carrierAPIs.ups;
// Default to null if carrier not supported
return null;
};
// API endpoint to fetch tracking information
router.get('/apps/tracking-proxy', async (req, res) => {
try {
const { tracking_number, carrier } = req.query;
if (!tracking_number) {
return res.status(400).json({
error: 'Missing tracking number'
});
}
// Get the appropriate carrier handler
const carrierHandler = getCarrierHandler(carrier);
if (!carrierHandler) {
// If carrier not supported, return a generic response
return res.json({
status: 'In Transit',
status_message: 'Tracking information is limited. Please check with the carrier directly.',
events: [
{
timestamp: new Date().toISOString(),
status: 'Shipment information received',
description: 'The carrier has been notified to pick up the package',
location: ''
}
]
});
}
// Fetch tracking information from the carrier
const trackingInfo = await carrierHandler.fetchTracking(tracking_number);
// Return the tracking information
return res.json(trackingInfo);
} catch (error) {
console.error('Tracking proxy error:', error);
return res.status(500).json({
error: 'Failed to fetch tracking information',
message: error.message
});
}
});
module.exports = router;
{% endcomment %}
{% comment %}
Webhook Implementation for Automated Tracking Updates
{% endcomment %}
{% comment %}
// tracking-webhook.js - Add this to your Shopify app
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const router = express.Router();
// Use raw body parser for webhook verification
router.use(bodyParser.json({
verify: (req, res, buf) => {
req.rawBody = buf;
}
}));
// Shopify webhook handler for fulfillment events
router.post('/webhooks/fulfillments/create', async (req, res) => {
try {
// Verify the webhook signature
const hmac = req.headers['x-shopify-hmac-sha256'];
const generatedHash = crypto
.createHmac('sha256', process.env.SHOPIFY_API_SECRET)
.update(req.rawBody)
.digest('base64');
if (hmac !== generatedHash) {
return res.status(401).send('Invalid webhook signature');
}
// Process the fulfillment event
const fulfillment = req.body;
// If the fulfillment has tracking info, store it in your database
if (fulfillment.tracking_number ||
(fulfillment.tracking_numbers && fulfillment.tracking_numbers.length > 0)) {
// Get tracking info from carrier API
const trackingNumber = fulfillment.tracking_number || fulfillment.tracking_numbers[0];
const carrier = fulfillment.tracking_company;
// Get the carrier handler
const carrierHandler = getCarrierHandler(carrier);
if (carrierHandler) {
try {
// Fetch tracking information
const trackingInfo = await carrierHandler.fetchTracking(trackingNumber);
// Store in database
await storeTrackingInfo({
order_id: fulfillment.order_id,
fulfillment_id: fulfillment.id,
tracking_number: trackingNumber,
carrier: carrier,
tracking_info: trackingInfo,
last_updated: new Date()
});
// Optionally, send notification to customer about tracking update
await sendTrackingUpdateNotification(fulfillment.order_id, trackingNumber, trackingInfo);
} catch (error) {
console.error('Error fetching tracking data for webhook:', error);
}
}
}
// Return 200 OK to acknowledge receipt of the webhook
return res.status(200).send('Webhook processed');
} catch (error) {
console.error('Webhook processing error:', error);
return res.status(500).send('Error processing webhook');
}
});
module.exports = router;
{% endcomment %}
Track Your Order
Enter your order information below to check the status of your shipment.