Features Overview
Event Lens organises its capabilities into four areas: Capture, Analyze, Debug, Advanced.
Capture — Catch Events
Event Lens automatically captures the following.
CustomEvent / dispatchEvent
document.dispatchEvent(new CustomEvent('user:logged-in', {
detail: { userId: 123, timestamp: Date.now() }
}));
In Event Lens:
CustomEvent:user:logged-in
Payload: { userId: 123, timestamp: 1714756800000 }
Source: app.js:42
Subscribers: 3 listeners
postMessage
window.postMessage({ type: 'UPDATE', data: { /* ... */ } }, '*');
In Event Lens:
postMessage:UPDATE
Payload: { type: 'UPDATE', data: { ... } }
Origin: https://myapp.com
Correlated API: POST /api/sync (fired 50ms later)
BroadcastChannel
const channel = new BroadcastChannel('user-sync');
channel.postMessage({ action: 'LOGOUT' });
In Event Lens:
BroadcastChannel:user-sync:LOGOUT
Payload: { action: 'LOGOUT' }
Cross-tab: Other tabs receive it too
Delivery: Broadcast (one-to-many)
Event Bus (auto-detect)
Event Lens automatically finds event buses attached to window.
window.eventBus = new EventEmitter();
window.eventBus.emit('checkout:completed', { orderId: 'ORD-123' });
In Event Lens:
PubSub:checkout:completed
Pattern: emit/on (EventEmitter)
Payload: { orderId: 'ORD-123' }
Subscribers: updateUI(), trackAnalytics(), sendNotification()
Delivery: Sync
Supported patterns:
emit/on(EventEmitter).emit/addEventListener.dispatch/on.dispatch/subscribe.publish/subscribe.fire/on.trigger/on.send/on.notify/subscribe.
Manual SDK hook
If auto-detect doesn't work for your bus, hook in explicitly:
window.__REACT_EVENT_LENS__ = {
onEvent: function (callback) {
yourCustomBus.on('*', callback);
}
};
Event Lens picks up this hook and connects to it.
fetch / XMLHttpRequest
fetch('/api/cart/items', {
method: 'POST',
body: JSON.stringify({ /* ... */ })
});
In Event Lens:
Network:fetch:POST /api/cart/items
Triggered by: cart:item-added (50ms earlier)
Status: 200 OK
Duration: 145ms
Response: { success: true, itemCount: 5 }
Analyze — Understand Events
Schema drift detection
The shape of each event payload is checked on every fire:
First emission:
{ "userId": 123, "email": "[email protected]" }
Second emission:
{ "userId": 456, "email": "[email protected]", "role": "admin" } <- new key!
Event Lens shows a [DRIFT] badge.
Badges:
DRIFT— new keys appeared or a type changed.-KEYS— keys present in earlier payloads are missing.DRIFT -KEYS— both at once.
A changing payload shape can quietly break subscribers, which is why this matters.
Duplicate detection
If the same event fires with the same payload in quick succession:
cart:item-added { "itemId": 123 } First
cart:item-added { "itemId": 123 } DUP
cart:item-added { "itemId": 123 } DUP x3
Badge: DUP x3.
Duplicates often hide buggy handler logic or accidental double-emits.
Performance budget
Define limits for event behavior:
Settings → Budget
Max payload size: 50 KB
Max frequency: 100 events/sec
Max subscriber duration: 100 ms
Max total per minute: 10,000 events
When a rule is violated the event gets an OVER BUDGET badge.
Slow subscriber detection
When a handler takes too long:
user:login
updateUI() 2ms
trackAnalytics() 85ms <- SLOW
syncCache() 3ms
Total: 90ms
Slow handlers can freeze the UI.
Event chains
When events trigger each other, the chain is visualised:
user:click (user clicked)
| 5ms
product:selected (product selected)
| 8ms
api:request (API call)
| 145ms
api:response (response received)
| 2ms
ui:updated (UI refreshed)
Network correlation
Events and API requests share a single timeline:
Timeline (ms):
0 cart:item-added
50 fetch /api/cart (200ms)
100 analytics:track
250 fetch /api/analytics (100ms)
Event Lens automatically figures out how many ms after an event each API call happened.
Debug — Test Events
Event replay
Re-fire an event with its original payload:
Event: cart:item-added { "itemId": 123, "quantity": 1 }
Action: [Replay]
Result: The event fires again on the page; the UI updates.
Confirmation required — guards against accidental triggers.
Payload editor
Replay an event with a modified payload:
Original:
{ "itemId": 123, "quantity": 1 }
Edited:
{ "itemId": 456, "quantity": 5 }
[Replay Edited] (no confirmation — editing is itself the intent)
Useful for testing edge cases and probing subscriber behavior with different inputs.
Breakpoints
Pause the debugger when an event fires:
- Right-click an event → Breakpoint.
- When the event fires, execution pauses.
- Inspect state before subscribers run.
- Resume to continue.
Replay queue
Replay multiple events in order:
Event 1: user:login
Event 2: product:viewed
Event 3: cart:item-added
Event 4: checkout:completed
[Play All] replays each in sequence with a 500 ms delay.
For simulating complex user flows and integration tests.
Conditional filters
Find events with a multi-field filter:
Filter:
Event name contains "cart"
Payload.itemId equals "123"
Source contains "app.js"
Warning type is "SLOW"
Only events that match every condition remain visible.
Advanced
Memory leak detection
addEventListener / removeEventListener balance is tracked:
Active listeners (by event type):
resize
Added: 5
Removed: 2
Outstanding: 3 <- potential leak
Last added: app.js:142
scroll
Added: 10
Removed: 10
Outstanding: 0
Thresholds:
- Listener count > 50 →
HIGHseverity. - Unbounded growth in a 10s window →
MEDIUMseverity.
Session capture
Record a user flow:
[Start recording]
-> clicked .product-card
-> scrolled 500px
-> filled #email input
-> clicked [Submit]
-> navigated to /order-confirmation
[Stop recording]
-> Export to JSON
What the JSON captures:
- User flow — clicks, scrolls, inputs, navigation.
- DOM mutations — node additions and removals.
- DOM snapshots — page state at intervals.
- Events — every event with its timeline.
Use cases: bug reproduction (share the JSON), regression tests, validating complex flows.
Delivery tracking
Per-subscriber delivery status for custom event buses:
checkout:completed
Delivery model: ACK / NACK
updateOrderTable() ACK (success)
sendConfirmationEmail() NACK (error: email service down)
updateAnalytics() PENDING (async, not yet resolved)
triggerNotification() ACK
Summary:
Success: 2
Failed: 1
Pending: 1
Tells you at a glance which handlers succeeded, failed, or are still in flight.
Leak report
Detailed report on memory leaks:
HIGH severity: resize listener leak
Current count: 87 listeners (threshold: 50)
Added in last 10s: 25
Removed in last 10s: 0
Growth rate: +25/sec
Outstanding listeners:
addEventListener(...) app.js:142
addEventListener(...) utils.js:89
... (85 more)
Where added:
ResizeObserver cleanup (15 times)
Window resize handler (10 times)
Performance Budgets
A violated budget surfaces an OVER BUDGET badge on the event and a row in the Budget tab:
Budget Rules:
Max payload: 50 KB VIOLATED (78 KB)
Max frequency: 100/sec VIOLATED (120/sec)
Max subscriber duration: 100ms VIOLATED (250ms)
Max total/min: 10,000 OK
Violations:
[x3] event:large-payload (78 KB)
[x12] event:frequent (20/sec)
[x1] event:slow-subscriber (250ms handler)
Clients Tab
Aggregate view: who is listening to what.
By Subscriber:
updateUI() listens to:
cart:updated (45 fires)
user:changed (12 fires)
[Transport: Event Bus]
trackAnalytics() listens to:
button:click (234 fires)
page:scroll (567 fires)
[Transport: DOM]
By Topic:
cart:updated (45 fires)
updateUI() 1ms
persistToLocalStorage() 2ms
triggerNotification() 50ms
Export / Import
Export the session to JSON, import it later:
{
"version": 2,
"exportedAt": "2026-05-08T14:03:21Z",
"url": "https://myapp.com/products",
"events": [],
"networkRequests": [],
"leakReport": [],
"listenerCounts": [],
"breakpoints": ["cart:item-added"],
"budget": {},
"replayHistory": []
}
Use cases: attach a session to a bug report, do offline analysis, commit test cases to a repo.
Theme
Dark (default, Catppuccin Mocha) and Light modes are available.
Settings → Theme
Dark (default)
Light
The choice is persisted in localStorage.