AgentShield
JavaScript Beacon

Basic Usage

Learn how to use the AgentShield Beacon for AI agent detection

Getting Started

Once you've installed the beacon, here's how to use it effectively.

Basic Initialization

import { AgentShieldBeacon } from '@kya-os/agentshield-beacon';

// Minimal configuration
const beacon = new AgentShieldBeacon({
  apiKey: 'your-api-key'
});

// With recommended settings
const beacon = new AgentShieldBeacon({
  apiKey: 'your-api-key',
  batchSize: 20,           // Batch 20 events before sending
  flushInterval: 5000,     // Auto-send every 5 seconds
  useWorker: true,         // Use WebWorker for better performance
  debug: false             // Set to true in development
});

Tracking Page Views

The most basic use case is tracking page views:

// Track current page view
beacon.collect('pageview');

// Track on route changes (SPA)
window.addEventListener('popstate', () => {
  beacon.collect('pageview');
});

// React Router example
import { useLocation } from 'react-router-dom';

function App() {
  const location = useLocation();
  
  useEffect(() => {
    beacon.collect('pageview');
  }, [location]);
  
  return <Routes>...</Routes>;
}

Tracking Custom Events

Track specific user interactions and behaviors:

Basic Event Tracking

// Simple event
beacon.trackEvent('button_click');

// Event with metadata
beacon.trackEvent('form_submit', {
  formId: 'signup-form',
  fields: ['email', 'name'],
  timestamp: Date.now()
});

// Async with error handling
try {
  await beacon.trackEvent('purchase', {
    productId: 'SKU123',
    price: 29.99,
    currency: 'USD'
  });
  console.log('Purchase tracked');
} catch (error) {
  console.error('Tracking failed:', error);
}

Common Event Patterns

// User authentication
beacon.trackEvent('login_attempt', {
  method: 'email',
  success: true
});

// Content interaction
beacon.trackEvent('article_read', {
  articleId: '123',
  readTime: 45,
  scrollDepth: 0.8
});

// E-commerce
beacon.trackEvent('add_to_cart', {
  productId: 'PROD-456',
  quantity: 2,
  value: 59.98
});

// Search
beacon.trackEvent('search', {
  query: 'javascript tutorial',
  results: 42,
  filters: ['beginner', 'free']
});

Session Management

The beacon automatically manages sessions, but you can customize behavior:

const beacon = new AgentShieldBeacon({
  apiKey: 'your-api-key',
  sessionTimeout: 1800000,           // 30 minutes
  sessionCookieName: '_as_session'   // Custom cookie name
});

// Get current session ID
const sessionId = beacon.getSessionId();

// Force new session
beacon.resetSession();

Page Unload Tracking

Ensure events are sent even when users leave:

// Track page unload
window.addEventListener('beforeunload', () => {
  beacon.trackPageUnload();
});

// Or use visibilitychange for better reliability
document.addEventListener('visibilitychange', () => {
  if (document.hidden) {
    beacon.flush(); // Send all pending events
  }
});

Working with Forms

const form = document.getElementById('contact-form');

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  
  // Track form submission
  await beacon.trackEvent('form_submit', {
    formId: 'contact-form',
    fields: Array.from(form.elements)
      .filter(el => el.name)
      .map(el => el.name)
  });
  
  // Submit form
  form.submit();
});

// Track form abandonment
let formStarted = false;
form.addEventListener('input', () => {
  if (!formStarted) {
    formStarted = true;
    beacon.trackEvent('form_start', {
      formId: 'contact-form'
    });
  }
});

window.addEventListener('beforeunload', () => {
  if (formStarted && !form.submitted) {
    beacon.trackEvent('form_abandon', {
      formId: 'contact-form'
    });
  }
});
function ContactForm() {
  const [started, setStarted] = useState(false);
  
  const handleSubmit = async (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);
    
    await beacon.trackEvent('form_submit', {
      formId: 'contact-form',
      fields: Array.from(formData.keys())
    });
    
    // Submit logic
  };
  
  const handleInput = () => {
    if (!started) {
      setStarted(true);
      beacon.trackEvent('form_start', {
        formId: 'contact-form'
      });
    }
  };
  
  useEffect(() => {
    return () => {
      if (started) {
        beacon.trackEvent('form_abandon', {
          formId: 'contact-form'
        });
      }
    };
  }, [started]);
  
  return (
    <form onSubmit={handleSubmit} onInput={handleInput}>
      {/* Form fields */}
    </form>
  );
}
<template>
  <form @submit.prevent="handleSubmit" @input="handleInput">
    <!-- Form fields -->
  </form>
</template>

<script setup>
import { ref, onUnmounted } from 'vue';

const started = ref(false);

const handleSubmit = async (e) => {
  const formData = new FormData(e.target);
  
  await beacon.trackEvent('form_submit', {
    formId: 'contact-form',
    fields: Array.from(formData.keys())
  });
  
  // Submit logic
};

const handleInput = () => {
  if (!started.value) {
    started.value = true;
    beacon.trackEvent('form_start', {
      formId: 'contact-form'
    });
  }
};

onUnmounted(() => {
  if (started.value) {
    beacon.trackEvent('form_abandon', {
      formId: 'contact-form'
    });
  }
});
</script>

Error Tracking

Automatically track JavaScript errors:

// Global error handler
window.addEventListener('error', (event) => {
  beacon.trackEvent('error', {
    message: event.message,
    source: event.filename,
    line: event.lineno,
    column: event.colno,
    stack: event.error?.stack
  });
});

// Promise rejection handler
window.addEventListener('unhandledrejection', (event) => {
  beacon.trackEvent('unhandled_rejection', {
    reason: event.reason,
    promise: event.promise.toString()
  });
});

Performance Monitoring

Track performance metrics:

// Page load performance
window.addEventListener('load', () => {
  const perfData = performance.getEntriesByType('navigation')[0];
  
  beacon.trackEvent('performance', {
    domContentLoaded: perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart,
    loadComplete: perfData.loadEventEnd - perfData.loadEventStart,
    domInteractive: perfData.domInteractive,
    firstPaint: performance.getEntriesByName('first-paint')[0]?.startTime
  });
});

// Track slow interactions
const startTime = performance.now();

// After some operation
const duration = performance.now() - startTime;
if (duration > 1000) {
  beacon.trackEvent('slow_interaction', {
    operation: 'data_fetch',
    duration: Math.round(duration)
  });
}

User Engagement Tracking

// Time on page
let startTime = Date.now();

window.addEventListener('beforeunload', () => {
  const timeOnPage = Date.now() - startTime;
  beacon.trackEvent('engagement', {
    timeOnPage: Math.round(timeOnPage / 1000), // seconds
    page: window.location.pathname
  });
});

// Scroll depth
let maxScroll = 0;

window.addEventListener('scroll', () => {
  const scrollPercent = (
    window.scrollY / 
    (document.documentElement.scrollHeight - window.innerHeight)
  ) * 100;
  
  maxScroll = Math.max(maxScroll, scrollPercent);
});

window.addEventListener('beforeunload', () => {
  beacon.trackEvent('scroll_depth', {
    maxDepth: Math.round(maxScroll),
    page: window.location.pathname
  });
});

// Click tracking
document.addEventListener('click', (e) => {
  const target = e.target.closest('[data-track]');
  if (target) {
    beacon.trackEvent('click', {
      element: target.dataset.track,
      text: target.textContent,
      href: target.href
    });
  }
});

Conditional Tracking

Respect user privacy preferences:

// Check Do Not Track
const respectDNT = navigator.doNotTrack === '1';

if (!respectDNT) {
  beacon.collect('pageview');
}

// Check user consent
const hasConsent = localStorage.getItem('tracking-consent') === 'true';

if (hasConsent) {
  beacon.trackEvent('user_action', data);
}

// Conditional initialization
function initializeTracking() {
  if (shouldTrack()) {
    return new AgentShieldBeacon({
      apiKey: 'your-key',
      respectDoNotTrack: true
    });
  }
  return null;
}

Best Practices

Performance Tip: Use batching and WebWorker mode to minimize impact on your application's performance.

1. Initialize Once

// Good: Single instance
const beacon = new AgentShieldBeacon(config);
export default beacon;

// Bad: Multiple instances
function trackEvent() {
  const beacon = new AgentShieldBeacon(config); // Don't do this
  beacon.trackEvent('action');
}

2. Use Async/Await

// Good: Handle async properly
async function trackAction() {
  try {
    await beacon.trackEvent('action', data);
    // Continue after tracking
  } catch (error) {
    // Handle error gracefully
    console.error('Tracking failed:', error);
  }
}

// Bad: Fire and forget without error handling
beacon.trackEvent('action', data); // No error handling

3. Clean Up Resources

// Good: Clean up on unmount
useEffect(() => {
  const beacon = new AgentShieldBeacon(config);
  
  return () => {
    beacon.destroy();
  };
}, []);

// Bad: Memory leak
useEffect(() => {
  const beacon = new AgentShieldBeacon(config);
  // No cleanup
}, []);
// Good: Use batching
beacon.trackEvent('product_view', { id: '1' });
beacon.trackEvent('product_view', { id: '2' });
beacon.trackEvent('product_view', { id: '3' });
// These will be sent in one batch

// Bad: Force immediate sends
beacon.trackEvent('product_view', { id: '1' });
beacon.flush();
beacon.trackEvent('product_view', { id: '2' });
beacon.flush();
// Multiple network requests

Debugging

Enable debug mode during development:

const beacon = new AgentShieldBeacon({
  apiKey: 'your-key',
  debug: true,
  logLevel: 'debug'
});

// Check the console for:
// - Event tracking logs
// - API requests and responses
// - Configuration details
// - Error messages

Next Steps

Command Palette

Search for a command to run...