Skip to main content
Ask your AI

Next.js Quickstart

This guide shows you how to integrate walkerOS into your Next.js application. Most setup is identical to React - check the React quickstart guide for more details.

Installation​

Install the required packages:

npm install @walkeros/core @walkeros/collector @walkeros/web-source-browser

Setup​

1. Walker initialization​

Create the walker initialization file:

// walker/index.ts
import type { Collector, WalkerOS } from '@walkeros/core';
import { startFlow } from '@walkeros/collector';
import { createTagger, sourceBrowser } from '@walkeros/web-source-browser';

// Global type declarations
declare global {
  interface Window {
    elb: WalkerOS.Elb;
    walker: Collector.Instance;
  }
}

let walkerReady: Promise<void> | undefined;

// Starts the flow once, later calls return the same promise
export function initializeWalker(): Promise<void> {
  walkerReady ??= startWalker();
  return walkerReady;
}

async function startWalker(): Promise<void> {
  const { collector } = await startFlow({
    consent: { functional: true },
    sources: {
      browser: {
        code: sourceBrowser,
        config: {
          settings: {
            pageview: true,
            history: true, // a page view on every route change
            elb: 'elb',
          },
        },
      },
    },
    destinations: {
      // Your destinations - add console for testing
      console: {
        code: {
          type: 'console',
          config: {},
          push: (event) => console.log('Event:', event.name),
        },
      },
    },
  });

  // Set global window object
  window.walker = collector;
}

// Tagger helper for easy component tagging
const taggerInstance = createTagger();

export function tagger(entity?: string) {
  return taggerInstance(entity);
}

2. App integration​

The collector sends the first page view when it starts. With history: true the browser source sends one on every route change and picks up the tagged elements the new route renders, so the app only starts the walker once. Some routers set the new page title after the route change, so its page view can carry the previous title. For exact titles, see single-page apps.

With the Pages Router, start it in _app.tsx:

// pages/_app.tsx
import type { AppProps } from 'next/app';
import { useEffect } from 'react';
import { initializeWalker } from '../walker';

export default function App({ Component, pageProps }: AppProps) {
  useEffect(() => {
    // Starts once, also when React StrictMode runs effects twice
    initializeWalker();
  }, []);

  return <Component {...pageProps} />;
}

With the App Router, effects only run in a Client Component, so start it from one and render that from the root layout:

// app/walker-tracker.tsx
'use client';

import { useEffect } from 'react';
import { initializeWalker } from '../walker';

export function WalkerTracker() {
  useEffect(() => {
    // Starts once, also when React StrictMode runs effects twice
    initializeWalker();
  }, []);

  return null;
}
// app/layout.tsx
import type { ReactNode } from 'react';
import { WalkerTracker } from './walker-tracker';

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <WalkerTracker />
        {children}
      </body>
    </html>
  );
}

Component usage​

Component usage is identical to React. Use the tagger helper and manual events. Here the tagger sends product view when the product is on the page, and the button sends product add manually. With the App Router, the onClick handler makes this a Client Component, so its file starts with 'use client':

'use client';

import { tagger } from '../walker';

function ProductPage({ product }: { product: { id: number; name: string } }) {
  return (
    <div
      {...tagger()
        .entity('product')
        .action('load', 'view')
        .data('id', product.id)
        .data('name', product.name)
        .get()}
    >
      <h1>{product.name}</h1>
      <button
        onClick={() =>
          window.elb({ name: 'product add', data: { id: product.id } })
        }
      >
        Add to Cart
      </button>
    </div>
  );
}
info

When using the tagger helper, make sure to call .get() at the end of the chain.

Testing​

During walker initialization, we added a console destination. It logs each event's name to the console. Open your browser's developer console and navigate from the home page to a product page to see tracked events. The first page view is the home page, the second the product page, then the product's view:

Event: page view
Event: page view
Event: product view

Best practices​

  1. Use tagger: Clean component tagging with the tagger helper
  2. Minimal Next.js code: Keep Next.js integration as simple as possible
  3. Trust walkerOS: No need for custom error handling or state management
  4. Direct integration: No providers needed, integrate directly in _app or layout
  5. Test with console: Use console destination during development

Troubleshooting​

Events not firing​

  1. Check that window.walker is set in the browser console
  2. Verify data attributes are correctly formatted (use data-elb prefix)
  3. Ensure walker initialization completed (window.walker.allowed must be true)
  4. Check browser console for any error messages

Route changes not tracked​

  1. Check that the browser source has history: true
  2. Remove route-change walker run calls: with history on they send a second page view
  3. A route that reuses its component when only a parameter changes does not fire its tagged elements again: remount it per route, for example with a template.tsx or a key

TypeScript errors​

Make sure you've added the global type declarations in your walker initialization file.

Next steps​

💡 Setting this up for production?
If your setup involves consent management, server-side pipelines, or custom destinations, the creators of walkerOS offer hands-on implementation support. Start with a free scoping call.