JavaScript Beacon
Events
Complete guide to event tracking with AgentShield Beacon
Event Types
AgentShield Beacon supports multiple event types for comprehensive tracking:
Built-in Event Types
Event Type | Description | When to Use |
---|---|---|
pageview | Page view tracking | On page load or route change |
pageunload | Page exit tracking | Before user leaves page |
error | Error tracking | When JavaScript errors occur |
custom | Custom events | User-defined interactions |
heartbeat | Keep-alive signal | Long-running sessions |
Event Structure
All events follow a consistent structure:
interface BeaconEvent {
// Core fields (automatically populated)
type: BeaconEventType;
timestamp: number;
sessionId: string;
// Context data (automatically collected)
data: {
url: string;
userAgent: string;
viewport: string;
screenResolution: string;
timezone: string;
language: string;
platform: string;
// ... additional browser data
};
// Custom metadata (user-provided)
metadata?: Record<string, any>;
}
Pageview Events
Pageview events are the most common type of tracking:
Basic Pageview
// Track current page
beacon.collect('pageview');
// Automatically includes:
// - Current URL
// - Referrer
// - User agent
// - Screen resolution
// - Viewport size
// - Session ID
Single Page Applications
// React Router
import { useLocation } from 'react-router-dom';
function App() {
const location = useLocation();
useEffect(() => {
beacon.collect('pageview');
}, [location.pathname]);
return <RouterProvider />;
}
// Vue Router
router.afterEach((to, from) => {
beacon.collect('pageview');
});
// Vanilla JavaScript
window.addEventListener('popstate', () => {
beacon.collect('pageview');
});
Enhanced Pageview Data
// Track with additional context
beacon.trackEvent('pageview_enhanced', {
page_type: 'article',
category: 'technology',
author: 'john-doe',
published_date: '2024-01-15',
word_count: 1500,
estimated_read_time: 6, // minutes
});
Custom Events
Custom events allow tracking specific user interactions:
E-commerce Events
// Product view
beacon.trackEvent('product_view', {
product_id: 'SKU-123',
product_name: 'Wireless Headphones',
category: 'Electronics',
price: 199.99,
currency: 'USD',
in_stock: true,
});
// Add to cart
beacon.trackEvent('add_to_cart', {
product_id: 'SKU-123',
quantity: 2,
cart_value: 399.98,
cart_items: 5,
});
// Purchase
beacon.trackEvent('purchase', {
order_id: 'ORD-456',
total: 425.97,
items: [
{ id: 'SKU-123', quantity: 2, price: 199.99 },
{ id: 'SKU-789', quantity: 1, price: 25.99 },
],
shipping: 10.0,
tax: 15.99,
payment_method: 'credit_card',
});
Content Events
// Article engagement
beacon.trackEvent('article_read', {
article_id: 'post-123',
title: 'Understanding AI Agents',
read_time: 245, // seconds
scroll_depth: 85, // percentage
comments_viewed: true,
shared: false,
});
// Video interaction
beacon.trackEvent('video_play', {
video_id: 'vid-456',
duration: 180,
autoplay: false,
quality: '1080p',
});
beacon.trackEvent('video_progress', {
video_id: 'vid-456',
current_time: 45,
percentage: 25,
buffered: true,
});
User Events
// Authentication
beacon.trackEvent('login', {
method: 'email',
success: true,
mfa_required: false,
provider: 'local',
});
beacon.trackEvent('signup', {
method: 'social',
provider: 'google',
referral_source: 'organic',
plan: 'free',
});
// User preferences
beacon.trackEvent('preference_change', {
setting: 'theme',
old_value: 'light',
new_value: 'dark',
});
Error Events
Automatically track and report errors:
Global Error Handler
window.addEventListener('error', (event) => {
beacon.trackEvent('javascript_error', {
message: event.message,
source: event.filename,
line: event.lineno,
column: event.colno,
stack: event.error?.stack,
user_agent: navigator.userAgent,
page: window.location.href,
});
});
window.addEventListener('unhandledrejection', (event) => {
beacon.trackEvent('promise_rejection', {
reason: event.reason?.toString(),
promise: event.promise?.toString(),
page: window.location.href,
});
});
Manual Error Tracking
try {
// Risky operation
performOperation();
} catch (error) {
beacon.trackEvent('operation_error', {
operation: 'data_processing',
error_type: error.name,
error_message: error.message,
error_stack: error.stack,
recovery_attempted: true,
});
// Handle error
}
API Error Tracking
fetch('/api/data')
.then((response) => {
if (!response.ok) {
beacon.trackEvent('api_error', {
endpoint: '/api/data',
status: response.status,
statusText: response.statusText,
method: 'GET',
});
}
return response.json();
})
.catch((error) => {
beacon.trackEvent('network_error', {
endpoint: '/api/data',
error: error.message,
type: 'fetch_failed',
});
});
Heartbeat Events
Keep sessions alive and track engagement:
// Send heartbeat every 30 seconds for active users
let heartbeatInterval;
let lastActivity = Date.now();
// Track user activity
document.addEventListener('mousemove', () => {
lastActivity = Date.now();
});
document.addEventListener('keypress', () => {
lastActivity = Date.now();
});
// Start heartbeat
heartbeatInterval = setInterval(() => {
const inactive = Date.now() - lastActivity > 60000; // 1 minute
if (!inactive) {
beacon.collect('heartbeat');
}
}, 30000);
// Clean up
window.addEventListener('beforeunload', () => {
clearInterval(heartbeatInterval);
});
Event Batching
Events are automatically batched for efficiency. You can control batching behavior through configuration.
Batching Configuration
const beacon = new AgentShieldBeacon({
apiKey: 'your-key',
batchSize: 20, // Send after 20 events
flushInterval: 5000, // Or after 5 seconds
maxQueueSize: 100, // Maximum events to queue
});
Manual Batch Control
// Force send all queued events
beacon.flush();
// Track multiple events then send
beacon.trackEvent('action_1', { step: 1 });
beacon.trackEvent('action_2', { step: 2 });
beacon.trackEvent('action_3', { step: 3 });
beacon.flush(); // Send all three events together
Event Validation
Ensure data quality with validation:
// Validate before sending
function trackPurchase(orderData) {
// Validate required fields
if (!orderData.order_id || !orderData.total) {
console.error('Invalid order data');
return;
}
// Validate data types
if (typeof orderData.total !== 'number') {
orderData.total = parseFloat(orderData.total);
}
// Sanitize data
const sanitized = {
order_id: orderData.order_id.toString(),
total: Math.round(orderData.total * 100) / 100,
currency: orderData.currency || 'USD',
items: orderData.items || [],
};
beacon.trackEvent('purchase', sanitized);
}
Event Enrichment
Add context to all events:
// Create wrapper with enrichment
class EnrichedBeacon {
constructor(beacon, userContext) {
this.beacon = beacon;
this.userContext = userContext;
}
trackEvent(name, data) {
// Add user context to all events
const enrichedData = {
...data,
user_id: this.userContext.userId,
user_type: this.userContext.userType,
experiment_group: this.userContext.experimentGroup,
timestamp_client: Date.now(),
};
return this.beacon.trackEvent(name, enrichedData);
}
}
const enrichedBeacon = new EnrichedBeacon(beacon, {
userId: 'user-123',
userType: 'premium',
experimentGroup: 'A',
});
Event Sampling
Reduce data volume with sampling:
// Sample 10% of events
function shouldSample(rate = 0.1) {
return Math.random() < rate;
}
if (shouldSample(0.1)) {
beacon.trackEvent('high_volume_event', data);
}
// Sample based on user
function getUserSampleRate(userId) {
// Consistent sampling per user
const hash = userId.split('').reduce((a, b) => {
a = (a << 5) - a + b.charCodeAt(0);
return a & a;
}, 0);
return Math.abs(hash) % 100 < 10; // 10% sample
}
if (getUserSampleRate(userId)) {
beacon.trackEvent('sampled_event', data);
}
Privacy Considerations
Always respect user privacy. Never track personally identifiable information (PII) without explicit consent.
Anonymizing Data
// Hash sensitive data
function hashEmail(email) {
return crypto.subtle.digest('SHA-256', new TextEncoder().encode(email)).then((buffer) => {
return Array.from(new Uint8Array(buffer))
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
});
}
// Track with hashed email
const hashedEmail = await hashEmail(userEmail);
beacon.trackEvent('user_action', {
email_hash: hashedEmail,
// Don't include: email: userEmail
});
Consent Management
// Check consent before tracking
function getTrackingConsent() {
return localStorage.getItem('tracking_consent') === 'granted';
}
if (getTrackingConsent()) {
beacon.trackEvent('user_action', data);
} else {
// Track only essential, anonymous data
beacon.trackEvent('anonymous_action', {
type: data.type,
// Exclude user-specific data
});
}
Performance Tips
- Batch events - Let the beacon batch events automatically
- Avoid blocking - Use async tracking for non-critical events
- Debounce high-frequency events - Limit scroll/mousemove tracking
- Use sampling - Sample high-volume, low-value events
- Clean up - Always destroy beacon on unmount
Next Steps
- Configuration - Advanced configuration options
- Worker Mode - Optimize with WebWorkers
- API Reference - Complete API documentation