Skip to main content

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 - Handles special characters in values (semicolons, colons, quotes, backslashes)
  • 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('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

const attributes = tagger()
.data('description', 'Product with: special; chars & "quotes"')
.get();

// Result:
// {
//   'data-elb-': 'description:Product with\\: special\\; chars & \\"quotes\\"'
// }

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 for event triggers. Creates a data-elbactions attribute.

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

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

// Multiple actions
tagger().actions({ load: 'view', click: 'select', visible: 'visible' });

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

Adds context properties that apply to all events.

// 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 persist across page views.

// 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>)

Adds link relationships between elements.

// Single link
tagger().link('details', 'parent');

// Multiple links
tagger().link({ details: 'parent', modal: 'child', sidebar: 'child' });
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)