FullStory Event Tracking
Overview
Event tracking in FullStory allows you to capture custom user actions, business events, and behavioral signals beyond automatic page views and clicks. By implementing custom events, you can track specific interactions like button clicks, form submissions, feature usage, errors, and business outcomes.
FullStory's event tracking is powered by the FS.event() API, which lets you send custom events with properties and metadata. Combined with FS.identify() for user identification, you can build rich behavioral datasets that power Omnisearch, funnels, segments, and session replay filters.
Why Track Custom Events?
While FullStory automatically captures clicks, page views, and form interactions, custom events let you track:
- Business-specific actions: Add to cart, checkout, subscription upgrades
- Feature usage: Toggle settings, open modals, use search
- User milestones: Complete onboarding, reach usage limits, achieve goals
- Error states: API failures, validation errors, timeout issues
- Custom workflows: Multi-step processes, conditional logic, A/B test variants
Custom events make your FullStory data more meaningful and actionable by aligning tracking with your product's unique behaviors.
The FS.event() API
Basic Syntax
FS.event(eventName, eventProperties);
Parameters:
eventName(string, required): The name of the event (e.g., "Clicked CTA Button")eventProperties(object, optional): Key-value pairs with additional context
Simple Event Example
Track a button click:
FS.event('Signup Button Clicked');
This creates a searchable event in FullStory. You can later search for sessions where this event occurred using Omnisearch.
Event with Properties
Track a button click with additional context:
FS.event('Signup Button Clicked', {
location: 'homepage',
button_color: 'blue',
campaign: 'summer_promo'
});
Event properties allow you to filter and segment events by specific attributes. For example, you can search for "Signup Button Clicked where location is homepage."
Event Naming Best Practices
Use clear, descriptive names:
// Good
FS.event('Checkout Started');
FS.event('Video Played');
FS.event('Filter Applied');
// Bad
FS.event('click');
FS.event('event1');
FS.event('action');
Use consistent naming conventions:
// Consistent pattern: Action + Object
FS.event('Clicked Pricing CTA');
FS.event('Submitted Contact Form');
FS.event('Viewed Product Page');
Avoid special characters:
// Good
FS.event('Add to Cart');
// Bad
FS.event('Add-to-Cart!');
FS.event('add_to_cart#123');
Common Event Tracking Patterns
Button Clicks
Track specific button interactions:
document.getElementById('cta-button').addEventListener('click', function() {
FS.event('CTA Button Clicked', {
button_text: this.innerText,
page: window.location.pathname,
timestamp: new Date().toISOString()
});
});
Form Submissions
Track form submissions with context:
document.getElementById('contact-form').addEventListener('submit', function(e) {
FS.event('Contact Form Submitted', {
form_name: 'Contact Us',
page: window.location.pathname,
fields_completed: document.querySelectorAll('input:valid').length
});
});
Feature Usage
Track when users interact with specific features:
function toggleDarkMode() {
const isDarkMode = document.body.classList.toggle('dark-mode');
FS.event('Dark Mode Toggled', {
enabled: isDarkMode,
source: 'settings_menu'
});
}
E-commerce Events
Track shopping behaviors:
// Add to cart
function addToCart(product) {
FS.event('Product Added to Cart', {
product_id: product.id,
product_name: product.name,
price: product.price,
quantity: 1,
category: product.category
});
}
// Checkout started
function startCheckout(cart) {
FS.event('Checkout Started', {
cart_value: cart.total,
item_count: cart.items.length,
currency: 'USD'
});
}
// Purchase completed
function completePurchase(order) {
FS.event('Purchase Completed', {
order_id: order.id,
revenue: order.total,
items: order.items.length,
payment_method: order.paymentMethod
});
}
Error Tracking
Track errors and failures:
// API Error
fetch('/api/data')
.then(response => {
if (!response.ok) {
FS.event('API Error', {
endpoint: '/api/data',
status_code: response.status,
error_message: response.statusText
});
}
return response.json();
})
.catch(error => {
FS.event('Network Error', {
endpoint: '/api/data',
error: error.message
});
});
// Form Validation Error
function validateForm(form) {
const errors = getFormErrors(form);
if (errors.length > 0) {
FS.event('Form Validation Error', {
form_name: form.id,
error_count: errors.length,
first_error: errors[0]
});
}
}
Video Interactions
Track video engagement:
const video = document.getElementById('promo-video');
video.addEventListener('play', function() {
FS.event('Video Played', {
video_id: video.dataset.videoId,
video_title: video.dataset.title,
duration: video.duration
});
});
video.addEventListener('ended', function() {
FS.event('Video Completed', {
video_id: video.dataset.videoId,
watch_time: video.currentTime
});
});
video.addEventListener('pause', function() {
const percentWatched = (video.currentTime / video.duration) * 100;
FS.event('Video Paused', {
video_id: video.dataset.videoId,
percent_watched: Math.round(percentWatched),
timestamp: video.currentTime
});
});
Search Queries
Track search behavior:
document.getElementById('search-form').addEventListener('submit', function(e) {
const query = document.getElementById('search-input').value;
FS.event('Search Performed', {
query: query,
query_length: query.length,
page: window.location.pathname
});
});
// Track search result clicks
function trackSearchResultClick(result, position) {
FS.event('Search Result Clicked', {
result_title: result.title,
result_position: position,
query: getCurrentSearchQuery()
});
}
User Identification with FS.identify()
Overview
FS.identify() associates user sessions with specific user identities and custom attributes. This allows you to:
- Search for sessions by specific users
- Filter replays by user properties (account type, subscription, company)
- Segment analytics by user cohorts
- Link FullStory data to your CRM or database
Basic Syntax
FS.identify(userId, userVars);
Parameters:
userId(string, required): Unique identifier for the user (email, database ID, etc.)userVars(object, optional): Custom user properties
Simple Identification
Identify a logged-in user:
FS.identify('user_12345');
Identification with User Properties
Enrich user identification with custom attributes:
FS.identify('user_12345', {
displayName: 'Jane Doe',
email: 'jane@example.com',
accountType: 'premium',
signupDate: '2024-01-15',
company: 'Acme Corp',
plan: 'enterprise',
monthlySpend: 499
});
User Property Types
FullStory supports several property types:
String properties:
FS.identify('user_123', {
email_str: 'user@example.com',
plan_str: 'premium',
role_str: 'admin'
});
Number properties:
FS.identify('user_123', {
loginCount_int: 42,
accountAge_int: 365,
revenue_real: 1250.50
});
Boolean properties:
FS.identify('user_123', {
isPremium_bool: true,
hasCompletedOnboarding_bool: true,
isTrialing_bool: false
});
Date properties:
FS.identify('user_123', {
signupDate_date: new Date('2024-01-15'),
lastLogin_date: new Date()
});
When to Call FS.identify()
After user login:
function onUserLogin(user) {
FS.identify(user.id, {
email: user.email,
displayName: user.name,
accountType: user.accountType,
lastLogin: new Date()
});
}
On page load for logged-in users:
// Check if user is logged in
if (currentUser) {
FS.identify(currentUser.id, {
email: currentUser.email,
plan: currentUser.subscription.plan,
role: currentUser.role
});
}
When user properties change:
function onSubscriptionUpgrade(newPlan) {
FS.identify(currentUser.id, {
plan: newPlan,
upgradeDate: new Date()
});
}
Updating User Properties
You can update user properties at any time:
// Initial identification
FS.identify('user_123', {
plan: 'free',
trialEnded: false
});
// Later, when user upgrades
FS.identify('user_123', {
plan: 'premium',
upgradeDate: new Date()
});
Anonymous Users
For anonymous users (not logged in), FullStory automatically assigns a unique session ID. You can still track events without calling FS.identify():
// No identification needed for anonymous users
FS.event('Viewed Pricing Page');
FS.event('Started Free Trial');
Once the user logs in, call FS.identify() to associate previous anonymous sessions with their identity.
Advanced Event Tracking Patterns
Conditional Event Tracking
Track events only under specific conditions:
function trackFeatureUsage(featureName) {
// Only track for premium users
if (currentUser.plan === 'premium') {
FS.event('Premium Feature Used', {
feature: featureName,
userId: currentUser.id
});
}
}
Batching Events
Track related events together:
function trackCheckoutFlow(cart) {
// Event 1: Checkout started
FS.event('Checkout Started', {
cartValue: cart.total,
itemCount: cart.items.length
});
// Event 2: Payment method selected
FS.event('Payment Method Selected', {
method: cart.paymentMethod
});
// Event 3: Order completed
FS.event('Order Completed', {
orderId: cart.orderId,
revenue: cart.total
});
}
Tracking User Journeys
Track multi-step processes:
// Step 1: Onboarding started
FS.event('Onboarding Started', {
source: 'signup_page'
});
// Step 2: Profile completed
FS.event('Onboarding Profile Completed', {
fields_completed: 8
});
// Step 3: Tutorial completed
FS.event('Onboarding Tutorial Completed', {
steps_completed: 5
});
// Step 4: Onboarding finished
FS.event('Onboarding Completed', {
duration_seconds: 180
});
A/B Test Tracking
Track experiment variants:
// Assign user to variant
const variant = assignExperimentVariant(currentUser.id);
FS.identify(currentUser.id, {
experiment_variant: variant,
experiment_name: 'pricing_page_test'
});
// Track variant-specific events
FS.event('Experiment CTA Clicked', {
experiment: 'pricing_page_test',
variant: variant
});
Framework-Specific Integration
React
import { useEffect } from 'react';
function ProductPage({ product }) {
useEffect(() => {
FS.event('Product Page Viewed', {
product_id: product.id,
product_name: product.name,
price: product.price
});
}, [product]);
const handleAddToCart = () => {
FS.event('Add to Cart Clicked', {
product_id: product.id,
source: 'product_page'
});
// ... add to cart logic
};
return (
<div>
<button onClick={handleAddToCart}>Add to Cart</button>
</div>
);
}
Vue.js
export default {
methods: {
trackEvent(eventName, properties) {
if (window.FS) {
window.FS.event(eventName, properties);
}
},
handleCheckout() {
this.trackEvent('Checkout Button Clicked', {
cart_value: this.cart.total,
items: this.cart.items.length
});
// ... checkout logic
}
},
mounted() {
this.trackEvent('Page Viewed', {
page: this.$route.name
});
}
}
Angular
import { Component, OnInit } from '@angular/core';
declare global {
interface Window {
FS: any;
}
}
@Component({
selector: 'app-product',
templateUrl: './product.component.html'
})
export class ProductComponent implements OnInit {
ngOnInit() {
this.trackEvent('Product Page Loaded', {
product_id: this.productId
});
}
trackEvent(eventName: string, properties?: any) {
if (window.FS) {
window.FS.event(eventName, properties);
}
}
addToCart() {
this.trackEvent('Add to Cart', {
product_id: this.productId,
price: this.product.price
});
}
}
Event Tracking Best Practices
Define an Event Taxonomy
Create a consistent naming structure:
Format: [Action] [Object] [Context]
Examples:
Clicked CTA Button - HomepageSubmitted Form - ContactViewed Page - PricingCompleted Checkout - Success
Limit Event Properties
Keep properties focused and relevant:
// Good: Clear, focused properties
FS.event('Video Played', {
video_id: '12345',
duration: 120,
autoplay: false
});
// Bad: Too many unnecessary properties
FS.event('Video Played', {
video_id: '12345',
duration: 120,
autoplay: false,
browser: 'Chrome',
os: 'Windows',
screen_width: 1920,
timestamp: Date.now(),
user_agent: navigator.userAgent
// FullStory already captures most of this automatically
});
Avoid PII in Events
Don't send personally identifiable information in event properties:
// Bad: Contains PII
FS.event('Form Submitted', {
email: 'user@example.com',
phone: '555-1234',
ssn: '123-45-6789'
});
// Good: No PII
FS.event('Form Submitted', {
form_type: 'contact',
fields_count: 5
});
Test Events Before Deploying
Verify events fire correctly in development:
function trackEvent(name, properties) {
if (window.FS) {
console.log('[FullStory Event]', name, properties);
FS.event(name, properties);
} else {
console.warn('[FullStory] Not loaded, event not tracked:', name);
}
}
Document Your Events
Maintain a tracking plan document:
# FullStory Event Tracking Plan
## Signup Flow
- **Event:** Signup Button Clicked
- **When:** User clicks "Sign Up" CTA
- **Properties:** location (string), button_color (string)
- **Event:** Signup Form Submitted
- **When:** User submits registration form
- **Properties:** form_type (string), plan_selected (string)
Searching Events in FullStory
Once events are tracked, use Omnisearch to find sessions:
Search by event name:
Event: "Checkout Started"
Search by event property:
Event: "Product Added to Cart" where product_category = "electronics"
Combine events with user properties:
Event: "Checkout Completed" where plan = "premium"
Find users who performed multiple events:
Event: "Signup Button Clicked" AND Event: "Signup Completed"
Troubleshooting Event Tracking
Events Not Appearing in FullStory
Check if FullStory is loaded:
if (window.FS) {
console.log('FullStory loaded');
FS.event('Test Event');
} else {
console.error('FullStory not loaded');
}
Verify event syntax:
// Correct
FS.event('Button Clicked', { location: 'homepage' });
// Incorrect (missing event name)
FS.event({ location: 'homepage' });
User Identification Not Working
Ensure userId is a string:
// Correct
FS.identify('12345');
// Incorrect (number instead of string)
FS.identify(12345);
Check timing:
// Make sure FS is loaded before identifying
window.addEventListener('load', function() {
if (window.FS && currentUser) {
FS.identify(currentUser.id, {
email: currentUser.email
});
}
});
Events Firing Multiple Times
Use event listeners carefully to avoid duplicates:
// Bad: Adds listener every time function runs
function setupTracking() {
button.addEventListener('click', () => {
FS.event('Button Clicked');
});
}
// Good: Only add listener once
let listenerAdded = false;
function setupTracking() {
if (!listenerAdded) {
button.addEventListener('click', () => {
FS.event('Button Clicked');
});
listenerAdded = true;
}
}
Next Steps:
- Integrations - Connect FullStory with other tools
- Setup & Implementation - Install FullStory tracking
- Troubleshooting & Debugging - Solve common issues
Additional Resources: