Page Flow
An upsell funnel is a chain of one or more upsell pages between the checkout and the receipt. The SDK uses meta tags and the ?ref_id= URL parameter to wire the chain together — no JavaScript routing required.
Page Anatomy
Every upsell page needs four pieces:
- The page is identified as an upsell page via
<meta name="next-page-type" content="upsell">. - The order is loaded via the
?ref_id=URL parameter (the SDK does this automatically). - One or more accept buttons or offer containers on the page.
- Redirect URLs for accept and decline.
<head>
<meta name="next-page-type" content="upsell">
<meta name="next-upsell-accept-url" content="/upsell-2">
<meta name="next-upsell-decline-url" content="/upsell-2">
<!-- optional: prevent the customer from going back to checkout -->
<meta name="next-prevent-back-navigation" content="true">
<script src="https://cdn.jsdelivr.net/gh/NextCommerceCo/[email protected]/dist/loader.js" type="module"></script>
</head>
<body>
<!-- Offer markup here -->
</body>Redirect URL Resolution
When an accept button is clicked, the SDK resolves the next URL in this order:
data-next-urlon the button itself<meta name="next-upsell-accept-url">(for accept) or<meta name="next-upsell-decline-url">(for decline)- If neither is present, the loading overlay is dismissed and the page stays put.
The current page's query parameters (including ref_id) are preserved automatically. You do not need to append ?ref_id=... to the redirect URL.
Multi-Step Funnel
Chain pages by setting the redirect URLs on each one. The order context (refId, completedUpsells, upsellJourney) persists across pages via sessionStorage, so the same order is carried through the entire chain.
<!-- /upsell-1 -->
<meta name="next-upsell-accept-url" content="/upsell-2">
<meta name="next-upsell-decline-url" content="/upsell-2">
<!-- /upsell-2 -->
<meta name="next-upsell-accept-url" content="/receipt">
<meta name="next-upsell-decline-url" content="/receipt">If a page has more than one offer with different next steps, override on the button itself:
<button
data-next-action="accept-upsell"
data-next-package-id="42"
data-next-url="/upsell-2-premium">
Premium track
</button>
<button
data-next-action="accept-upsell"
data-next-package-id="43"
data-next-url="/upsell-2-basic">
Basic track
</button>Prevent Back Navigation
To stop the customer from using the browser Back button to return to checkout (which would let them re-pay or change the order), add this to the first upsell page:
<meta name="next-prevent-back-navigation" content="true">The SDK pushes a guard state into history on load. If the customer presses Back, the browser navigates forward again, keeping them on the current page.
Use this only on the first upsell page. Adding it to every page traps the customer in the funnel and gives them no way out.
Tracking Customer Journey
The SDK records every accept and skip into orderStore.upsellJourney. Each entry has the package ID, page path, action (viewed, accepted, skipped), and timestamp. Read it from JavaScript:
window.nextReady.push(() => {
const journey = window.next.getCompletedUpsells();
console.log('Already accepted:', journey);
});| Method | Description |
|---|---|
next.canAddUpsells() | true when the order is loaded and supports upsells |
next.getCompletedUpsells() | Array of package IDs already accepted in this session |
The journey is also used for duplicate detection — if a customer hits Back and revisits the same offer, the duplicate dialog appears before re-submitting.
bfcache Recovery
When the customer presses the browser Back button, modern browsers may restore the page from the back/forward cache. Both upsell enhancers handle this:
- The loading overlay from any in-flight click on the previous page view is dismissed.
- All accept buttons are re-enabled.
- The customer can interact with the page normally, without a stale "loading" state.
You do not need to handle bfcache yourself.
Page Type Tracking
When the page has <meta name="next-page-type" content="upsell">, the SDK records the page view in orderStore.upsellJourney with action viewed and emits the upsell:viewed event. Each unique page path is tracked at most once per page load — refreshing the page does not log a duplicate view.
Next Steps
- All meta tags: Reference → Attributes
- All events emitted during the flow: Reference → Events
- CSS classes for skipped, processing, and success states: Reference → CSS