AgentShield
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 TypeDescriptionWhen to Use
pageviewPage view trackingOn page load or route change
pageunloadPage exit trackingBefore user leaves page
errorError trackingWhen JavaScript errors occur
customCustom eventsUser-defined interactions
heartbeatKeep-alive signalLong-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
});
// 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

  1. Batch events - Let the beacon batch events automatically
  2. Avoid blocking - Use async tracking for non-critical events
  3. Debounce high-frequency events - Limit scroll/mousemove tracking
  4. Use sampling - Sample high-volume, low-value events
  5. Clean up - Always destroy beacon on unmount

Next Steps

Command Palette

Search for a command to run...