Here’s the latest optimized version of your Builder.io conversion tracking script with minor enhancements, inline comments for clarity, and improved safety checks. The core logic is preserved, and functionality remains unchanged.
const BUILDER_STORAGE_KEY = 'builderPendingEvents';
const API_KEY = 'YOUR_API_KEY'
const MAX_RETRIES = 3;
const RETRY_DELAY = 1000;
// Helper function to safely get storage data
const getPendingEvents = () => {
try {
const stored = localStorage.getItem(BUILDER_STORAGE_KEY);
return stored ? JSON.parse(stored) : [];
} catch (e) {
console.error('Error reading pending events:', e);
return [];
}
};
// Helper function to safely store data
const storePendingEvent = (eventData) => {
try {
const events = getPendingEvents();
events.push(eventData);
localStorage.setItem(BUILDER_STORAGE_KEY, JSON.stringify(events));
} catch (e) {
console.error('Error storing pending event:', e);
}
};
// Helper function to remove stored events
const removePendingEvents = () => {
try {
localStorage.removeItem(BUILDER_STORAGE_KEY);
} catch (e) {
console.error('Error removing pending events:', e);
}
};
// Function to send tracking data to Builder.io
const sendToBuilder = async (eventData, retryCount = 0) => {
try {
console.log("Sending to Builder...", eventData);
const response = await fetch(
`https://cdn.builder.io/api/v1/track?apiKey=${API_KEY}`,
{
method: 'POST',
body: JSON.stringify({ events: [eventData] }),
headers: {
'content-type': 'application/json',
},
mode: 'cors',
keepalive: true,
}
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
console.log("Builder response:", response);
return true;
} catch (error) {
console.error('Tracking error:', error);
if (retryCount < MAX_RETRIES) {
await new Promise((resolve) =>
setTimeout(resolve, RETRY_DELAY * (retryCount + 1))
);
return sendToBuilder(eventData, retryCount + 1);
}
storePendingEvent(eventData);
return false;
}
};
// Main tracking function
const trackConversion = ({ amountInfo, meta = {} }) => {
console.log("Track Conversion Started...");
const sessionId = document.cookie
.split('; ')
.find((row) => row.startsWith('builderSessionId='))
?.split('=')[1] || null;
const variationId = document.cookie
.split('; ')
.find((row) => row.startsWith('builder.tests='))
?.split('=')[1] || null;
const visitorId = localStorage.getItem('builderVisitorId') || null;
console.log("Session ID:", sessionId);
console.log("Variation ID:", variationId);
console.log("Visitor ID:", visitorId);
console.log("Amount:", amountInfo.amount);
const eventData = {
type: 'conversion',
data: {
amount: amountInfo.amount,
metadata: {
sdkVersion: '3.2.10',
url: location.href,
currency: amountInfo.currencyCode,
timestamp: new Date().toISOString(),
...meta,
},
ownerId: API_KEY,
userAttributes: {
sessionId,
visitorId,
variationId,
},
sessionId,
visitorId,
},
};
console.log("Event data being sent:", eventData);
return sendToBuilder(eventData);
};
// ✅ Updated main event listener with `order_id` or fallback to `checkout.token`
analytics.subscribe('checkout_completed', (event) => {
console.log("Checkout Completed Event Received:", event);
if (!event.data || !event.data.checkout) {
console.error('Invalid checkout data received');
return;
}
const checkout = event.data.checkout;
console.log("Processing checkout:", checkout);
trackConversion({
amountInfo: checkout.totalPrice,
meta: {
additionalData: 'Conversion Recorded',
eventId: event.id,
clientId: event.clientId,
order_id: checkout.order?.id || `checkout_token:${checkout.token}`,
},
});
});
// Try to send pending events on page load
window.addEventListener('load', async () => {
const pendingEvents = getPendingEvents();
if (pendingEvents.length > 0) {
console.log("Processing pending events:", pendingEvents);
const results = await Promise.all(
pendingEvents.map((event) => sendToBuilder(event))
);
if (results.every(Boolean)) {
removePendingEvents();
}
}
});
// Backup tracking before page unload
window.addEventListener('beforeunload', () => {
const pendingEvents = getPendingEvents();
if (pendingEvents.length > 0) {
try {
navigator.sendBeacon(
`https://cdn.builder.io/api/v1/track?apiKey=${API_KEY}`,
JSON.stringify({ events: pendingEvents })
);
removePendingEvents();
} catch (e) {
console.error('Error sending beacon:', e);
}
}
});