Landing page and app
A plain HTML landing page on example.com and a Next.js app on app.example.com, as one site: one visitor, one journey, and the sale credited to what brought them.
The common SaaS shape: the marketing site is plain HTML on example.com, the
product is a Next.js app on app.example.com. Use one site in trckable,
with the parent domain (example.com) as its domain, and install it in both
places with the same site id.
On the landing page
The script tag, with data-domain set to the site's domain:
<script
defer
data-site="tkb_a1b2c3d4"
data-domain="example.com"
src="https://stats.example.com/js/tkb_a1b2c3d4.js">
</script>In the app
The Next.js setup, unchanged:
import { Analytics } from 'trckable/next'
<Analytics site="tkb_a1b2c3d4" />// app/api/e/route.ts — same-origin: past analytics blocklists, 400-day Safari visitors
export { POST } from 'trckable/next'# .env
TRCKABLE_HOST=https://stats.example.com
TRCKABLE_PROXY_KEY=your-proxy-keySettings → Install → Landing page and app shows both, filled in for your site.
Why it is one visitor
Both hosts read the same trckable_vid cookie, on example.com:
- the script writes it there because of
data-domain; - the app's route has trckable set it from the server, on the site's domain, whenever the page is on that domain or a subdomain of it.
Whichever the visitor opens first, the other picks the cookie up. Once they reach the app, its route renews the cookie as a server cookie, so Safari keeps it for 400 days rather than seven.
A browser test in trckable's own suite walks this path in Chromium, Firefox and WebKit: landing page with a campaign, app, hosted checkout, sale. It checks there is one visitor and one session, and that the sale is credited to the landing page's campaign.
Revenue
Nothing extra. Hosted checkout links (Stripe Payment Links, Lemon Squeezy, Polar, Dodo) are decorated by the script on either host. A checkout the app creates on the server reads the same cookie:
import { cookies } from 'next/headers'
import { getIds, checkoutFields } from 'trckable/next'
const ids = getIds(await cookies())
await stripe.checkout.sessions.create({ ...params, ...checkoutFields('stripe', ids, 'subscription') })What breaks it
- No
data-domain. The landing page's cookie stays onexample.comalone; the app never sees it and counts a second visitor, and the sale goes to the app rather than the campaign. www.example.comas the site's domain. The server scopes its cookie to the site's domain, andapp.example.comis not underwww. Use the parent domain, and the same value indata-domain.- Two sites. Two site ids are two sets of visitors, by design.