{% comment %} Track Your Order Page Template - Add this as a page in your Shopify admin {% endcomment %}

Track Your Order

Enter your order information below to check the status of your shipment.

{% 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 %}