-
Notifications
You must be signed in to change notification settings - Fork 51
Add guidance for analytics scripts handling checkout prerendering #1043
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -377,11 +377,26 @@ function subscribeOnBodlEvents() { | |
if (typeof window.bodlEvents.checkout.checkoutBegin === 'function') { | ||
// run the checkoutBegin function to get the payload | ||
window.bodlEvents.checkout.checkoutBegin((payload) => { | ||
// log the event payload | ||
console.log( | ||
'window.bodlEvents.checkout.checkoutBegin ~ payload', | ||
payload | ||
); | ||
// Check if page is being prerendered before tracking analytics | ||
if (document.prerendering) { | ||
// Defer analytics tracking until page becomes active | ||
document.addEventListener('prerenderingchange', () => { | ||
console.log( | ||
'window.bodlEvents.checkout.checkoutBegin ~ payload (after prerendering)', | ||
payload | ||
); | ||
// Now trigger your actual analytics tracking | ||
// e.g., gtag('event', 'begin_checkout', payload); | ||
}, { once: true }); | ||
} else { | ||
// Page is already active, safe to track immediately | ||
console.log( | ||
'window.bodlEvents.checkout.checkoutBegin ~ payload', | ||
payload | ||
); | ||
// Trigger your actual analytics tracking | ||
// e.g., gtag('event', 'begin_checkout', payload); | ||
} | ||
}); | ||
} | ||
|
||
|
@@ -457,8 +472,83 @@ Accept: application/json | |
} | ||
``` | ||
|
||
## Handling prerendered pages | ||
|
||
When pages are prerendered using [Speculation Rules API](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API), BODL events may fire before users actually navigate to the page. This is particularly important for checkout analytics where premature event firing can skew conversion tracking. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
### Prerendering detection for BODL events | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
All BODL event handlers should check for prerendering before triggering analytics: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
```javascript | ||
function handleBodlEvent(eventName, payload) { | ||
if (document.prerendering) { | ||
// Page is being prerendered - defer analytics | ||
document.addEventListener('prerenderingchange', () => { | ||
// Now it's safe to trigger analytics | ||
triggerAnalytics(eventName, payload); | ||
}, { once: true }); | ||
} else { | ||
// Page is already active | ||
triggerAnalytics(eventName, payload); | ||
} | ||
} | ||
|
||
function triggerAnalytics(eventName, payload) { | ||
// Your analytics implementation here | ||
console.log(`Analytics event: ${eventName}`, payload); | ||
// e.g., gtag('event', eventName, payload); | ||
// e.g., fbq('track', eventName, payload); | ||
} | ||
``` | ||
|
||
### Updated BODL implementation with prerendering support | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
Here's an updated version of the example script that includes prerendering detection: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
```javascript | ||
function subscribeOnBodlEvents() { | ||
// Helper function to handle prerendering | ||
function handleBodlEvent(eventName, payload) { | ||
if (document.prerendering) { | ||
document.addEventListener('prerenderingchange', () => { | ||
console.log(`${eventName} ~ payload (after prerendering)`, payload); | ||
// Add your analytics tracking here | ||
}, { once: true }); | ||
} else { | ||
console.log(`${eventName} ~ payload`, payload); | ||
// Add your analytics tracking here | ||
} | ||
} | ||
|
||
if (!window?.bodlEvents) { | ||
console.log('BODL not available'); | ||
return; | ||
} | ||
|
||
// Checkout events with prerendering support | ||
if (typeof window.bodlEvents.checkout?.checkoutBegin === 'function') { | ||
window.bodlEvents.checkout.checkoutBegin((payload) => { | ||
handleBodlEvent('checkout.checkoutBegin', payload); | ||
}); | ||
} | ||
|
||
if (typeof window.bodlEvents.checkout?.orderPurchased === 'function') { | ||
window.bodlEvents.checkout.orderPurchased((payload) => { | ||
handleBodlEvent('checkout.orderPurchased', payload); | ||
}); | ||
} | ||
|
||
// Apply the same pattern to other BODL events as needed | ||
} | ||
|
||
window.addEventListener('load', subscribeOnBodlEvents, false); | ||
``` | ||
|
||
## Resources | ||
|
||
- [Scripts overview](/docs/integrations/scripts) | ||
- [REST Management API: Scripts reference](/docs/rest-management/scripts) | ||
- [Using Script Manager (Help Center)](https://support.bigcommerce.com/s/article/Using-Script-Manager) | ||
- [Speculation Rules API documentation](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API) | ||
- [Prerender pages guide](https://developer.chrome.com/docs/web-platform/prerender-pages#eagerness) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,6 +58,66 @@ The following table describes the locations you can associate with Scripts API o | |
|
||
To associate scripts with a checkout page, you need the [Modify Checkout Content OAuth scope](/docs/start/authentication/api-accounts#oauth-scopes). | ||
|
||
## Handling prerendered checkout pages | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
With the introduction of [Speculation Rules API](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API) and browser prerendering, checkout pages may be prerendered before users actually navigate to them. This can cause analytics and other event-tracking scripts to fire prematurely. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
When scripts inject into checkout pages, they should check whether the page is being prerendered to avoid triggering events before the user actually visits the page. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
### Detecting prerendering | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
Use the `document.prerendering` property to detect if the page is currently being prerendered: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
```javascript | ||
// Check if the page is currently being prerendered | ||
if (document.prerendering) { | ||
// Page is being prerendered - defer analytics tracking | ||
console.log('Page is being prerendered, deferring analytics'); | ||
|
||
// Listen for when prerendering ends and page becomes active | ||
document.addEventListener('prerenderingchange', () => { | ||
console.log('Page is now active, triggering analytics'); | ||
// Now it's safe to trigger analytics events | ||
triggerCheckoutAnalytics(); | ||
}); | ||
} else { | ||
// Page is not prerendered, safe to trigger analytics immediately | ||
triggerCheckoutAnalytics(); | ||
} | ||
``` | ||
|
||
### Example implementation for checkout analytics | ||
|
||
Here's a complete example that safely handles both normal page loads and prerendered pages: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
```javascript | ||
function initializeCheckoutAnalytics() { | ||
function triggerAnalyticsEvents() { | ||
// Your analytics tracking code here | ||
// e.g., fbq('track', 'InitiateCheckout'); | ||
// e.g., gtag('event', 'begin_checkout'); | ||
console.log('Checkout analytics triggered'); | ||
} | ||
|
||
if (document.prerendering) { | ||
// Defer analytics until page becomes active | ||
document.addEventListener('prerenderingchange', triggerAnalyticsEvents, { once: true }); | ||
} else { | ||
// Page is already active, trigger analytics immediately | ||
triggerAnalyticsEvents(); | ||
} | ||
} | ||
|
||
// Initialize when DOM is ready | ||
if (document.readyState === 'loading') { | ||
document.addEventListener('DOMContentLoaded', initializeCheckoutAnalytics); | ||
} else { | ||
initializeCheckoutAnalytics(); | ||
} | ||
``` | ||
|
||
For more information about prerendering detection, see the [Speculation Rules API documentation](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API) and the [prerender pages guide](https://developer.chrome.com/docs/web-platform/prerender-pages#eagerness). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
## Creating scripts for Catalyst storefronts | ||
|
||
Catalyst is BigCommerce's modern storefront framework built on Next.js. When creating scripts for Catalyst storefronts, there are several important considerations that differ from traditional Stencil themes. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -95,3 +95,91 @@ For instance, if you wanted a script for product reviews to load only on product | |
Sometimes scripts have logic that runs each time a page is visited. If you find that the script you install is working on the first page you visit, but not the second, it's likely dependent on additional logic like this. | ||
|
||
The `<Script/>` component has an `onReady` prop that accepts a function that will run every time a page is loaded, even if the script is already loaded. You can view more details about this property [on the Next.js docs](https://nextjs.org/docs/app/api-reference/components/script#onready). | ||
|
||
## Handling prerendered pages | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
With modern browsers supporting [Speculation Rules API](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API) for prerendering, pages (especially checkout pages) may be prerendered before users actually navigate to them. This can cause analytics scripts to fire prematurely. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
### Detecting prerendering in your scripts | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
When adding analytics or event-tracking scripts to Catalyst, you should check if the page is being prerendered: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
```tsx {1,8-19} filename="core/app/[locale]/(default)/layout.tsx" copy | ||
import Script from 'next/script'; | ||
|
||
export default function DefaultLayout({ children }) { | ||
return ( | ||
<> | ||
{children} | ||
<Script | ||
src="https://your-analytics-service.com/script.js" | ||
onReady={() => { | ||
// Initialize analytics with prerendering support | ||
if (typeof window !== 'undefined') { | ||
if (document.prerendering) { | ||
// Defer analytics until page becomes active | ||
document.addEventListener('prerenderingchange', () => { | ||
// Now it's safe to trigger analytics | ||
window.yourAnalytics?.track('page_view'); | ||
}, { once: true }); | ||
} else { | ||
// Page is already active | ||
window.yourAnalytics?.track('page_view'); | ||
} | ||
} | ||
}} | ||
/> | ||
</> | ||
); | ||
} | ||
``` | ||
|
||
### Example: Analytics script with prerendering support | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
Here's a complete example of adding an analytics script to checkout pages that properly handles prerendering: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
```tsx {1,25-39} filename="core/app/[locale]/(default)/checkout/page.tsx" copy | ||
import Script from 'next/script'; | ||
|
||
export default function CheckoutPage() { | ||
return ( | ||
<> | ||
{/* Your checkout page content */} | ||
<div>Checkout content...</div> | ||
|
||
{/* Analytics script with prerendering support */} | ||
<Script | ||
id="checkout-analytics" | ||
strategy="afterInteractive" | ||
dangerouslySetInnerHTML={{ | ||
__html: ` | ||
function initializeCheckoutAnalytics() { | ||
function triggerCheckoutEvents() { | ||
// Your analytics code here | ||
console.log('Checkout page analytics triggered'); | ||
// e.g., gtag('event', 'begin_checkout'); | ||
// e.g., fbq('track', 'InitiateCheckout'); | ||
} | ||
|
||
if (document.prerendering) { | ||
// Defer until page becomes active | ||
document.addEventListener('prerenderingchange', triggerCheckoutEvents, { once: true }); | ||
} else { | ||
// Page is already active | ||
triggerCheckoutEvents(); | ||
} | ||
} | ||
|
||
// Initialize when script loads | ||
initializeCheckoutAnalytics(); | ||
` | ||
}} | ||
/> | ||
</> | ||
); | ||
} | ||
``` | ||
|
||
This approach ensures that analytics events only fire when users actually visit the page, not when it's being prerendered in the background. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
For more information about prerendering, see the [Speculation Rules API documentation](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API) and the [prerender pages guide](https://developer.chrome.com/docs/web-platform/prerender-pages#eagerness). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prerendered
is misspeltretext-spell
retext-spell