Migration guide: from @elbwalker to @walkerOS
This guide helps you migrate from the old elbwalker packages to the new walkerOS packages.
Quick reference
Core package changes
@elbwalker/walker.js→@walkeros/collector+@walkeros/web-source-browser@elbwalker/types+@elbwalker/utils→@walkeros/core@elbwalker/destination-web-*→@walkeros/web-destination-*@elbwalker/destination-node-*→@walkeros/server-destination-*
Step-by-step migration
1. Update dependencies
Before:
{
"dependencies": {
"@elbwalker/walker.js": "^2.0.0",
"@elbwalker/destination-web-google-ga4": "^2.0.0"
}
}After:
{
"dependencies": {
"@walkeros/collector": "^4.6.0",
"@walkeros/web-source-browser": "^4.6.0",
"@walkeros/web-destination-gtag": "^4.6.0"
}
}2. Update imports
Before:
import { Walkerjs } from '@elbwalker/walker.js';
import { destinationGoogleGA4 } from '@elbwalker/destination-web-google-ga4';
import type { WalkerOS } from '@elbwalker/types';After:
import { startFlow } from '@walkeros/collector';
import { sourceBrowser } from '@walkeros/web-source-browser';
import { destinationGtag } from '@walkeros/web-destination-gtag';
import type { WalkerOS } from '@walkeros/core';3. Update function calls
Before:
const walker = Walkerjs({
destinations: [destinationGoogleGA4],
});After:
const { elb } = await startFlow({
sources: {
browser: {
code: sourceBrowser,
config: {
settings: { scope: document.body },
},
},
},
destinations: {
gtag: {
code: destinationGtag,
config: {
settings: {
ga4: { measurementId: 'G-XXXXXXXXXX' },
},
},
},
},
});Breaking changes
1. Unified collector
- Single
@walkeros/collectorpackage works across all platforms - Use
startFlow()instead ofWalkerjs()orcreateSourceNode()
2. Modular sources
- DOM tracking is now
@walkeros/web-source-browser - Import and initialize sources separately
3. Core package merger
- All types and utilities now come from
@walkeros/core - Update all import statements accordingly
4. Google destinations unified
- GA4, Google Ads, and GTM are now unified in
@walkeros/web-destination-gtag - Configure all Google services through a single destination
Destination configuration patterns
Unified configuration approach
Configure all sources and destinations in a single startFlow call:
const { elb } = await startFlow({
sources: {
browser: {
code: sourceBrowser,
config: {
settings: { scope: document.body },
},
},
},
destinations: {
gtag: {
code: destinationGtag,
config: {
settings: {
ga4: { measurementId: 'G-XXXXXXXXXX' },
},
},
},
},
});Benefits:
- One configuration describes the entire tracking setup
- Full type safety, with configs linked to their packages
- No manual destination registration
- Code and configuration stay separate
Migration checklist
Package dependencies
- [ ] Remove old
@elbwalker/*packages - [ ] Add
@walkeros/collector - [ ] Add required sources and destinations
- [ ] Add
@walkeros/corefor custom implementations
Code updates
- [ ] Update all imports to new packages
- [ ] Replace collector initialization with
startFlow() - [ ] Update type imports to use
@walkeros/core - [ ] Test functionality after migration
Common issues
"Cannot find module @walkeros/web-collector"
Solution: Use @walkeros/collector + @walkeros/web-source-browser
"elb is not defined"
Solution: elb is returned by startFlow() function
TypeScript cannot find types
Solution: Import types from @walkeros/core
data-elbaction vs data-elbactions
Breaking change in @walkeros packages
The behavior of data-elbaction has changed to improve performance and provide
more precise entity targeting:
- @elbwalker behavior:
data-elbactionapplied to all entities in the DOM hierarchy - @walkeros behavior:
data-elbactionapplies to nearest entity only
Migration strategy
Option 1: keep current behavior (recommended for migration)
Replace data-elbaction with data-elbactions to keep the same behavior for
the click and submit triggers:
<!-- Before (@elbwalker) -->
<div data-elb="parent">
<div data-elb="child" data-elbaction="click:action">
<!-- Triggered both parent and child entities -->
</div>
</div>
<!-- After (@walkeros) - Same behavior -->
<div data-elb="parent">
<div data-elb="child" data-elbactions="click:action">
<!-- Triggers both parent and child entities -->
</div>
</div>data-elbactions on its own fires only for the click and submit triggers.
All other triggers, such as load, visible, impression, hover, scroll,
wait, and pulse, start only from an element with data-elbaction, which
applies to the nearest entity; a matching data-elbactions entry on that same
element takes precedence and applies to all entities.
Option 2: use new behavior (recommended for new projects)
Use data-elbaction for more precise tracking that fires fewer events:
<!-- @walkeros - New behavior -->
<div data-elb="parent">
<div data-elb="child" data-elbaction="click:action">
<!-- Only triggers child entity -->
</div>
</div>When to use each
Use data-elbaction (nearest entity) when:
- You want precise tracking of only the specific entity
- Performance is critical (fewer events)
- Implementing new features
Use data-elbactions (all entities; on its own, click and submit only) when:
- Migrating from @elbwalker and need same behavior
- You need context from parent entities
- Analytics requires full DOM hierarchy
Tagger API
The tagger also provides both methods:
// Nearest entity only (data-elbaction)
tagger().action('click', 'select').get();
// All entities (data-elbactions)
tagger().actions('click', 'select').get();visible vs impression triggers
Breaking change in @walkeros packages
The visibility trigger names have been updated to better reflect their behavior:
visibletrigger: Now fires multiple times when element re-enters viewport (wasvisibles)impressiontrigger: Fires once only when element first becomes visible (wasvisible)
Migration strategy
Option 1: update trigger names (recommended)
Update your HTML to use the new trigger names:
<!-- Before (@elbwalker and early @walkeros) -->
<div data-elbaction="visible:view">Single fire</div>
<div data-elbaction="visibles:track">Multiple fires</div>
<!-- After (@walkeros current) -->
<div data-elbaction="impression:view">Single fire</div>
<div data-elbaction="visible:track">Multiple fires</div>Option 2: understand the behavior change
If you keep using the old names, understand the behavior has changed:
- Old
visiblebehavior (single-fire) → Now useimpression - Old
visiblesbehavior (multiple-fire) → Now usevisible
When to use each
Use impression trigger when:
- You want to track when content is first seen
- Measuring ad impressions or content views
- One-time engagement metrics
Use visible trigger when:
- You want to track repeated interactions
- Measuring scroll behavior or re-engagement
- Analytics requires multiple visibility events
Tagger API
The tagger supports both trigger types:
// Single impression (fires once)
tagger().action('impression', 'view').get();
// Multiple visibility (fires each time visible)
tagger().action('visible', 'track').get();