APIServer-side attribution
Node
Read the referral cookie and attribute a Stripe customer from any Node handler.
Works with Express, Fastify, Hono, or a plain http handler: anything that gives you the
request's cookies. The three lines are the ones that read the cookie and pass the click id.
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
/** The click id from the `rail_referral` cookie, or null when the visitor had no referral. */
function railReferral(cookieHeader) {
const match = /(?:^|;\s*)rail_referral=([^;]*)/.exec(cookieHeader ?? "");
if (!match) return null;
try {
return JSON.parse(decodeURIComponent(match[1])).clickId ?? null;
} catch {
return null;
}
}
app.post("/signup", async (req, res) => {
const clickId = railReferral(req.headers.cookie);
const customer = await stripe.customers.create({
email: req.body.email,
metadata: clickId ? { rail_referral: clickId } : {},
});
// Elements, a PaymentIntent, a Subscription: whatever you create next for this customer is
// attributed, because the customer is. Nothing else to pass.
res.json({ customerId: customer.id });
});If you create the subscription before the customer has the metadata (some flows create the customer early, at account signup, and the referral arrives later), put it on the subscription instead:
await stripe.subscriptions.create({
customer: customer.id,
items: [{ price: priceId }],
metadata: clickId ? { rail_referral: clickId } : {},
});Both work. Both are idempotent: the first one we see binds the customer, the second is ignored.