Umami Data Layer | OpsBlu Docs

Umami Data Layer

Set up the data layer for Umami — structure events, define variables, and ensure consistent tracking data.

Data Layer Setup in Umami

Umami's data layer is intentionally minimal and privacy-focused. Unlike traditional analytics platforms that encourage extensive user profiling, Umami's approach centers on event-level data collection without persistent user identification. This design philosophy means there's no traditional "data layer" object to populate with user attributes - instead, you work with event-specific data that's captured ephemerally and never tied to individual users across sessions.

Privacy-First Data Philosophy

What Umami Does NOT Track:

  • Personal identifiable information (PII)
  • Individual user identities across sessions
  • IP addresses (stored or logged)
  • User agents or device fingerprints
  • Cookie-based user IDs
  • Cross-session user journeys

What Umami DOES Track:

  • Aggregated page views
  • Event names and event-specific metadata
  • Referrer sources (anonymized)
  • Geographic data (country-level only)
  • Device categories (mobile/desktop/tablet)
  • Browser and OS (aggregated, not individual fingerprints)

This distinction is crucial: Umami is designed for understanding aggregate behavior patterns, not individual user profiling.

Event Data Structure

Umami's data layer revolves around custom events with optional metadata:

Basic Event Tracking:

// Simple event (no metadata)
umami.track('newsletter_signup');

// Event with metadata
umami.track('purchase', {
  product: 'Pro Plan',
  value: 99,
  currency: 'USD',
  category: 'subscription'
});

Event Data Properties:

umami.track('event_name', {
  // String properties
  plan_type: 'enterprise',
  feature_name: 'export_data',

  // Numeric properties
  value: 149.99,
  quantity: 3,

  // Boolean properties
  is_trial: false,
  is_upgrade: true
});

Common Data Layer Patterns

E-Commerce Tracking

Product Views:

// Track when user views a product
umami.track('product_view', {
  product_id: 'prod-123',
  product_name: 'Wireless Headphones',
  category: 'Electronics',
  price: 79.99,
  currency: 'USD'
});

Add to Cart:

umami.track('add_to_cart', {
  product_id: 'prod-123',
  product_name: 'Wireless Headphones',
  quantity: 2,
  price: 79.99,
  cart_total: 159.98
});

Purchase Completion:

umami.track('purchase', {
  transaction_id: 'txn-456789',
  value: 159.98,
  currency: 'USD',
  items_count: 2,
  payment_method: 'credit_card',
  shipping_method: 'express'
});

Cart Abandonment:

// Track when user leaves checkout
umami.track('cart_abandoned', {
  cart_value: 159.98,
  items_count: 2,
  checkout_step: 'payment'
});

SaaS Application Tracking

Feature Usage:

umami.track('feature_used', {
  feature_name: 'data_export',
  export_format: 'CSV',
  record_count: 1500,
  file_size_mb: 2.3
});

Subscription Events:

// Trial start
umami.track('trial_started', {
  plan: 'pro',
  trial_days: 14,
  source: 'landing_page'
});

// Plan upgrade
umami.track('plan_upgraded', {
  from_plan: 'basic',
  to_plan: 'enterprise',
  billing_cycle: 'annual',
  value: 1200
});

// Subscription cancellation
umami.track('subscription_cancelled', {
  plan: 'pro',
  reason: 'too_expensive',
  months_subscribed: 6
});

User Milestones:

umami.track('milestone_reached', {
  milestone_type: 'projects_created',
  milestone_value: 10,
  days_since_signup: 45
});

Content Engagement

Video Tracking:

// Video started
umami.track('video_play', {
  video_id: 'intro-tutorial',
  video_title: 'Getting Started Guide',
  video_duration: 180
});

// Video progress
umami.track('video_progress', {
  video_id: 'intro-tutorial',
  progress_percent: 50,
  seconds_watched: 90
});

// Video completed
umami.track('video_complete', {
  video_id: 'intro-tutorial',
  total_watch_time: 180,
  completion_rate: 100
});

Content Downloads:

umami.track('download', {
  file_name: 'product-guide.pdf',
  file_type: 'PDF',
  file_size_mb: 2.5,
  content_category: 'documentation'
});

Search Queries:

umami.track('search', {
  query: 'integration guide',
  results_count: 12,
  filter_category: 'documentation'
});

Form Interactions

Form Submissions:

umami.track('form_submit', {
  form_name: 'contact',
  form_type: 'lead_generation',
  fields_completed: 8,
  time_to_complete: 120 // seconds
});

Form Errors:

umami.track('form_error', {
  form_name: 'signup',
  error_field: 'email',
  error_type: 'invalid_format'
});

Form Abandonment:

umami.track('form_abandoned', {
  form_name: 'checkout',
  fields_completed: 3,
  fields_total: 8,
  completion_percent: 37.5
});

Data Layer Best Practices

1. Consistent Event Naming

Use a clear naming convention:

// Good: Descriptive, consistent
umami.track('newsletter_signup', { source: 'footer' });
umami.track('product_purchased', { category: 'electronics' });
umami.track('video_completed', { title: 'intro' });

// Bad: Inconsistent, unclear
umami.track('nlSignup', { source: 'footer' });
umami.track('bought', { category: 'electronics' });
umami.track('vidDone', { title: 'intro' });

Naming Convention Examples:

  • Use snake_case: cart_abandoned, signup_completed
  • Use verb + noun: form_submitted, video_played, file_downloaded
  • Be specific: trial_started not just trial
  • Group related events: checkout_started, checkout_completed, checkout_abandoned

2. Structured Metadata

Keep metadata consistent across similar events:

// All purchase events should have same structure
umami.track('purchase', {
  value: 99.99,
  currency: 'USD',
  category: 'subscription',
  payment_method: 'stripe'
});

umami.track('purchase', {
  value: 149.99,
  currency: 'USD',
  category: 'one_time',
  payment_method: 'paypal'
});

3. Numeric Values for Analysis

Always include numeric values when tracking business metrics:

umami.track('goal_achieved', {
  goal_type: 'revenue',
  value: 500,        // Always include value for aggregation
  currency: 'USD',
  source: 'email_campaign'
});

4. Avoid PII in Event Data

Never include personally identifiable information:

// Bad: Contains PII
umami.track('signup', {
  email: 'user@example.com',    // Don't do this
  name: 'John Doe',              // Don't do this
  phone: '555-1234'              // Don't do this
});

// Good: Generic metadata without PII
umami.track('signup', {
  source: 'landing_page',
  plan: 'free',
  referrer_type: 'organic'
});

Integration with Tag Managers

If using Google Tag Manager or similar:

DataLayer Push to Umami:

// Listen to GTM dataLayer pushes
window.dataLayer = window.dataLayer || [];
window.dataLayer.push = function(obj) {
  Array.prototype.push.call(window.dataLayer, obj);

  // Convert GTM events to Umami events
  if (obj.event && window.umami) {
    const eventData = {
      ...obj
    };
    delete eventData.event; // Remove GTM event property

    umami.track(obj.event, eventData);
  }
};

Selective Event Forwarding:

// Only forward specific GTM events to Umami
const UMAMI_EVENTS = ['purchase', 'signup', 'download'];

window.dataLayer.push = function(obj) {
  Array.prototype.push.call(window.dataLayer, obj);

  if (obj.event && UMAMI_EVENTS.includes(obj.event) && window.umami) {
    umami.track(obj.event, {
      value: obj.value,
      currency: obj.currency,
      category: obj.category
    });
  }
};

Server-Side Data Collection

While Umami is primarily client-side, you can send events from your server:

Using Umami API:

// Node.js example
const fetch = require('node-fetch');

async function trackServerEvent(eventName, eventData) {
  const response = await fetch('https://analytics.example.com/api/send', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'User-Agent': 'Mozilla/5.0' // Required
    },
    body: JSON.stringify({
      type: 'event',
      payload: {
        website: 'YOUR-WEBSITE-ID',
        url: '/api/endpoint',  // Logical URL for server event
        name: eventName,
        data: eventData
      }
    })
  });

  return response.json();
}

// Track server-side purchase
await trackServerEvent('server_purchase', {
  value: 99.99,
  currency: 'USD',
  payment_processor: 'stripe'
});

Data Validation and Testing

Test Event Tracking:

// Development environment: log events
function trackEvent(eventName, eventData) {
  if (process.env.NODE_ENV === 'development') {
    console.log('Umami Event:', eventName, eventData);
  }

  if (window.umami) {
    umami.track(eventName, eventData);
  }
}

// Use in your app
trackEvent('button_click', {
  button_name: 'signup',
  location: 'header'
});

Event Data Schema Validation:

// Define expected event schemas
const EVENT_SCHEMAS = {
  purchase: ['value', 'currency', 'category'],
  signup: ['source', 'plan'],
  download: ['file_name', 'file_type']
};

function validateAndTrack(eventName, eventData) {
  const schema = EVENT_SCHEMAS[eventName];

  if (schema) {
    const missingFields = schema.filter(field => !(field in eventData));

    if (missingFields.length > 0) {
      console.warn(`Missing fields for ${eventName}:`, missingFields);
    }
  }

  umami.track(eventName, eventData);
}

Viewing Event Data in Dashboard

Access Event Data:

  1. Log into Umami dashboard
  2. Select your website
  3. Navigate to "Events" tab
  4. View event names, counts, and associated metadata

Analyzing Event Metadata:

  • Click on specific event to see metadata breakdown
  • Filter by date range to see trends
  • Export data for external analysis

Limitations and Considerations

Data Retention:

  • Event data is stored according to your Umami instance settings
  • Self-hosted: Configure retention in database settings
  • Cloud: Check your plan's data retention policy

Metadata Limitations:

  • Metadata is stored as JSON
  • Very large metadata objects may impact performance
  • Keep metadata focused and relevant

No User-Level Segmentation:

  • Can't filter events by individual user characteristics
  • All analysis is aggregate-level
  • Use event metadata for segmentation (e.g., plan type, user role)

Query Capabilities:

  • Limited complex querying in UI
  • Use API for advanced analysis
  • Export data to BI tools for deeper insights

Migration from Other Platforms

If migrating from Google Analytics or other platforms:

GA4 to Umami Event Mapping:

// GA4 event
gtag('event', 'purchase', {
  transaction_id: 'T12345',
  value: 99.99,
  currency: 'USD',
  items: [...]
});

// Umami equivalent (simplified)
umami.track('purchase', {
  value: 99.99,
  currency: 'USD'
  // Note: Individual items not tracked (privacy-first)
});

Segment to Umami:

// Segment
analytics.track('Product Purchased', {
  product_id: '123',
  price: 99.99
});

// Umami
umami.track('product_purchased', {
  price: 99.99
  // Note: product_id removed to avoid tracking individual products per user
});

Summary

Umami's data layer is fundamentally different from traditional analytics platforms:

  • No persistent user IDs: Events are anonymous and aggregated
  • Event-centric model: Focus on what happens, not who does it
  • Metadata for context: Use event properties for segmentation and analysis
  • Privacy by design: Never include PII in event data
  • Simple API: Easy to implement and maintain

This approach provides valuable business insights while respecting user privacy and simplifying compliance with data protection regulations.