Skip to main content
The T1 Component Library includes a powerful interaction tracking system that monitors user behavior, provides real-time analytics, and supports both anonymous and authenticated users.

Overview

The tracking system captures component interactions throughout your application and provides:
  • Real-time analytics with automatic statistics updates
  • User segmentation (anonymous vs. registered users)
  • Server-side persistence with MongoDB
  • Dashboard integration for viewing analytics
  • CSV export functionality for data analysis

Architecture

The tracking system consists of two main parts:
  1. Client-side Context (InteractionContext.tsx) - Manages local state and sends events to the server
  2. Server-side Service (tracking.service.ts) - Persists interactions and generates statistics

Getting Started

Setup

Wrap your application with the InteractionProvider:
import { InteractionProvider } from './context/InteractionContext';

function App() {
  return (
    <InteractionProvider>
      {/* Your app components */}
    </InteractionProvider>
  );
}
The InteractionProvider should be placed inside AuthProvider and QueryClientProvider to access authentication state and React Query functionality.

Track Interactions

Use the useInteractions hook to track user interactions:
import { useInteractions } from './context/InteractionContext';

function MyButton() {
  const { trackInteraction } = useInteractions();

  const handleClick = () => {
    trackInteraction('MyButton', 'click');
    // Your button logic
  };

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
}

Tracking API

The useInteractions hook provides the following:
PropertyTypeDescription
trackInteraction(componentName: string, action: string) => voidTrack a user interaction
totalInteractionsnumberCount of interactions in current session
serverStatsServerStats | undefinedAggregated statistics from the server
isLoadingServerStatsbooleanLoading state for initial stats fetch
isRefetchingServerStatsbooleanLoading state for stats refresh

Server Statistics

The serverStats object contains:
interface ServerStats {
  totalInteracciones: number;
  porComponente: Array<{ _id: string; count: number }>;
  porAccion: Array<{ _id: { componente: string; accion: string }; count: number }>;
  porTipoUsuario: Array<{ _id: string; count: number }>;
}

How It Works

1

Interaction Captured

When you call trackInteraction(), the event is immediately stored in local state and displayed in the session counter.
2

Server Transmission

The interaction is sent to the server via a React Query mutation, including the component name, action, timestamp, and user type.
3

User Type Detection

The system automatically determines if the user is ‘anonymous’ or ‘registered’ based on authentication state.
4

Server Persistence

The server saves the interaction to MongoDB with full metadata including timestamps and user information.
5

Statistics Update

After successful tracking, statistics are automatically refreshed to reflect the latest data.

Tracked Data

Each interaction record contains:
FieldTypeDescription
nombrestringComponent name being tracked
accionstringAction performed (e.g., ‘click’, ‘hover’, ‘submit’)
timestampDateWhen the interaction occurred
tipo_usuario'anonymous' | 'registered'User authentication status
usuariostring | undefinedUser ID if authenticated

Implementation Examples

Basic Button Tracking

import { useInteractions } from './context/InteractionContext';

function DownloadButton() {
  const { trackInteraction } = useInteractions();

  return (
    <button
      onClick={() => {
        trackInteraction('DownloadButton', 'click');
        // Handle download
      }}
    >
      Download
    </button>
  );
}

Form Submission Tracking

function ContactForm() {
  const { trackInteraction } = useInteractions();

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    trackInteraction('ContactForm', 'submit');
    // Process form
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
      <button type="submit">Submit</button>
    </form>
  );
}

Component Visibility Tracking

import { useEffect } from 'react';
import { useInteractions } from './context/InteractionContext';

function Hero() {
  const { trackInteraction } = useInteractions();

  useEffect(() => {
    trackInteraction('Hero', 'view');
  }, []);

  return <div>Hero Section</div>;
}

Multi-Action Component

function VideoPlayer() {
  const { trackInteraction } = useInteractions();

  return (
    <div>
      <video
        onPlay={() => trackInteraction('VideoPlayer', 'play')}
        onPause={() => trackInteraction('VideoPlayer', 'pause')}
        onEnded={() => trackInteraction('VideoPlayer', 'complete')}
      />
    </div>
  );
}

Analytics Dashboard

Display Statistics

Create a dashboard to visualize interaction data:
import { useInteractions } from './context/InteractionContext';

function AnalyticsDashboard() {
  const { serverStats, isLoadingServerStats } = useInteractions();

  if (isLoadingServerStats) {
    return <div>Loading analytics...</div>;
  }

  return (
    <div>
      <h2>Total Interactions: {serverStats?.totalInteracciones}</h2>
      
      <section>
        <h3>Top Components</h3>
        <ul>
          {serverStats?.porComponente.map((item) => (
            <li key={item._id}>
              {item._id}: {item.count} interactions
            </li>
          ))}
        </ul>
      </section>

      <section>
        <h3>User Types</h3>
        <ul>
          {serverStats?.porTipoUsuario.map((item) => (
            <li key={item._id}>
              {item._id}: {item.count} interactions
            </li>
          ))}
        </ul>
      </section>
    </div>
  );
}

Real-time Updates

The statistics automatically refresh on window focus:
// From InteractionContext.tsx:41-54
const {
  data: serverStats,
  isLoading: isLoadingServerStats,
  isRefetching: isRefetchingServerStats,
} = useQuery({
  queryKey: ['stats'],
  queryFn: async () => {
    const response = await api.getStats();
    return response.data;
  },
  refetchOnWindowFocus: true,
  staleTime: 3000,
});

Server-Side Features

Statistics Generation

The server provides aggregated statistics using MongoDB aggregation pipelines:
// From tracking.service.ts:49-72
getStats: async (): Promise<TrackingStats> => {
  const [totalInteracciones, porComponente, porAccion, porTipoUsuario] = 
    await Promise.all([
      Tracking.countDocuments(),
      Tracking.aggregate([
        { $group: { _id: '$nombre', count: { $sum: 1 } } },
        { $sort: { count: -1 } },
        { $limit: 10 }
      ]),
      Tracking.aggregate([
        { 
          $group: { 
            _id: { componente: '$nombre', accion: '$accion' }, 
            count: { $sum: 1 } 
          } 
        },
        { $sort: { '_id.componente': 1, count: -1 } }
      ]),
      Tracking.aggregate([
        { $group: { _id: '$tipo_usuario', count: { $sum: 1 } } }
      ])
    ]);

  return { totalInteracciones, porComponente, porAccion, porTipoUsuario };
}

Paginated Data Access

Retrieve paginated interaction records:
// From tracking.service.ts:74-108
getPaginated: async (page: number = 1, limit: number = 10) => {
  const skip = (page - 1) * limit;
  
  const [trackings, total] = await Promise.all([
    Tracking.find()
      .sort({ timestamp: -1 })
      .skip(skip)
      .limit(limit)
      .populate('usuario', 'nombre'),
    Tracking.countDocuments()
  ]);

  const totalPages = Math.ceil(total / limit);

  return {
    data: trackings.map((tracking) => ({
      id: tracking._id.toString(),
      nombre_componente: tracking.nombre,
      accion: tracking.accion,
      timestamp: tracking.timestamp,
      tipo_usuario: tracking.tipo_usuario,
      nombre_usuario: tracking.usuario?.nombre || null
    })),
    pagination: {
      page,
      limit,
      total,
      totalPages,
      hasNextPage: page < totalPages,
      hasPrevPage: page > 1
    }
  };
}

Data Export

Export all tracking data for analysis:
// From tracking.service.ts:110-116
export: async (): Promise<ITracking[]> => {
  const trackings = await Tracking.find()
    .sort({ timestamp: -1 })
    .populate('usuario', 'nombre email');

  return trackings;
}

Best Practices

Track meaningful interactions - Focus on user actions that provide valuable insights rather than tracking everything.
  1. Use descriptive names - Component names and actions should be clear and consistent
  2. Track user flows - Monitor complete user journeys, not just individual clicks
  3. Respect privacy - Only track necessary data and comply with privacy regulations
  4. Monitor performance - Be mindful of tracking overhead in high-traffic components
  5. Analyze patterns - Regularly review analytics to improve UX

Common Tracking Patterns

E-commerce Actions

trackInteraction('ProductCard', 'view');
trackInteraction('ProductCard', 'add-to-cart');
trackInteraction('Checkout', 'initiate');
trackInteraction('Checkout', 'complete');

Content Engagement

trackInteraction('Article', 'view');
trackInteraction('Article', 'scroll-50');
trackInteraction('Article', 'scroll-100');
trackInteraction('ShareButton', 'click');
trackInteraction('MainNav', 'menu-open');
trackInteraction('MainNav', 'products-click');
trackInteraction('SearchBar', 'search');
trackInteraction('Footer', 'newsletter-signup');

Error Handling

The tracking system includes built-in error handling:
// From InteractionContext.tsx:56-71
const trackMutation = useMutation({
  mutationFn: (params: { nombre: string; accion: string }) => {
    return api.trackInteraction({
      nombre: params.nombre,
      accion: params.accion,
      tipo_usuario: isAuthenticated ? 'registered' : 'anonymous',
      usuario: isAuthenticated ? user?.id : undefined,
    });
  },
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['stats'] });
  },
  onError: (error) => {
    console.error('Error al enviar interacción:', error);
  },
});
Failed tracking attempts are logged but don’t block the user experience. The app continues to function even if tracking fails.

Source Code References

  • Interaction Context: client/app/context/InteractionContext.tsx
  • Tracking Service: server/src/services/tracking.service.ts
  • Tracking Model: server/src/models/Tracking.model.ts
  • Interaction Hook: client/app/context/InteractionContext.tsx:102-108

Build docs developers (and LLMs) love