SDK reference

@trace/sdk reads the Trace cookies (trace_visitor_id, trace_session_id) and shapes them as a metadata object you can pass straight to Stripe. One line, framework-aware, server- or client-side.

Why use the SDK?
It's the difference between 100%-accurate metadata attributionand email-fallback attribution that depends on your customer's checkout email matching the email they used when they first identified themselves to your store. Use the SDK whenever you can.

Install

bash
npm install @trace/sdk
# or
pnpm add @trace/sdk
# or
yarn add @trace/sdk

Subpath imports

The SDK ships one entry point per environment. Pick the one that matches your stack — they all return the same { trace_visitor_id, trace_session_id } shape.

ImportUse when
@trace/sdk/nextNext.js App Router (route handlers, server actions, server components)
@trace/sdk/next-pagesNext.js Pages Router (pages/api/*)
@trace/sdk/expressExpress, Fastify, Hono, or anything that gives you a request object with req.headers.cookie
@trace/sdk/browserClient-side checkout where you call Stripe.js directly from the browser
@trace/sdk/nodeGeneric Node — pass any Cookie header string in

Next.js App Router

ts
// app/api/checkout/route.ts
import { getAttribution } from '@trace/sdk/next';
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function POST(req: Request) {
  const { line_items } = await req.json();
  const session = await stripe.checkout.sessions.create({
    mode: 'payment',
    line_items,
    success_url: 'https://yourstore.com/thanks',
    cancel_url: 'https://yourstore.com/cart',
    metadata: await getAttribution(),
  });
  return Response.json({ url: session.url });
}

Works in any server context that has access to cookies() from next/headers — route handlers, server actions, server components.

Next.js Pages Router

ts
// pages/api/checkout.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { getAttribution } from '@trace/sdk/next-pages';
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const session = await stripe.checkout.sessions.create({
    mode: 'payment',
    line_items: req.body.line_items,
    success_url: 'https://yourstore.com/thanks',
    cancel_url: 'https://yourstore.com/cart',
    metadata: getAttribution(req),
  });
  res.json({ url: session.url });
}

Express / Fastify / Hono

ts
// server.ts
import express from 'express';
import { getAttribution } from '@trace/sdk/express';
import Stripe from 'stripe';

const app = express();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

app.post('/api/checkout', express.json(), async (req, res) => {
  const session = await stripe.checkout.sessions.create({
    mode: 'payment',
    line_items: req.body.line_items,
    success_url: 'https://yourstore.com/thanks',
    cancel_url: 'https://yourstore.com/cart',
    metadata: getAttribution(req),
  });
  res.json({ url: session.url });
});

The Express helper reads req.headers.cookie directly, so it works with any framework that follows that convention.

Browser (client-side checkout)

If you build your Checkout Session on the server but kick off Stripe.js from the browser, send the attribution from the client and have your server pass it through:

ts
// client
import { getAttribution } from '@trace/sdk/browser';

const res = await fetch('/api/checkout', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    line_items: cart.items,
    attribution: getAttribution(),
  }),
});
ts
// server — pass body.attribution straight into metadata
const session = await stripe.checkout.sessions.create({
  mode: 'payment',
  line_items: body.line_items,
  metadata: body.attribution,
  success_url: '...',
  cancel_url: '...',
});
Don't trust client-supplied data unconditionally
We're only using the attribution as analytics metadata, so this is fine. But if you're storing it as a record of identity, prefer the server-side helper.

Generic Node (any Cookie header)

ts
import { getAttributionFromCookieHeader } from '@trace/sdk';

const meta = getAttributionFromCookieHeader(req.headers.cookie ?? '');
// → { trace_visitor_id?: string; trace_session_id?: string }

Use this if you're on a Node-flavored framework we don't ship a helper for (Hapi, Koa-with-no-cookie-parser, Cloudflare Workers, etc.).

The shape it returns

ts
type Attribution = {
  trace_visitor_id?: string;
  trace_session_id?: string;
};

Both keys are optional. If a user lands on your checkout from a fresh browser with no Trace cookies (e.g. they came from an email or a paste of the cart URL), the SDK returns {}. That's safe — Stripe accepts empty metadata.

Subscriptions, payment links, and elements

  • Subscriptions — pass attribution to stripe.subscriptions.create the same way: { metadata: await getAttribution() }.
  • Payment Links— these don't support per-visitor metadata. Trace falls back to email matching. Fine for low-volume PLG flows; not recommended as your primary checkout.
  • Stripe Elements / Payment Element — pass attribution into the PaymentIntent metadata when you create it on the server.