Theme

Start for free
DocsNext.js

02 · Install

Add the snippet to a Next.js app

The tag goes in the root layout, once. Client-side navigations are pageviews on their own, with nothing to wire up.

01Where it goes

In app/layout.tsx, the root layout: inside its <head>.

Show the code for

// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <script defer data-site="k3xq2mfa7twp" src="https://t.tallybyoutpost.com/script.js"></script>
      </head>
      <body>{children}</body>
    </html>
  );
}

// pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html lang="en">
      <Head>
        <script defer data-site="k3xq2mfa7twp" src="https://t.tallybyoutpost.com/script.js"></script>
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

02Check it worked

03Pass the visitor's id to Stripe

In the route handler that creates Checkout Sessions, read the _tally_vid cookie and put it in the session's metadata:

Next.js
// app/api/checkout/route.ts
import { cookies } from 'next/headers';
import Stripe from 'stripe';

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

export async function POST() {
  const visitorId = (await cookies()).get('_tally_vid')?.value;
  const metadata: Record<string, string> = visitorId ? { 'tally_visitor_id': visitorId } : {};
  const session = await stripe.checkout.sessions.create({
    mode: 'subscription',
    line_items: [{ price: 'price_123', quantity: 1 }],
    success_url: 'https://example.com/thanks?session_id={CHECKOUT_SESSION_ID}',
    metadata,
    // Renewals read the subscription's metadata. In payment mode, leave this line out.
    subscription_data: { metadata },
  });
  return Response.json({ url: session.url });
}

Stripe Checkout has the same in Node, Python, Ruby and PHP, and why the success URL matters too.

04Serving it from your domain

A rewrite in next.config.js serves the script and its events from your own domain, which keeps most ad blockers out of the way: Serving it from your domain.

05What it can't see

Something missing, or not what you see? Write to support@tallybyoutpost.com and say which page.