Skip to content
Documentation menu: Next.js

Next.js integration

Add theBizness.ai analytics to your Next.js application with one script tag in your root layout.

Setup time

2 minutes

Difficulty

Easy

Loading

After the page is interactive

Choose your Next.js version

App Router installation

For Next.js 13+ applications using the new App Router

Step 1: Add to the root layout

Add the tracking script to your app/layout.tsx file:

// app/layout.tsx
import Script from 'next/script'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <head>
        <Script
          strategy="afterInteractive"
          data-website-id="your-website-id"
          data-domain="yourdomain.com"
          src="https://thebizness.ai/js/script.js"
        />
      </head>
      <body>{children}</body>
    </html>
  )
}
Tip

strategy="afterInteractive" loads the script after the page becomes interactive, so it does not delay your first render.

Pages Router installation

For Next.js 12 and below, or projects still using Pages Router

Step 1: Add to _app.tsx

Add the tracking script to your pages/_app.tsx file (_app.js works the same way):

// pages/_app.tsx
import type { AppProps } from 'next/app'
import Script from 'next/script'

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Script
        strategy="afterInteractive"
        data-website-id="your-website-id"
        data-domain="yourdomain.com"
        src="https://thebizness.ai/js/script.js"
      />
      <Component {...pageProps} />
    </>
  )
}
Why not _document

Do not put this tag in pages/_document. That file is rendered on the server only and is never hydrated, so a next/script tag with strategy="afterInteractive" there does not load in the browser.

Environment variables (recommended)

Keep your website ID and domain in environment variables so each environment can use its own

Step 1: Add to .env.local

# .env.local
NEXT_PUBLIC_THEBIZNESS_WEBSITE_ID=your-website-id
NEXT_PUBLIC_THEBIZNESS_DOMAIN=yourdomain.com

Step 2: Use them in the layout

// app/layout.tsx
import Script from 'next/script'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <head>
        <Script
          strategy="afterInteractive"
          data-website-id={process.env.NEXT_PUBLIC_THEBIZNESS_WEBSITE_ID}
          data-domain={process.env.NEXT_PUBLIC_THEBIZNESS_DOMAIN}
          src="https://thebizness.ai/js/script.js"
        />
      </head>
      <body>{children}</body>
    </html>
  )
}
Why use environment variables
  • • Use a different website ID for staging and production
  • • Change the ID without editing code
  • • Keep your configuration in one place

The website ID and domain are public: they appear in your page HTML, and NEXT_PUBLIC_ variables are included in the browser bundle. They are configuration, not secrets.

Advanced: proxy setup

Route analytics through your own domain so fewer requests are blocked by ad blockers
What to know
  • • Served from your own domain, so ad blockers are less likely to block it. Some blockers still will.
  • • Keeps the script and its requests on your first-party domain
  • • The proxy removes the Cookie and Authorization headers before forwarding, and the Referer on the script download, so your visitors' cookies for your own domain and the address of the page that loads the script never reach us
  • • It keeps the Origin (or Referer) header on every request under /api/events/. The origin check needs one of them: a browser request that carries neither, or one from another domain, is rejected and nothing is recorded
  • • Every visitor then reaches us from your server's address, so the per-address rate limits (120 pageviews a minute, for example) apply to your site as a whole
  • • Conversions work through the same proxy: the script sends them to /api/events/conversions and the recipes pass them on to /api/conversions. The /check path only serves copies of the script cached before October 2026
  • • Server-side reporting with your ingest secret goes straight to https://thebizness.ai, not through this proxy, which removes the Authorization header. Keep the secret out of browser code

Step 1: Add the proxy

Forward the script and the tracking requests to thebizness.ai. Pick the one that matches how your site is served. If you already have a middleware.ts, add this logic to it and add the two paths to its matcher.

// middleware.ts (project root, or src/ if you use a src directory)
import { NextResponse, type NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const { pathname, search } = request.nextUrl;

  // The script posts conversions to /api/events/conversions. Our API serves them at /api/conversions.
  const target = pathname.startsWith('/api/events/conversions')
    ? pathname.replace('/api/events/conversions', '/api/conversions')
    : pathname;

  // Do not pass your visitors' cookies or any HTTP authentication on to us
  const headers = new Headers(request.headers);
  headers.delete('cookie');
  headers.delete('authorization');
  // The script file does not need the address of the page that loads it
  if (pathname === '/js/script.js') headers.delete('referer');

  // Origin (and the origin-only Referer of the script's requests) stay intact: the origin check reads them
  return NextResponse.rewrite(new URL(target + search, 'https://thebizness.ai'), {
    request: { headers },
  });
}

export const config = {
  matcher: ['/js/script.js', '/api/events/:path*'],
};

Next.js 16 and later name this file convention proxy (proxy.ts, with an exported function called proxy). The code inside is the same.

# /etc/nginx/snippets/thebizness-proxy.conf
proxy_ssl_server_name on;
proxy_set_header Host thebizness.ai;
# An empty value means the header is not passed on
proxy_set_header Cookie "";
proxy_set_header Authorization "";

# Inside the server { } block of your site
location = /js/script.js {
    include snippets/thebizness-proxy.conf;
    proxy_set_header Referer "";
    proxy_pass https://thebizness.ai/js/script.js;
}

location = /api/events {
    include snippets/thebizness-proxy.conf;
    proxy_pass https://thebizness.ai/api/events;
}

location = /api/events/event {
    include snippets/thebizness-proxy.conf;
    proxy_pass https://thebizness.ai/api/events/event;
}

location = /api/events/conversions {
    include snippets/thebizness-proxy.conf;
    proxy_pass https://thebizness.ai/api/conversions;
}

# Optional: only copies of the script cached before October 2026 still call this
location = /api/events/conversions/check {
    include snippets/thebizness-proxy.conf;
    proxy_pass https://thebizness.ai/api/conversions/check;
}

Reload nginx after adding the snippet and the locations.

// Cloudflare Worker. Add routes for:
//   yourdomain.com/js/script.js
//   yourdomain.com/api/events*
const UPSTREAM = 'https://thebizness.ai';

export default {
  async fetch(request) {
    const url = new URL(request.url);

    // The script posts conversions to /api/events/conversions. Our API serves them at /api/conversions.
    const path = url.pathname.startsWith('/api/events/conversions')
      ? url.pathname.replace('/api/events/conversions', '/api/conversions')
      : url.pathname;

    // Do not pass your visitors' cookies or any HTTP authentication on to us
    const headers = new Headers(request.headers);
    headers.delete('cookie');
    headers.delete('authorization');
    // The script file does not need the address of the page that loads it
    if (url.pathname === '/js/script.js') headers.delete('referer');

    return fetch(new Request(UPSTREAM + path + url.search, {
      method: request.method,
      headers,
      body: request.body,
      redirect: 'manual',
    }));
  },
};

Attach the Worker only to the two routes in the comment, and make sure your site has no routes of its own under /api/events.

Step 2: Update the script source

Change the script src to use your local domain:

// With proxy configuration, use local paths
<Script
  strategy="afterInteractive"
  data-website-id="your-website-id"
  data-domain="yourdomain.com"
  src="/js/script.js"
/>
Plain rewrites are not recommended

Next.js rewrites() in next.config.js work, but they forward everything the browser sends: your visitors' cookies for your domain, any HTTP Basic-auth header, and the address of the page, all of which would reach thebizness.ai. Use the middleware above instead. If you keep rewrites anyway, this is the configuration:

// next.config.js (not recommended: this forwards everything the browser sends)
/** @type {import('next').NextConfig} */
const nextConfig = {
  async rewrites() {
    return [
      {
        source: '/js/script.js',
        destination: 'https://thebizness.ai/js/script.js',
      },
      {
        source: '/api/events',
        destination: 'https://thebizness.ai/api/events',
      },
      {
        source: '/api/events/event',
        destination: 'https://thebizness.ai/api/events/event',
      },
      {
        source: '/api/events/conversions',
        destination: 'https://thebizness.ai/api/conversions',
      },
      // Optional: only copies of the script cached before October 2026 still call this
      {
        source: '/api/events/conversions/check',
        destination: 'https://thebizness.ai/api/conversions/check',
      },
    ];
  },
};

module.exports = nextConfig;

Verify installation

Make sure everything is working correctly

Quick check

  1. 1. Deploy your changes
  2. 2. Visit your website
  3. 3. Check browser Network tab for script load
  4. 4. Navigate between pages

Dashboard check

  1. 1. Sign in to your theBizness.ai dashboard
  2. 2. Open the Overview and check that pageviews appear after a reload
  3. 3. Navigate between pages and confirm each visit is counted
  4. 4. Test UTM parameter tracking
Common issues
  • • The tracker does nothing on localhost, *.local, *.test, private IP addresses or file:// pages. It logs a "Tracking disabled on localhost" warning in the console. Verify on a publicly reachable domain.
  • • Make sure you're using your actual website ID, not the placeholder
  • • Check that your domain matches exactly (no www mismatch)
  • • Verify the script loads in browser DevTools Network tab
  • • If your site sends a Content-Security-Policy header, allow https://thebizness.ai in script-src and connect-src. Blocked requests show only as CSP errors in the browser console

Installation complete

Your Next.js application is now tracking visitor analytics with theBizness.ai. Here's what to do next:

Revenue attribution

Connect Stripe to track which campaigns generate paying customers

Conversion tracking

Set up custom events to track signups, purchases, and more

UTM campaigns

Start using UTM parameters to track marketing campaigns