Event definition and naming strategy

Build a consistent, maintainable analytics system with clear naming conventions

What's covered

  • Why centralized event definitions matter
  • The "Object Verb" naming convention
  • How to organize frontend vs backend events
  • Patterns for scalable event management
  • Common naming mistakes to avoid

Why Event Strategy Matters

Without a strategy, analytics becomes chaos:

// ❌ Inconsistent naming across the team
track('user_searched_something');
track('Search Executed');
track('search-performed');
track('SEARCH_ACTION');

With a strategy, analytics tell a clear story:

// ✅ Consistent, predictable, searchable
track('Search Performed');
track('Filter Applied');
track('Export Generated');
track('Todo Created');

The "Object Verb" Convention

Format: [Object] [Past Tense Verb]

Examples:

  • ✅ Todo Created
  • ✅ User Invited
  • ✅ Search Performed
  • ✅ Integration Connected

Not:

  • ❌ Create Todo
  • ❌ Inviting User
  • ❌ Button Clicked
  • ❌ Page Viewed

Why This Works:

  1. Consistent - Always know the format
  2. Searchable - Easy to find in analytics tools
  3. Clear - Immediately understand what happened
  4. Sortable - Groups related events naturally

Centralized Event Definitions

The Problem with Scattered Events

// ❌ Events defined everywhere
// FileA.js
track('user performed search');

// FileB.js  
track('Search Performed');

// FileC.js
track('SEARCH_EXECUTED');

Issues:

  • Same event tracked differently
  • No way to audit all events
  • Typos create phantom events
  • Hard to maintain

The Solution: Single Source of Truth

Create dedicated event definition files:

src/analytics/
└── events.js          # Backend event definitions


static/spa/src/analytics/
└── events.js          # Frontend event definitions

Backend Event Definitions

📦

Working Example Available

The following code is available in our sample app available on GitHub.

🔗 View the full Forge Analytics Example on GitHub

src/analytics/events.js

/**
 * BACKEND EVENT DEFINITIONS
 * 
 * Single source of truth for all backend analytics events.
 * 
 * NAMING CONVENTION: "Object Verb" format
 * - Todo Created (not Create Todo)
 * - Search Performed (not Perform Search)
 * - Export Generated (not Generate Export)
 */

import { track } from './dispatcher';

// Core tracking function with identify/group
const trackEvent = async (context, eventName) => {
  const userId = context.accountId;
  const groupId = context.cloudId;
  
  // Bundle identify, group, and track
  await track(userId, groupId, eventName);
};

/**
 * TODO EVENTS
 */
export const trackTodoCreated = (context) => 
  trackEvent(context, 'Todo Created');

export const trackTodoUpdated = (context) => 
  trackEvent(context, 'Todo Updated');

export const trackTodoDeleted = (context) => 
  trackEvent(context, 'Todo Deleted');

export const trackTodosCleared = (context) => 
  trackEvent(context, 'Todos Cleared');

/**
 * USER EVENTS
 */
export const trackUserInvited = (context) => 
  trackEvent(context, 'User Invited');

export const trackUserRemoved = (context) => 
  trackEvent(context, 'User Removed');

export const trackUserRoleChanged = (context) => 
  trackEvent(context, 'User Role Changed');

/**
 * INTEGRATION EVENTS
 */
export const trackIntegrationConnected = (context) => 
  trackEvent(context, 'Integration Connected');

export const trackIntegrationDisconnected = (context) => 
  trackEvent(context, 'Integration Disconnected');

export const trackIntegrationSynced = (context) => 
  trackEvent(context, 'Integration Synced');

Frontend Event Definitions

📦

Working Example Available

The following code is available in our sample app available on GitHub.

🔗 View the full Forge Analytics Example on GitHub

static/spa/src/analytics/events.js

/**
 * FRONTEND EVENT DEFINITIONS
 * 
 * Single source of truth for all frontend analytics events.
 * All events are routed through backend resolvers for privacy.
 * 
 * NAMING CONVENTION: "Object Verb" format
 */

import { invoke } from '@forge/bridge';

// Core tracking function
const track = async (eventName) => {
  try {
    await invoke('track-event', { event: eventName });
  } catch (error) {
    console.error('[Analytics] Failed to track:', error);
  }
};

/**
 * SEARCH EVENTS
 */
export const trackSearchPerformed = (searchType) => 
  track(`${searchType} Search Performed`);

export const trackFilterApplied = (filterType) => 
  track(`${filterType} Filter Applied`);

/**
 * MEANINGFUL INTERACTION EVENTS
 */
export const trackFormSubmitted = (formName) => 
  track(`${formName} Form Submitted`);

export const trackFormCancelled = (formName) => 
  track(`${formName} Form Cancelled`);

export const trackExportGenerated = (exportType) => 
  track(`${exportType} Export Generated`);

/**
 * FEATURE USAGE EVENTS
 */
export const trackSearchUsed = () => 
  track('Search Used');

export const trackFilterApplied = (filterType) => 
  track(`${filterType} Filter Applied`);

export const trackExportRequested = (format) => 
  track(`${format} Export Requested`);

/**
 * APP LIFECYCLE EVENTS
 */
export const trackAppLoaded = () => 
  track('App Loaded');

export const trackAppErrored = () => 
  track('App Errored');

Event Categories and Patterns

1. CRUD Operations

// Pattern: [Object] [CRUD Verb]
'Todo Created'
'Todo Updated'
'Todo Deleted'
'Todos Listed'    // Plural for bulk operations

2. Feature Usage

// Pattern: [Feature] [Action Taken]
'Advanced Search Performed'
'Bulk Export Generated'
'Integration Configured'
'Template Applied'

3. User Workflows

// Pattern: [Workflow] [Completion State]
'Onboarding Completed'
'Setup Wizard Abandoned'
'Migration Finished'

4. Features

// Pattern: [Feature] [Usage Verb]
'Search Performed'
'CSV Export Generated'
'Notification Sent'
'Theme Changed'

5. Errors and Issues

// Pattern: [Context] Error Occurred
'API Error Occurred'
'Validation Error Occurred'
'Permission Error Occurred'

Organizing Complex Apps

For larger apps, organize events by domain:

// src/analytics/events/index.js
export * from './todo-events';
export * from './user-events';
export * from './project-events';
export * from './billing-events';

// src/analytics/events/todo-events.js
export const trackTodoCreated = (context) => 
  trackEvent(context, 'Todo Created');

export const trackTodoAssigned = (context) => 
  trackEvent(context, 'Todo Assigned');

// src/analytics/events/project-events.js
export const trackProjectCreated = (context) => 
  trackEvent(context, 'Project Created');

export const trackProjectArchived = (context) => 
  trackEvent(context, 'Project Archived');

Event Naming Checklist

Before adding a new event, verify:

  • Follows "Object Verb" format
  • Uses past tense verb
  • No redundant prefixes (e.g., "Event:", "Track:")
  • No implementation details (e.g., "Button1", "Link_2")
  • No PII in event name
  • Consistent with existing events
  • Added to central definition file


Common Anti-Patterns to Avoid

❌ Technical Implementation Details

// Bad - exposes implementation
track('div#search-input focused');
track('GET /api/search?q=test Success');
track('Redux Action SEARCH_EXECUTED');

// Good - describes user intent
track('Search Performed');
track('Filter Applied');

❌ Inconsistent Formatting

// Bad - mixed formats
track('search-performed');
track('FILTER_APPLIED');
track('exportGenerated');

// Good - consistent format
track('Search Performed');
track('Filter Applied');
track('Export Generated');

❌ Present or Future Tense

// Bad - wrong tense
track('Performing Search');
track('Will Generate Export');
track('Is Applying Filter');

// Good - past tense
track('Search Performed');
track('Export Generated');
track('Filter Applied');

❌ Vague or Generic Names

// Bad - not specific
track('Action');
track('Event Happened');
track('User Did Something');

// Good - specific and clear
track('Search Performed');
track('Report Generated');
track('Subscription Upgraded');


Key Takeaways

  1. Centralize definitions - One file per environment (frontend/backend)
  2. "Object Verb" format - Consistent and clear
  3. Past tense only - Describes what happened
  4. No implementation details - Focus on user intent