Skip to main content

The tracking library for design systems

User behavior tracking that ships with your components.

Tag a component once, and every page that uses it is tracked. No future tracking tickets, no vendor-shaped code. Switching analytics tools happens in config, not in a rebuild.

Quickstart
  • MIT-licensed
  • Works with any framework
  • Storybook addon
ArticleTeaser.html
1<article class="teaser"
2 data-elb="article"
3 data-elbaction="impression"
4>
5 <img src="/img/bug.jpg" alt="" />
6 <span class="kicker" data-elb-article="category:#innerText">Tech</span>
7 <h3 data-elb-article="title:#innerText">Return of the Bug</h3>
8 <a data-elbaction="click:open">Open →</a>
9</article>
articleimpression
TechReturn of the Bug
Open →
SELECT * FROM walkerOS.eventslive
RownameSTRINGdataJSON
1article open{"category":"Tech","title":"Return of the Bug"}
2article impression{"category":"Tech","title":"Return of the Bug"}

Because event instrumentation is real engineering effort

Hand-written tracking doesn't scale.

Three ways the usual setup costs you, release after release.

01Every feature needs a tracking ticket

A tracking spec, a Jira ticket, and a dev hand-writing the push. Tracking always comes after shipping, and a missing event looks exactly like a quiet afternoon.

02Your code speaks your vendor's language

Tracking calls are written in GA4's or Amplitude's exact shape. Switching vendors means rewriting every call site, so nobody switches.

03Events without structure

Ten teams, ten ways to name a click: "click_btn_new2", "teaser-click", "TeaserClick_v3". No shared syntax, so the tag manager fills up with workarounds just to make the data usable, and every new report starts with cleanup.

Tracking lives in the component, not a separate step

Tag the component, not the page.

Tracking becomes part of your design system's API, just like props and styles.

Instead of a hand-written push or GTM listener for every feature, data attributes live in the component markup. Tag it once, and every team using it ships structured events by default: entity, action and data. Fewer tracking tickets. Structured events by default. Less dev time on instrumentation.

entityactionpropertycontextglobals

Link carries the click:open action wherever it is rendered.

Link.tsxatom
1export const Link = ({ href, children }) => (
2 <a href={href} data-elbaction="click:open">
3 {children}
4 </a>
5);
ArticleTeaser.tsxmolecule
1export const ArticleTeaser = ({
2 title, category, image, url, position,
3}) => (
4 <article data-elb="article"
5 data-elb-article={`position:${position}`}>
6 <img src={image} />
7 <span data-elb-article="category:#innerText">{category}</span>
8 <h3 data-elb-article="title:#innerText">{title}</h3>
9 <Link href={url}>Open →</Link>
10 </article>
11);
HomeFeed.tsxorganism
1<section data-elbcontext="list:homefeed">
2 {stories.map((s, i) => <ArticleTeaser {...s} position={i + 1} />)}
3</section>
RelatedStories.tsxorganism
1<section data-elbcontext="list:related">
2 {related.map((s, i) => <ArticleTeaser {...s} position={i + 1} />)}
3</section>
HomePage.tsxtemplate
1<main data-elbglobals="pagetype:homepage">
2 <HomeFeed />
3</main>
ArticlePage.tsxtemplate
1<main data-elbglobals="pagetype:article">
2 <RelatedStories />
3</main>
pagetype:homepage
<HomeFeed /> · homepagelist:homefeed
article1TechReturn of the BugOpen →
article2TechThe quiet return of RSSOpen →
article3FoodWhy sourdough came backOpen →
pagetype:article
<RelatedStories /> · article pageRelated storieslist:related
article1TechThe quiet return of RSSOpen →
article2ScienceA year on the ice shelfOpen →
article3CultureSmall venues, big nightsOpen →

The vendor becomes a destination

Add, swap or drop any tool without touching your app.

Instrument once. Analytics, ads, CRM or warehouse: every tool is a mapping, not a rewrite.

Instead of calling each vendor's SDK in its own shape, your components emit one entity action event. A destination config translates it for GA4, Meta, TikTok, Amplitude or 30+ others. Swap or add a tool, and the app never changes. The instrumentation you build today survives your next vendor decision.

Pick an event
elb('product view', { id: 'ers', price: 420, currency: 'EUR' })
// same event, four destinations, zero app code touched
GA4
mapping"product": { "view": { "name": "view_item", "data": {…} } }
sends
gtag('event', 'view_item', {
currency: 'EUR',
value: 420,
items: [{ item_id: 'ers' }],
send_to: 'G-XXXXXXXXXX',
})
Meta Pixel
mapping"product": { "view": { "name": "ViewContent", "data": {…} } }
sends
fbq('track', 'ViewContent', {
value: 420,
currency: 'EUR',
contents: [{ id: 'ers', quantity: 1 }],
content_type: 'product',
}, { eventID: '…' })
TikTok Pixel
mapping"product": { "view": { "name": "ViewContent", "data": {…} } }
sends
ttq.track('ViewContent', {
content_id: 'ers',
content_type: 'product',
value: 420,
currency: 'EUR',
}, { event_id: '…' })
Amplitude
mapping"product": { "view": { "name": "Product Viewed", "data": {…} } }
sends
amplitude.track('Product Viewed', {
product_id: 'ers',
price: 420,
currency: 'EUR',
})

50+ destination packages ship with the project. Removing GA4 or adding a new pixel is a block in this file, not a re-instrumentation project across every page.

How teams use it in production.

Media

One design system. ~50 components. No hand-written tracking code.

A major German media platform spent too much dev time hand-coding tracking around a single analytics vendor. They tagged their component library once, and now every product team ships tracking by default, reviewed in Storybook next to the component itself.

~50

components tagged once

Day 1

tracking on every new feature

Next vendor switch is a config change, not a project

Energy

From GTM workarounds to structured events.

A German energy provider ran a GTM container full of inconsistent event names and hand-written workarounds just to make the data usable. walkerOS now generates structured entity action events straight from the markup, with the same syntax everywhere, no cleanup scripts, and GTM back to just firing tags.

1

event syntax across every page

0

cleanup workarounds in GTM

Data the analytics team can trust

More features

Everything around the event, built in.

Same packages, same config.

Consent handling

Set the consent each destination needs. Until a visitor grants it, that destination's events wait in a queue and nothing is sent to it.

Docs

Storybook addon

See and test a component's tracking in isolation, in the same review as its design.

Docs

Session detection

Session starts with referrer, UTMs and click IDs. Works without storage, and switches to device IDs once consent is granted.

Docs

dataLayer migration

Existing GTM and GA4 pushes become walkerOS events. Migrate component by component instead of all at once.

Docs

Version controlled

Tracking config lives in your repo and goes through the same PR review, tests and deploys as your code.

Docs

AI-readiness

Fully typed, plus MCP servers and skills, so your coding agent can tag components and simulate flows.

Docs

Quickstart

From script tag to structured events in minutes.

No config, no build step. Works next to your existing Google Tag Manager setup.

  1. Install the script

    Add one script tag to every page, below your GTM snippet.

  2. Tag your components

    Name the entities, add their data, and say which actions count.

  3. Get rich dataLayer pushes

    Every interaction becomes one structured push, ready for GTM triggers.

Read full quickstart guide

Beyond the browser.

Once your events are structured, they can go further. Same event model, no re-instrumentation.

Server-side pipeline

Replace server-side GTM.

Run the same events through your own server pipeline on Express, AWS Lambda or GCP Functions. Validate, enrich and redact PII before anything reaches a vendor, and send conversions to Meta, Google Ads or TikTok server-to-server. No tags, triggers and variables to maintain per vendor, just one flow in your repo.

Raw data

Own your analytics data.

Send every event raw and structured straight into your warehouse, like BigQuery or ClickHouse. No sampling, no vendor-defined schema, no export limits. Query your own data directly, and use an analytics vendor only where you actually need one, or not at all.

Set up with your agent

Beyond the repo

Run it yourself, or bring us in.

The software stays MIT licensed and self-hostable either way.

Community

Open-source

Everything on this page. Clone it, read it, run it. Support via GitHub Discussions.

  • MIT licensed, no seat limits
  • All sources, destinations and transformers
  • Community support
Start free

Fixed scope

Implementation

We tag your design system with your team. We define the entity action event model, wire up the components and mappings, and hand over tracking your engineers own from day one.

  • Business questions mapped to events
  • Design system tagging and Storybook setup
  • Migration off dataLayer and GTM-based tracking
  • Custom source or destination builds
Scope a project

SLA

Support

A contract on top of the open-source project, for teams whose tracking drives revenue reporting or ad spend.

  • Guaranteed response times, direct access to the people who build walkerOS
  • Priority fixes and security patches
  • Upgrade guidance for production setups
Talk to us

FAQ

Questions we actually get.

Do I need a design system to use walkerOS?

No. Tagging works on any HTML: templates, CMS pages, plain markup or individual components. A design system just multiplies the effect, because a component you tag once is tracked everywhere it's used. Without one, you still get structured events and vendor-independent mapping, and you can migrate existing dataLayer pushes page by page.

We already have a tracking layer in-house. Why switch?

You don't have to throw it away. Most in-house setups are a tracking spec plus a helper function, and they still need a ticket per event. walkerOS gives you the declarative layer as an MIT-licensed, typed library you wrap in your own API, with your own prefix and your own components. You own the architecture; we maintain the plumbing.

Can't we just keep using Google Tag Manager, and doesn't marketing lose point-and-click tagging?

Yes, as a destination. GTM is good at firing tags, but it can't track anything until a developer hand-writes a push with structured data, and that's the ticket loop. walkerOS removes that step and can still feed GTM.

No. GTM keeps working for marketing, wired off clean, typed events. What it stops carrying is the custom scripts, consent hacks and naming conventions that pile up once it's the only place data gets shaped.

Does it work with our framework?

Yes. Tagging is plain data attributes, so it works with React, Vue, Svelte, web components or server-rendered HTML. A typed tagger helper keeps attributes consistent in TypeScript.