Skip to main content

Funnel Navigation

tagada.funnel.navigate() takes the cart from the loaded checkout session, bootstraps an anonymous CMS session, and returns a redirect URL into a specific funnel step. It’s the JS equivalent of the WooCommerce / Shopify checkout plugins — one call from your own site, one URL to redirect to.
When to use it:
  • The cart lives in your store (Shopify, WooCommerce, PrestaShop, custom) and you want to route the shopper into a TagadaPay marketing funnel.
  • You want the shopper to enter at a specific funnel step (step_xxx) rather than the funnel default.
When NOT to use it:
  • You’re building a fully self-hosted checkout page — use Checkout Flow directly. Do not follow createSession().checkoutUrl.
  • You only need a one-shot Tagada-hosted checkout link without a funnel — use tagada.checkout.createSession() and follow its checkoutUrl.
  • You need a self-hosted checkout URL with no funnel — use tagada.checkout.createSessionUrl() so the shopper stays on your origin.

Prerequisites

accountId is required on createHeadlessClient()funnel.navigate() will throw TagadaError('missing_account_id') without it. A checkout session must be loaded first (tagada.checkout.loadSession(...)). The SDK sources the cart, currency, customer email, and promotion code from that session.
React provider: TagadaHeadlessProvider only forwards accountId through the full config prop, not the individual named props. Pass config={{ storeId, accountId, environment }} if you need funnel navigation in React.

Quick Start


What Happens Under the Hood

navigate() runs the same sequence the WooCommerce plugin does, with caching so repeat calls in the same page are cheap:
  1. POST /api/v1/cms/session/anonymous — creates an anonymous CMS session, returns a token.
  2. POST /api/v1/cms/session/v2/init — initializes the CMS session and binds a CMS customer id.
  3. POST /api/v1/funnel/initialize — creates the funnel session for funnelId + stepId.
  4. POST /api/v1/funnel/navigate — fires an INIT_CHECKOUT event with the cart and returns { url }.
The CMS token, session id, and customer id are cached on the module instance. Calling navigate() again in the same page skips steps 1–3.

Carrying Your Own Shipping Amount

If your storefront already charges its own shipping, pass externalShipping so the shopper is charged the amount they agreed to instead of whatever rate the platform would auto-select:
The checkout session starts on a rate matching that exact amount — an existing rate if one matches, otherwise a dynamically created one.
Only send this once shipping is genuinely resolved. { amount: 0 } means free shipping and pins a free rate — it is not a stand-in for “not known yet”. While shipping is unresolved, omit the field entirely and the platform selects a rate as before.

Keeping your rate when the checkout re-evaluates shipping

The hosted checkout re-evaluates shipping rates when the page loads, when the shopper changes country, and when discount codes move the cart across a rate’s amount bracket. If the rate your storefront picked stops matching the store’s rate conditions — for example a “10under10 under 150” rate on a cart whose catalogue price is $170 before the discount — the checkout swaps it for an eligible one. If your storefront is the authority on shipping, opt out of that re-selection by sending lockShippingRate: true in metadata alongside your pre-selected rate:
With the lock set:
  • The checkout keeps the pre-selected rate on load, on country changes and on discount changes; it never auto-selects another one.
  • The shipping selector shows that single rate and the shopper cannot change it.
  • The lock only applies once a rate is actually on the session (externalShipping, or a later setShippingRate call). With no rate yet, the checkout behaves as if the flag were absent.
Leave the flag off when you want the platform’s own rate rules — brackets, country restrictions, highlighted rate — to drive the selection.

Return Value

The SDK does not perform the redirect — call window.location.assign(url), router.push(url), or whatever your framework uses.

Errors

funnel.navigate() throws typed TagadaErrors:
  • no_cart_loadedsdk.checkout.loadSession(...) was not called first. The SDK has no cart to send.
  • missing_account_idaccountId was not provided on createHeadlessClient() and not passed per call.
Network and validation failures throw the standard TagadaNetworkError / TagadaValidationError.

SSR & Non-Browser Environments

The SDK reads globalThis.location?.href for currentUrl when running in a browser. In SSR / Node contexts, pass currentUrl explicitly:
Because navigate() returns { url } rather than redirecting, it composes cleanly with SPA routers (react-router, next/router) and server-side handoffs.
Funnel navigation vs. checkout.createSessionUrl(): Use funnel.navigate() to enter a marketing funnel (pre-checkout steps, upsell sequencing). Use checkout.createSessionUrl() when you just need a self-hosted checkout URL with no funnel logic in front of it.