⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content

elbwalker/walkerOS

Repository files navigation

Open-source data collection and tag management

walkerOS captures, structures, and routes events with built-in support for consent management — all directly in your code. No fragile UI configs. No black-box logic. Just tracking infrastructure you can version, test, and trust.

Why walkerOS?

  • Independence: Make your data collection independent from single vendor specifications to reduce complexity and extra code whenever you add or remove a new service. Keep maintenance effort to a minimum.
  • Scalability: DOM-based, component-level frontend tagging makes tracking user behavior declarative, reusable, and easy to maintain.
  • Privacy-first approach: Built-in consent handling and privacy controls help you meet compliance from day one.
  • Type-safe tracking: Built with TypeScript to catch tracking errors at compile time, not in production. Get IDE autocomplete for APIs and destination configs, prevent data structure mistakes.

How it works

walkerOS event flow

Two Ways to Use walkerOS

walkerOS supports two operating modes—choose based on your workflow:

Mode Best For Config Style
Integrated React/Next.js apps, TypeScript projects code: sourceBrowser
Bundled Static sites, Docker deployments, CI/CD package: "@walkeros/..."
Quick comparison

Integrated (collector in your app):

import { startFlow } from '@walkeros/collector';
import { sourceBrowser } from '@walkeros/web-source-browser';

await startFlow({
  sources: { browser: { code: sourceBrowser } },
});

Bundled (separate artifact via CLI):

{
  "sources": {
    "browser": { "package": "@walkeros/web-source-browser" }
  }
}

Then: walkeros bundle flow.json

📖 Full guide: Operating Modes

Quick Start (Integrated Mode)

npm

Install the required packages from npm:

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

Initialize walkerOS in your project:

import { startFlow } from '@walkeros/collector';
import { sourceBrowser } from '@walkeros/web-source-browser';

// Initialize walkerOS
export async function initializeWalker(): Promise<void> {
  const { collector, elb } = await startFlow({
    sources: {
      browser: {
        code: sourceBrowser,
        config: {
          settings: {
            pageview: true,
            session: true,
            elb: 'elb', // Makes elb available as window.elb
          },
        },
      },
    },
    destinations: {
      console: {
        code: {
          type: 'console',
          config: {},
          push: (event) => console.log('Event:', event),
        },
      },
    },
  });

  // Make collector available globally
  window.walker = collector;
}

script tag

For websites without build tools, you can install from a CDN:

<script type="module">
  import { startFlow } from 'https://cdn.jsdelivr.net/npm/@walkeros/collector/dist/index.mjs';
  import { sourceBrowser } from 'https://cdn.jsdelivr.net/npm/@walkeros/web-source-browser/dist/index.mjs';

  const { collector, elb } = await startFlow({
    sources: {
      browser: {
        code: sourceBrowser,
        config: {
          settings: {
            pageview: true,
            session: true,
            elb: 'elb',
          },
        },
      },
    },
    destinations: {
      console: {
        code: {
          type: 'console',
          config: {},
          push: (event) => console.log('Event:', event),
        },
      },
    },
  });

  window.walker = collector;
</script>

Example: React

Here's a quick look at how to integrate walkerOS into a React application.

1. Create a walker setup file:

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;
  }
}

export async function initializeWalker(): Promise<void> {
  // Skip initialization if already done
  if (window.walker) return;

  // Create collector with run: false for manual pageview control
  const { collector } = await startFlow({
    run: false,
    consent: { functional: true },
    sources: {
      browser: {
        code: sourceBrowser,
        config: {
          settings: {
            pageview: true,
            session: true,
            elb: 'elb',
          },
        },
      },
    },
    destinations: {
      // Your destinations - add console for testing
      console: {
        push(event, data) {
          console.log('Event:', event, data);
        },
      },
    },
  });

  // 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. Integrate into your App component:

import { Routes, Route, useLocation } from 'react-router-dom';
import { useEffect, useRef } from 'react';
import { initializeWalker } from './walker';

function App() {
  const location = useLocation();
  const hasInitialized = useRef(false);
  const firstRun = useRef(true);

  useEffect(() => {
    // Prevent React StrictMode double execution
    if (!hasInitialized.current) {
      initializeWalker();
      hasInitialized.current = true;
    }
  }, []);

  useEffect(() => {
    // Skip first run to prevent double page views
    if (firstRun.current) {
      firstRun.current = false;
      return;
    }

    window.elb('walker run');
  }, [location]);

  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;

3. Tag your components:

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

function ProductDetail({ productId }: { productId: string }) {
  const product = getProductById(parseInt(productId));

  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>
  );
}

Quick Start (Bundled Mode)

For config-as-code workflows with the CLI:

1. Install CLI:

npm install -g @walkeros/cli

2. Create flow.json:

{
  "version": 1,
  "flows": {
    "default": {
      "web": {},
      "sources": {
        "browser": {
          "package": "@walkeros/web-source-browser",
          "config": { "settings": { "pageview": true } }
        }
      },
      "collector": { "run": true }
    }
  }
}

3. Bundle and deploy:

walkeros bundle flow.json
# Output: ./dist/walker.js

📖 Full guide: Bundled Mode

Destinations

Destinations are the endpoints where walkerOS sends your processed events. They transform standardized walkerOS events into specific formats required by analytics platforms, marketing tools, and data warehouses.

Web Destinations

Server Destinations

Contributing

⭐️ Help us grow and star us. See our Contributing Guidelines to get involved.

Support

Need help? Start a discussion, or reach out via email.

For more insights, visit the talks repository.

License

Licensed under the MIT License.