Skip to main content
Ask your AI

Tagger

Web Source code Package

The tagger is a utility for generating HTML data attributes that the walkerOS browser source uses for event tracking. It provides a fluent interface to create properly formatted and escaped data attributes for your HTML elements.

Why use the tagger?​

The tagger solves several challenges when working with walkerOS data attributes:

  • Consistent formatting - Ensures data attributes follow walkerOS conventions
  • Automatic escaping - Escapes semicolons, single quotes and backslashes in values, plus colons in keys, so the browser source reads them back as passed
  • Type safety - Provides TypeScript support for better development experience
  • Fluent API - Chainable methods for building complex attribute sets
  • Maintainability - Centralized logic for attribute generation

When to use the tagger​

Use the tagger when you need to:

  • Generate data attributes programmatically in JavaScript/TypeScript
  • Handle dynamic values that may contain special characters
  • Build complex attribute sets with multiple properties
  • Ensure consistent tagging across your application
  • Integrate walkerOS tracking into component-based frameworks (React, Vue, etc.)

Installation​

npm install @walkeros/web-source-browser

Initialization​

The tagger is initialized using the createTagger factory function:

import { createTagger } from '@walkeros/web-source-browser';

// Create with default configuration
const tagger = createTagger();

// Create with custom configuration
const customTagger = createTagger({
prefix: 'data-elb',
});

Configuration​

PropertyTypeDescriptionMore
prefixstringCustom prefix for generated data attributes

Usage examples​

Basic data tagging (without entity)​

const tagger = createTagger();

// Using tagger with a scope parameter sets naming for data attributes only
const attributes = tagger('product')
.data('id', '123')
.data('name', 'Widget')
.get();

// Result:
// {
//   'data-elb-product': 'id:123;name:Widget'
// }
// Note: No 'data-elb' entity attribute is created

Entity tagging​

// To create an entity attribute, use the .entity() method
const attributes = tagger()
.entity('product')
.data('id', '123')
.data('name', 'Widget')
.get();

// Result:
// {
//   'data-elb': 'product',
//   'data-elb-product': 'id:123;name:Widget'
// }

Action mapping​

const attributes = tagger()
.action('load', 'view')
.action('click', 'select')
.get();

// Result:
// {
//   'data-elbaction': 'load:view;click:select'
// }

Context and global properties​

const attributes = tagger()
.entity('product')
.data('id', 123)
.context('test', 'engagement')
.globals('lang', 'en')
.get();

// Result:
// {
//   'data-elb': 'product',
//   'data-elb-product': 'id:123',
//   'data-elbcontext': 'test:engagement',
//   'data-elbglobals': 'lang:en'
// }

Scoped generic properties​

scoped() emits the data-elb_ attribute: a generic property that only reaches triggers nested below the element, unlike data-elb- which every trigger in the entity receives. It uses the same value syntax and escaping as the other methods.

const attributes = tagger()
.entity('product')
.data('name', 'A')
.scoped('size', 'L')
.get();

// Result:
// {
//   'data-elb': 'product',
//   'data-elb-product': 'name:A',
//   'data-elb_': 'size:L'
// }

Multiple entity scopes​

// Starting with a naming scope
const attributes = tagger('product')
.data('id', 123)
.entity('user') // Changes both entity attribute and naming scope
.data('name', 'John')
.get();

// Result:
// {
//   'data-elb': 'user',
//   'data-elb-product': 'id:123',
//   'data-elb-user': 'name:John'
// }

Order matters​

// Data before entity uses original scope
const attributes = tagger('product')
.data('id', 123)
.data('price', 99.99)
.entity('cart') // Changes scope for future data calls
.data('quantity', 2)
.get();

// Result:
// {
//   'data-elb': 'cart',
//   'data-elb-product': 'id:123;price:99.99',
//   'data-elb-cart': 'quantity:2'
// }

Value escaping​

The tagger puts a backslash before every semicolon, single quote and backslash in keys and values, and before colons in keys. These are the escapes the browser source reads, so the value arrives as passed.

const attributes = tagger()
.data('description', "Men's shirt: size L; blue")
.get();

// Result:
// {
//   'data-elb-': "description:Men\\'s shirt: size L\\; blue"
// }

Like any attribute value, it is still cast to a number or boolean where it looks like one, trimmed of surrounding whitespace, and read from the element when it starts with #.

Available methods (API reference)​

tagger(scope?: string)​

Creates a new tagger instance. The optional scope parameter sets the naming scope for data attributes without creating an entity attribute.

// Without scope - generic data attributes
tagger().data('key', 'value');
// Creates: data-elb-="key:value"

// With scope - scoped data attributes (no entity attribute)
tagger('product').data('id', '123');
// Creates: data-elb-product="id:123"
entity(name: string)​

Sets the entity attribute and updates the naming scope for subsequent data calls.

tagger().entity('product').data('id', '123');
// Creates: data-elb="product" data-elb-product="id:123"

// Entity changes the naming scope
tagger('foo').entity('bar').data('a', 1);
// Creates: data-elb="bar" data-elb-bar="a:1"
data(key: string, value: Property) | data(object: Properties)​

Adds data properties using the current naming scope.

// Single property
tagger('product').data('id', 123);
// Creates: data-elb-product="id:123"

// Multiple properties
tagger('product').data({ id: 123, name: 'Widget', price: 99.99 });
// Creates: data-elb-product="id:123;name:Widget;price:99.99"
action(trigger: string, action?: string) | action(object: Record<string, string>)​

Adds action mappings for event triggers. Creates a data-elbaction attribute.

// Single action
tagger().action('load', 'view');

// Combined trigger:action
tagger().action('load:view');

// Multiple actions
tagger().action({ load: 'view', click: 'select', impression: 'view' });
actions(trigger: string, action?: string) | actions(object: Record<string, string>)​

Adds action mappings that apply to the nearest entity and every entity above it. Creates a data-elbactions attribute, which on its own works for the click and submit triggers only. Use action() for every other trigger.

// Single action
tagger().actions('click', 'select');

// Combined trigger:action
tagger().actions('click:select');

// Multiple actions
tagger().actions({ click: 'select', submit: 'send' });

// Can be combined with action() method
tagger().action('load', 'view').actions('click', 'select');
context(key: string, value: Property) | context(object: Properties)​

Adds context properties for events triggered inside the element.

// Single context
tagger().context('test', 'engagement');

// Multiple contexts
tagger().context({ test: 'engagement', position: 'header', type: 'promo' });
globals(key: string, value: Property) | globals(object: Properties)​

Adds global properties that apply to every event on the page.

// Single global
tagger().globals('lang', 'en');

// Multiple globals
tagger().globals({ lang: 'en', plan: 'paid', version: '1.0' });
scoped(key: string, value: Property) | scoped(object: Properties)​

Adds path-scoped generic properties. Creates a data-elb_ attribute that only applies to triggers nested below the element.

// Single scoped property
tagger().scoped('size', 'L');
// Creates: data-elb_="size:L"

// Multiple scoped properties
tagger().scoped({ size: 'L', color: 'red' });
// Creates: data-elb_="size:L;color:red"
link(id: string, type: string) | link(object: Record<string, string>)​

Sets the element's link to another element. An element carries one link: a second, different link or an object with more than one entry throws an error.

tagger().link('details', 'parent');
// Creates: data-elblink="details:parent"

// Same link as an object with one entry
tagger().link({ details: 'parent' });
get()​

Generates the final HTML attributes object.

// With naming scope only
const attributes = tagger('product').data('id', '123').get();
// Returns: { 'data-elb-product': 'id:123' }

// With entity attribute
const attributes = tagger().entity('product').data('id', '123').get();
// Returns: { 'data-elb': 'product', 'data-elb-product': 'id:123' }

All methods return the tagger instance for method chaining, except get() which returns the final attributes object.

Common use cases​

Product listing page​

// For product cards with nearest entity tracking only
function ProductCard({ product }) {
return (
<div
{...tagger('product')
  .data({
    id: product.id,
    name: product.name,
    price: product.price,
    category: product.category
  })
  .action('click', 'select') // Only tracks the product entity
  .get()}
>
{product.name}
</div>
);
}

// For product cards that also need page context tracking
function ProductCardWithContext({ product }) {
return (
<div className="page-section" data-elb="page" data-elb-page="section:products">
<div
  {...tagger('product')
    .data({
      id: product.id,
      name: product.name,
      price: product.price,
      category: product.category
    })
    .actions('click', 'select') // Uses data-elbactions
    .get()}
>
  {product.name}
</div>
</div>
);
}

Shopping cart​

// For cart items that need both entity and data attributes
function CartItem({ item }) {
return (
<div
{...tagger()
  .entity('cart')
  .data({
    productId: item.id,
    quantity: item.quantity,
    price: item.price
  })
  .action('click', 'remove')
  .get()}
>
{item.name}
</div>
);
}

Dynamic component tracking​

// Reusable tracking function
function trackComponent(type, data, actions = {}) {
return tagger(type)
.data(data)
.action(actions)
.get();
}

// Usage
<button {...trackComponent('cta', { label: 'Sign Up', position: 'header' }, { click: 'signup' })}>
Sign Up
</button>
💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)