Skip to content

User Journey Tracker Service (UserJourneyTrackerService) ​

Overview ​

The UserJourneyTrackerService is the primary interface for capturing a detailed, chronological record of a user's session (the "Journey").

It manages the session lifecycle, automatically collects context data (device, URL, assignments), and batches events for efficient data transmission.

The service's API is designed for semantic tracking, providing specialized methods for distinct event categories (e.g., interactions, form changes, navigation, and conversions) to minimize noise and maximize analytical value.


Core Event Structures ​

  • JourneyEvent (generated by most methods): Used for general activity and milestones. Automatically enriched with context (URL, device, timestamps, etc.).

  • ConversionEvent (via trackConversionEvent): Specialized event with mandatory fields (testId, variantId, metricId) required for A/B test analysis.


1. Core Concepts and Session Management ​

  • User Journey: A continuous session that begins when a user is identified (via startJourney). It serves as the container for all subsequent events.
  • Session Management:
    • Inactivity and maximum session duration are automatically managed (e.g., 30 minutes of inactivity).
    • Activity is tracked via mouse movements, clicks, and focus changes.
  • Contextualization: Every event is automatically enriched with contextual data (current URL, viewport size, device type, active A/B test assignments).

1.1 Journey and Session Control API ​

MethodDescriptionArgumentsBest Use Case
startJourney(journeyName: string, config?: UserJourneyConfig)Initializes and tracks the start of a logical user session. Resets timers and attaches a unique Session ID to all subsequent events.- journeyName (string): Unique ID (e.g., application_session, onboarding).
- config (optional): Overrides session defaults (timeouts, etc.).
Called once when a user is identified or starts a major application flow.
endJourney(properties?: Record<string, unknown>)Manually signals the end of the current journey by sending a journey_completed event.- properties (optional): Any final context to attach to the completion event.Use for explicit completion points (purchase, sign-out, exit from a major flow).

2. Granular Event Tracking (Generating JourneyEvent) ​

These methods track specific user actions and state changes that are not related to A/B test conversion or funnel steps.

2.1 API Reference: Granular Methods ​

MethodDescriptionArgumentsEvent Type
trackJourneyEvent(name: string, props?: Record<string, unknown>)General-purpose tracking method for any milestone or event not covered by specialized trackers.- name (string): Semantic name (e.g., data_sync_complete).
- props (optional): Custom data.
generic_event
trackUserInteraction(name: string, props?: Record<string, unknown>)Tracks direct user interaction with UI elements (clicks, gestures, hovers).- name (string): Interaction type (e.g., button_click, drag_gesture).
- props (optional): Element details (e.g., elementId, position).
user_interaction
trackFormInteraction(formId: string, name: string, props?: Record<string, unknown>)Tracks progress and outcomes within a specific form or transactional process.- formId (string): Unique form name (e.g., signup_form).
- name (string): Status (e.g., start, field_error, submit_success).
form_interaction

2.2 Granular Tracking Example ​

typescript
// Example of specific tracking in a component
import { Component, inject } from '@angular/core';
import { UserJourneyTrackerService } from '.../user-journey-tracker.service';

@Component({...})
export class SettingsComponent {
  private tracker = inject(UserJourneyTrackerService);

  onProfileSave(isSuccess: boolean): void {
    if (isSuccess) {
        // Track a successful form submission
        this.tracker.trackFormInteraction('profile_settings_form', 'submit_success', {
            profileType: 'premium',
            timeTaken: 500 // ms
        });
        // Track a generic high-value milestone
        this.tracker.trackJourneyEvent('user_profile_updated', {
            settingGroup: 'core_info'
        });
    } else {
        // Track a failure interaction
        this.tracker.trackFormInteraction('profile_settings_form', 'submit_failure', {
            errorReason: 'Email invalid',
            fieldInError: 'email'
        });
    }
  }

  onFilterApplied(filterKey: string): void {
    // Track a click/action interaction
    this.tracker.trackUserInteraction('filter_applied_click', {
      elementId: `filter-${filterKey}`,
      value: 'active',
    });
  }
}

3. Navigation and Page View Tracking ​

3.1 API Reference: Navigation Methods ​

MethodDescriptionArgumentsBest Use Case
trackPageView(page: string, props?: Record<string, unknown>)Records that a page or route has finished loading and is being viewed.- page (string): Page/route name (e.g., /product/123).
- props (optional): Contextual data (e.g., referrer).
Best practice: Handled globally by subscribing to Angular Router events.
trackPageNavigation(destination: string, type: 'link' | 'button' | 'back', props?: Record<string, unknown>)Tracks explicit user action that initiated navigation.- destination (string): Target route or URL.
- type (string): Mechanism used (link, button, back, forward).
Use in components to link navigation action to page change.

3.2 Navigation Tracking Example (Global Router Hook) ​

typescript
import { Component, inject } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';
import { UserJourneyTrackerService } from '.../user-journey-tracker.service';

@Component({...})
export class AppComponent {
  private router = inject(Router);
  private tracker = inject(UserJourneyTrackerService);

  constructor() {
    // 1. Global Page View Tracking
    this.router.events.pipe(
      filter(event => event instanceof NavigationEnd)
    ).subscribe((event: NavigationEnd) => {
      this.tracker.trackPageView(event.urlAfterRedirects, {
        isInitialLoad: this.router.navigated ? false : true
      });
    });
  }

  // 2. Manual Navigation Tracking
  onCustomNavigation(route: string): void {
      this.tracker.trackPageNavigation(route, 'button', {
          sourceComponent: 'sidebar_menu'
      });
      this.router.navigateByUrl(route);
  }
}

4. Goal, Funnel, and A/B Test Tracking ​

4.1 API Reference: Goal and Funnel Methods ​

MethodDescriptionArgumentsRecommended Use Case
trackFunnelStep(funnelId: string, stepName: string, properties?: Record<string, unknown>)Tracks successful progress through a multi-step process.- funnelId (string): Funnel name.
- stepName (string): Must follow x-identifier.
Analyze drop-off and time-to-completion in sequential flows (e.g., checkout).
trackFunnelDropoff(funnelId: string, stepName: string, reason: string, properties?: Record<string, unknown>)Marks the point where a user exited a funnel prematurely.- funnelId (string): Funnel name.
- stepName (string): Step before exit.
- reason (string): Cause (e.g., cancelled, payment_failure).
Calculate dropoff rates and identify abandonment causes.
trackConversionEvent(event: ConversionEvent)Tracks an A/B test Success Metric.- event (ConversionEvent): Must include metricId, testId, variantId, and value.Used exclusively for A/B test analysis.

4.2 Funnel Naming Convention (MANDATORY) ​

The stepName must follow the format:

x-identifier

This ensures chronological ordering and clear branching in analytics.

  • Sequential Steps:

    • 1-initiate
    • 2-task-overview-reached
    • 3-created-new-task
  • Branching Paths:

    • 2.1-task-overview-reached
    • 2.2-task-overview-skipped

4.3 Goal Tracking Examples ​

typescript
// Example of tracking funnel progression, dropoff, and AB conversion

@Injectable({ providedIn: 'root' })
export class CheckoutService {
  private tracker = inject(UserJourneyTrackerService);
  private checkoutFunnelId = 'standard_checkout_flow';

  /**
   * Tracks progression through the funnel.
   * Called on successful move to the next step.
   */
  proceedToShipping(): void {
    this.tracker.trackFunnelStep(this.checkoutFunnelId, '1-cart-review-complete');
    // ... navigate to shipping page
  }

  /**
   * Tracks a drop-off from the funnel.
   */
  handleDropoff(stepName: string, reason: string): void {
    this.tracker.trackFunnelDropoff(
      this.checkoutFunnelId,
      stepName, // e.g., '2-shipping-details-page'
      reason, // e.g., 'high_shipping_cost'
      { cartTotal: 150.99 },
    );
  }

  /**
   * Tracks a final purchase as a Conversion Event for an A/B test.
   */
  completePurchase(testId: string, revenue: number, assignedVariant: VariantType): void {
    const purchaseEvent: ConversionEvent = {
      timestamp: new Date(),
      testId: testId,
      metricId: 'purchase_conversion',
      variantId: assignedVariant,
      value: revenue,
      properties: {
        orderId: 'O-12345',
        currency: 'USD',
      },
    };

    this.tracker.trackConversionEvent(purchaseEvent);
  }
}