Getting Started
Campaigns are fully custom checkout funnels — landing, checkout, upsell, and receipt pages — backed by a CORS-enabled API that handles products, pricing, payments, and order creation. No backend integration required.
The fastest path from zero to a working funnel on localhost is the Campaign Page Kit: a CLI that scaffolds an SDK-ready starter template, runs a hot-reload dev server, and outputs a static site you can deploy to Netlify, Cloudflare Pages, Vercel, or any static host.
Quick Start
1. Prerequisites
- Node.js 18+
- A Next Commerce store with a campaign created in the Campaigns App
- Your Campaign API key — find it under your campaign's Integration tab
2. Initialize a new project
In a fresh directory:
mkdir my-campaigns && cd my-campaigns
npm init -y
npm install next-campaign-page-kit
npx campaign-initcampaign-init walks you through everything in one prompt-driven flow:
- Pick a starter template (see Starter templates below)
- Enter your campaign name and slug (the URL path, e.g.
/my-campaign/) - The template is downloaded into
src/<slug>/and registered in_data/campaigns.json - CLI scripts (
dev,build,clone,config,compress) are added to yourpackage.json - Optionally, your API key is written to
assets/config.js - Optionally, an AI context doc is installed for Claude Code, Cursor, Codex, or Copilot
AI-ready out of the box
The --ai-context step writes the right context file to the right path for your assistant — CLAUDE.md, AGENTS.md, .cursor/rules/, or .github/copilot-instructions.md. Your AI editor will know the project structure, Liquid filters, and SDK conventions immediately.
Skipping the API key during init is fine — run npm run config later to set it.
3. Start the dev server
npm run devThis opens your campaign's first page (e.g. /<slug>/presell/) in the browser and hot-reloads as you edit. If you have multiple campaigns in the project, you'll get a picker.
🎉 You did it!
You now have a complete campaign funnel running on your local machine — presell, landing, checkout, upsells, and receipt — all wired up to your live store data through the SDK. Click through it and create a test order using the test card below.
4. Place a test order
Run the full funnel end-to-end on your local dev server. At checkout, pay with the test card below — it processes without a real transaction so you can verify presell → checkout → upsell(s) → receipt all wire up correctly.
| Card number | Expiry | CVV | What it does |
|---|---|---|---|
6011 1111 1111 1117 | Any future date | Any | Test payment success flow without transaction |
See the Testing Guide for 3DS, decline, and subscription test cards.
What you got
Each campaign is fully isolated — its own layouts, assets, and config — so you can run multiple campaigns in one repo without them stepping on each other.
my-campaigns/
├── _data/
│ └── campaigns.json # Registry — all campaigns live here
├── src/
│ └── <slug>/ # Your campaign
│ ├── _layouts/base.html # Page wrapper
│ ├── _includes/ # Reusable components
│ ├── assets/
│ │ ├── css/
│ │ ├── images/
│ │ ├── js/
│ │ └── config.js # SDK config — API key lives here
│ ├── presell.html
│ ├── checkout.html
│ ├── upsell.html
│ └── receipt.html
└── package.jsonStarter templates
Pick one at the campaign-init template prompt. Each template ships with SDK-ready checkout, upsell, and receipt surfaces, plus the supporting presell and landing pages for that family. Start from a maintained template, then replace campaign-specific copy, assets, package IDs, offer codes, shipping methods, tracking, and routes with values from Campaigns App and your build brief. The two Olympus templates are a good starting point for your first campaign.
Campaign Flow
A typical campaign funnel guides customers through a series of pages:
- Presell — advertorial article that warms up cold traffic before the offer
- Landing — marketing page that drives traffic
- Checkout — package selection, shipping, payment
- Upsells — post-purchase offers
- Receipt — order confirmation
You can customize this flow to fit your campaign — add/remove pages, change the order, or even have multiple funnels for different audiences, customize the next_page parameter on each page that links pages to the next.
Concepts
Campaigns
A campaign bundles everything needed for a checkout: packages, offers, shipping options, payment methods, and localization. Each campaign has a unique API key used by the SDK to authenticate requests.
Packages
A package is the campaign's sellable reference to a product or product variant. In SDK 0.4.x-compatible builds, keep packages focused on identity and base price:
- Create one package for the product or variant customers can buy.
- Use the package's base list price as the anchor price.
- Send the selected package ID and quantity from the page.
- Use offers to discount checkout quantity tiers and Code offers for upsells, downsells, and exit-pop incentives.
For bundle-based quantity discounts (e.g. "buy 3 for $21" or "buy 5 for $30"), use offers to discount the price at checkout rather than baking the discount into separate package records. This keeps the package list stable and lets the API return before/after pricing so template components can show savings consistently.
Package-level Quantity and Retail Price are legacy compatibility fields in Campaigns App. They may still appear when the campaign setting Enable Package Retail Price & Quantity is enabled, but new builds should prefer Offer-based price mutation.
Packages can also be recurring for subscription products. When you reference a package in HTML (data-next-package-id="…"), the ID comes from your campaign's package list in the Campaigns App.
Offers
Offers are price mutation rules that apply when an order meets a condition. Two flavours:
- Offer — automatic, applies when the cart matches the rule (checkout page only)
- Code — voucher-based, applies when the customer enters a code. Codes stack on top of automatic offers, and codes are also the mechanism for applying discounts on upsell pages (where automatic offers don't run).
The API returns adjusted before/after pricing so you can show savings. In modern Campaigns App setup, this replaces package-level compare-at pricing for most campaigns.
Example — quantity-based bundle pricing:
A single Widget package priced at $49.95/unit. Create one offer per quantity tier — including 1x — to control the discounted price the customer pays at each quantity:
| Quantity | List price | Offer | Customer pays | Savings |
|---|---|---|---|---|
| 1x | $49.95 | Buy 1 → $39.95 (Save 20%) | $39.95 | $10.00 |
| 2x | $99.90 | Buy 2 → $34.95 each (Save 30%) | $69.90 | $30.00 |
| 3x | $149.85 | Buy 3 → $29.95 each (Save 40%) | $89.85 | $60.00 |
The package's list price stays at $49.95/unit. Each offer matches its quantity rule and the API returns the adjusted total so the cart can render before/after pricing automatically.
Shipping methods
A shipping method in a campaign is a virtual link to a shipping method configured on the store, with campaign-specific custom pricing. This lets you charge a different shipping rate (e.g. a flat $4.95 or free shipping) per campaign without changing the underlying store-level shipping method.
Domains
Domains are configured in your store's Campaign Settings and apply across all campaigns. They control which domains are authorized to use your campaign API keys.
| Type | SDK Access | Analytics Tracking |
|---|---|---|
| Production | Yes | Yes — events tracked automatically |
| Development | Yes | No — events suppressed |
Add localhost and any staging domains as development domains so you can test the full checkout flow without polluting analytics data.
Requests from domains not listed in either production or development will be rejected. Add every environment your SDK runs in.
Analytics & Tracking
Every starter template ships with NEXT Campaign Analytics on by default in auto mode. The SDK automatically tracks the full funnel — page views, add-to-cart, begin checkout, shipping/payment info, purchase, and upsells — through the always-on internal nextCampaign provider. No code required.
To also forward those events to Google Tag Manager or Facebook Pixel, add your IDs in _data/campaigns.json:
{
"my-campaign": {
"name": "My Campaign",
"...": "...",
"gtm_id": "GTM-XXXXXXX",
"fb_pixel_id": "123456789012345"
}
}The matching providers.gtm.enabled and providers.facebook.enabled flags in assets/config.js control whether the SDK forwards events to each provider. Templates ship with these set to false — flip them to true once your IDs are in place. See the per-provider guides below for the full wiring.
Keep your campaign analytics clean
Two mechanisms skip tracking entirely — including the always-on internal nextCampaign provider — so your campaign dashboards reflect real customer conversions, not internal QA or test traffic:
- Development domains — any domain marked development in your store's Campaign Settings suppresses all events. Add
localhost, staging URLs, and preview hosts here. ?ignore=trueURL parameter — append it to any URL to silence tracking for the entire session, useful for one-off testing on a production domain. Clear it withwindow.NextAnalyticsClearIgnore().
Provider guides & Event reference
- Analytics overview — how the tracking system works end to end
- Google Tag Manager — container setup, GA4 wiring, variable mapping
- Facebook Pixel — event mapping, server-side deduplication,
storeName - Event reference — every
dl_*event the SDK emits, with schemas
Non-interactive setup (agents, CI)
campaign-init can run with no prompts — pass every value as a flag:
npx campaign-init --non-interactive \
--template olympus \
--slug my-campaign \
--name "My Campaign" \
--api-key "$CAMPAIGN_API_KEY" \
--ai-context claudeAdd --json for machine-readable stdout. See the page-kit CLI reference for the full flag list and exit codes.
Hosting
npm run build outputs a fully static site to _site/ — no server, no runtime, just HTML, CSS, JS, and images. That means you can host it on any static host. Configure your provider with:
- Build command:
npm run build - Publish directory:
_site
Make sure to add the host's domain (e.g. *.netlify.app, your custom domain) to your campaign's authorized domains in the Campaigns App so the SDK can call the API from that origin.
Netlify
Netlify — connect your Git repo, Netlify auto-detects the build command and serves _site/ on a *.netlify.app subdomain (custom domains free). Best for: zero-config Git deploys, branch previews, instant rollbacks.
Cloudflare Pages
Cloudflare Pages — connect your Git repo, set framework preset to "None", build command to npm run build, output directory to _site. Best for: global edge network, generous free tier, fast cold starts via Cloudflare's CDN.
Render
Render — create a new Static Site, point it at your repo, set publish path to _site. Best for: a single dashboard alongside any backend services you already run on Render.
Other static hosts
The same _site/ output works on Vercel, GitHub Pages, AWS S3 + CloudFront, Surge, or any host that serves static files. There is no server-side rendering and no runtime dependency on Node, so any plain static host will do.