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

# React Quickstart

This guide shows you how to integrate walkerOS into your React application with automatic pageview tracking and component-level event tracking.

## Key concepts[​](#key-concepts "Direct link to Key concepts")

* **Single file setup**: One initialization file, direct usage in App.tsx
* **No providers needed**: Direct integration in your main App component
* **StrictMode safe**: Handles React's double execution correctly
* **Data attributes**: Use the tagger helper for clean component tracking

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

First, install the required walkerOS packages:

```bash
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")

```tsx
// src/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: {
      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")

Integrate directly in your main App component. 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](/preview/pr-749/docs/sources/web/browser.md#single-page-apps).

```tsx
// src/App.tsx
import { Routes, Route } from 'react-router-dom';
import { useEffect } from 'react';
import { initializeWalker } from './walker';

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

  return (
    <div className="min-h-screen bg-gray-50">
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/category" element={<Category />} />
        <Route path="/product/:id" element={<Detail />} />
      </Routes>
    </div>
  );
}

export default App;
```

## Component tagging[​](#component-tagging "Direct link to Component tagging")

Use the tagger helper for clean component tracking:

```tsx
// src/components/ProductDetail.tsx
import { getProductById } from '../data/products';
import { tagger } from '../walker';

function ProductDetail({ productId }: { productId: string }) {
  const product = getProductById(parseInt(productId));
  if (!product) return null;

  return (
    <div
      {...tagger()
        .entity('product')
        .action('load', 'view')
        .data('productId', productId)
        .get()}
      className="bg-white rounded-lg shadow p-8"
    >
      <h1
        {...tagger('product').data('name', product.name).get()}
        className="text-3xl font-bold mb-2"
      >
        {product.name}
      </h1>

      <p
        {...tagger('product').data('price', product.price).get()}
        className="text-3xl font-bold text-blue-600"
      >
        €{product.price}
      </p>

      <button
        {...tagger().action('click', 'add').get()}
        className="w-full bg-blue-600 text-white py-3 px-6 rounded-lg"
      >
        Add to Cart
      </button>
    </div>
  );
}
```

```tsx
// Without tagger helper (verbose)
<div
  data-elb="product"
  data-elbaction="load:view"
  data-elb-product={`id:${product.id};name:${product.name};price:${product.price}`}
>

// With tagger helper (clean)
<div
  {...tagger()
    .entity('product')
    .action('load', 'view')
    .data('id', product.id)
    .data('name', product.name)
    .data('price', product.price)
    .get()}
>
```

info

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

## Manual event tracking[​](#manual-event-tracking "Direct link to Manual event tracking")

Use the `elb` function for custom events:

```tsx
import type { FormEvent } from 'react';

function CheckoutForm({ total, itemCount }: { total: number; itemCount: number }) {
  const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    window.elb({
      name: 'checkout complete',
      data: { total, items: itemCount },
    });
  };

  return <form onSubmit={handleSubmit}>{/* Form fields */}</form>;
}
```

## Testing[​](#testing "Direct link to Testing")

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

1. **Use tagger**: Clean component tagging with the tagger helper
2. **Minimal React code**: Keep React 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 component
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 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 `key={id}`

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

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