Upsell & Downsell Funnel
Time: ~10 minutes | Difficulty: Intermediate Build a complete post-purchase offer flow using the Node SDK. Customers check out, see an upsell offer, and either accept it (→ thank you) or decline it (→ cheaper downsell offer → thank you).This tutorial uses native checkout pages — no custom HTML or Plugin SDK deployment needed. TagadaPay auto-injects checkout, offer, and thank you pages when no plugin is assigned to a step.
Prerequisites
| Requirement | How to get it |
|---|---|
| Node.js 18+ | nodejs.org |
@tagadapay/node-sdk | npm install @tagadapay/node-sdk |
| API key | Dashboard → Settings → API Keys |
| A store with at least one payment processor | Merchant Quick Start |
What You’ll Build
A 4-step funnel with conditional routing based on offer acceptance:| Step | Type | Purpose |
|---|---|---|
| Checkout | checkout | Payment page — collects card info, processes the initial order |
| Upsell | offer | Post-purchase offer — VIP Coaching Pack ($99) |
| Downsell | offer | Fallback offer if upsell is declined — Quick-Start Guide ($19) |
| Thank You | thankyou | Order confirmation — fires conversion events |
{ when: 'offer.accepted' }— customer accepted the offer{ when: 'offer.declined' }— customer declined the offer
Step 1: Initialize the SDK
Step 2: Create products
You need three products — one for the main checkout, one for the upsell, one for the downsell.Step 3: Create checkout offers
Checkout offers are standalone resources that you bind to funnel steps. Each offer references product line items via theirpriceId.
Use tagada.checkoutOffers.create() — this creates offers in the checkout offers table, which the native offer page can render.
Verify and list offers
Both upsell and downsell use
type: 'upsell' — they are post-purchase offers. For order bumps shown on the checkout page (before payment), use tagada.offers.create() with type: 'orderbump'.Step 4: Create the funnel with conditional edges
This is where the magic happens. Define four nodes and five edges withconditions.when to control the flow.
How conditional edges work
Each offer step has two possible outcomes: accepted or declined. The orchestrator checks the edge conditions to decide where to send the customer:Step 5: Activate the funnel
Creating a funnel defines the structure. Updating it triggers the routing engine — routes get mounted to CDN, pages become reachable.TagadaPay detects that your nodes have no
pluginId and automatically injects the native checkout plugin. The offer pages show the bound offer product, and the thank you page shows the order confirmation — no setup needed.Step 6: Verify and manage the funnel
Retrieve a funnel
List all funnels
Delete a funnel
Delete checkout offers
Complete Flow Diagram
- Checkout → Accept upsell → Thank You — Customer pays 99 = $148
- Checkout → Decline upsell → Accept downsell → Thank You — Customer pays 19 = $68
- Checkout → Decline upsell → Decline downsell → Thank You — Customer pays $49
Edge Conditions Reference
The funnel orchestrator supports a rich set of conditions you can attach to edges viaconditions.when. Use string format for simple conditions, or object format for conditions that take parameters.
Offer Conditions
| Condition | Format | Description |
|---|---|---|
offer.accepted | string | Customer accepted the offer |
offer.declined | string | Customer declined the offer |
offer.acceptedWithId | object | Customer accepted a specific offer |
Payment Conditions
| Condition | Format | Params | Description |
|---|---|---|---|
payment.success | string | — | Payment succeeded |
payment.failed | string | — | Payment failed (error, declined, rejected) |
payment.amountGreaterThan | object | amount (cents) | Payment amount exceeds threshold |
Main Order Conditions
Evaluate the initial checkout order (the first order in the funnel).| Condition | Format | Params | Description |
|---|---|---|---|
mainOrder.exists | string | — | Main order was created |
mainOrder.hasProduct | object | productId or variantIds | Order contains a specific product |
mainOrder.totalGreaterThan | object | amount (cents) | Order total exceeds threshold |
Last Order Conditions
Evaluate the most recent order (from the current or previous step — could be an upsell or downsell order).| Condition | Format | Params | Description |
|---|---|---|---|
lastOrder.exists | string | — | Last order exists |
lastOrder.hasProduct | object | productId or variantIds | Last order contains a product |
lastOrder.totalGreaterThan | object | amount (cents) | Last order total exceeds threshold |
Customer Tag Conditions
Route based on tags attached to the customer (set via API or automations).| Condition | Format | Params | Description |
|---|---|---|---|
customer.hasTag | object | tag | Customer has an exact tag |
customer.hasTagPrefix | object | prefix | Customer has a tag starting with prefix |
customer.hasAnyTag | object | tags (comma-separated) | Customer has at least one of the tags |
customer.hasAllTags | object | tags (comma-separated) | Customer has all of the tags |
Customer Geo Conditions
Route based on the customer’s geographic location (detected automatically from IP).| Condition | Format | Params | Description |
|---|---|---|---|
customer.fromCountry | object | country (ISO code) | Customer is from a specific country |
customer.fromContinent | object | continent (code) | Customer is from a continent (EU, NA, SA, AS, AF, OC, AN) |
customer.fromEU | string | — | Customer is from the European Union |
Customer Device & Browser Conditions
Route based on the customer’s device, browser, or display mode.| Condition | Format | Params | Description |
|---|---|---|---|
customer.onMobile | string | — | Customer is on a mobile device |
customer.withBrowser | object | browser | Browser name (chrome, firefox, safari, edge) |
customer.withLocale | object | locale | Browser locale (e.g., en-US, fr-FR) |
customer.isChromeFamily | string | — | Chrome, Edge, Brave, or Opera |
customer.isStandalonePWA | string | — | Installed PWA (standalone mode) |
customer.isAppleSilicon | string | — | Apple Silicon Mac (M1/M2/M3) |
Traffic & Bot Conditions
Route based on traffic source or bot detection.| Condition | Format | Params | Description |
|---|---|---|---|
customer.fromUtmSource | object | source | UTM source (facebook, google, email, etc.) |
customer.isBot | string | — | Detected as a bot or crawler |
Generic Conditions
| Condition | Format | Description |
|---|---|---|
always | string | Always evaluates to true — use as fallback |
Edge Priority
When multiple edges leave the same node, usepriority to control evaluation order. Higher priority edges are checked first:
Going Further
Add an order bump on the checkout step
Order bumps appear on the checkout page, before payment. UsestepConfig.orderBumps with mode: 'custom' to pick specific bumps:
Chain multiple offers
Add more offer steps between checkout and thank you. Each can have independent accept/decline routing:Geo-based routing
Show different offers based on customer location:Generate a checkout link
Use checkout sessions to create pre-loaded cart links:SDK Methods Reference
Funnels
| Method | Description |
|---|---|
tagada.funnels.create(params) | Create a funnel with nodes and edges |
tagada.funnels.update(id, params) | Update config and activate routing |
tagada.funnels.retrieve(id) | Get a funnel by ID |
tagada.funnels.list(storeId) | List all funnels for a store |
tagada.funnels.del(id, storeId) | Delete a funnel and its routes |
Checkout Offers
| Method | Description |
|---|---|
tagada.checkoutOffers.create(params) | Create a post-purchase offer |
tagada.checkoutOffers.retrieve(id) | Get a checkout offer by ID |
tagada.checkoutOffers.list(params) | List offers for a store |
tagada.checkoutOffers.del(params) | Delete one or more offers |
Next Steps
Funnel Orchestrator
Deep dive into funnel concepts — nodes, edges, routing, analytics
Step Config Guide
Configure payment methods, pixels, scripts, and order bumps per step
Funnel Pages
Three ways to build pages: native, custom HTML, or Plugin SDK
Merchant Quick Start
Full setup from processor configuration to live checkout
