> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

# 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](/preview/pr-720/docs/getting-started/quickstart/react.md) for more details.

## Installation[​](#installation "Direct link to Installation")

Install the required packages:

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

## Setup[​](#setup "Direct link to Setup")

### 1. Walker initialization[​](#1-walker-initialization "Direct link to 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> {
  // run: false, the app sends `walker run` once per page
  const { collector } = await startFlow({
    run: false,
    consent: { functional: true },
    sources: {
      browser: {
        code: sourceBrowser,
        config: {
          settings: {
            pageview: true,
            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[​](#2-app-integration "Direct link to 2. App integration")

The collector starts with `run: false`, so nothing is sent until the first `walker run`. Send it for the initial page and on every route change, once the flow has started. With the Pages Router, use the Next.js router events:

```
// pages/_app.tsx
import type { AppProps } from 'next/app';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { initializeWalker } from '../walker';

export default function App({ Component, pageProps }: AppProps) {
  const router = useRouter();
  const initialRun = useRef(false);

  useEffect(() => {
    // walker run sends the page view and scans the page for load triggers
    const run = () => {
      initializeWalker().then(() => window.elb('walker run'));
    };

    // Initial page, once: React StrictMode runs effects twice in development
    if (!initialRun.current) {
      initialRun.current = true;
      run();
    }

    // Next.js route events
    router.events.on('routeChangeComplete', run);

    return () => {
      router.events.off('routeChangeComplete', run);
    };
  }, [router.events]);

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

For Next.js 13+ with App Router, `usePathname` only works in a Client Component, so put the tracking in one and render it from the root layout:

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

import { usePathname } from 'next/navigation';
import { useEffect, useRef } from 'react';
import { initializeWalker } from '../walker';

export function WalkerTracker() {
  const pathname = usePathname();
  const lastPathname = useRef('');

  useEffect(() => {
    // React StrictMode runs effects twice in development, run once per path
    if (lastPathname.current === pathname) return;
    lastPathname.current = pathname;

    // walker run sends the page view and scans the new page for load triggers
    initializeWalker().then(() => window.elb('walker run'));
  }, [pathname]);

  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 "Direct link to Component usage")

Component usage is identical to React. Use the tagger helper and manual events. Here the tagger sends `product view` when `walker run` scans 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'`:

```
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('product add', { 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[​](#testing "Direct link to 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 to a product page to see tracked events:

```
Event: product view

Event: page view
```

## Best practices[​](#best-practices "Direct link to 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[​](#troubleshooting "Direct link to Troubleshooting")

### Events not firing[​](#events-not-firing "Direct link to 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[​](#route-changes-not-tracked "Direct link to Route changes not tracked")

1. Check that `walker run` is called on route changes
2. Ensure the initial-run or pathname check sends one `walker run` per page, also under React StrictMode
3. Verify router event listeners are working correctly

### TypeScript errors[​](#typescript-errors "Direct link to TypeScript errors")

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

## Next steps[​](#next-steps "Direct link to Next steps")

* Configure [destinations](/preview/pr-720/docs/destinations.md) for your analytics tools
* Set up [consent management](/preview/pr-720/docs/guides/consent.md)
* **[Send it to GA4](/preview/pr-720/docs/getting-started/ga4-ecommerce.md)**: the same event arriving live in GA4 DebugView
* **[Operating modes](/preview/pr-720/docs/getting-started/modes.md)**: choose how to package and deploy
