@happyvertical/smrt-analytics

Server-side analytics tracking with GA4 and Plausible integration, event logging, scheduled reports, and AI-powered performance analysis.

v0.20.44GA4PlausibleAI Insights

Overview

smrt-analytics provides server-side analytics event tracking, property/data stream management, scheduled reporting, and AI-powered performance analysis for GA4 and Plausible.

Installation

bash
npm install @happyvertical/smrt-analytics

Quick Start

typescript
import {
  AnalyticsProperty, AnalyticsPropertyCollection,
  AnalyticsDataStream, AnalyticsDataStreamCollection,
  AnalyticsEvent, AnalyticsEventCollection,
  AnalyticsProvider, DataStreamType
} from '@happyvertical/smrt-analytics';

// Initialize collections
const properties = new AnalyticsPropertyCollection(db);
const streams = new AnalyticsDataStreamCollection(db);
const events = new AnalyticsEventCollection(db);

// Create GA4 property
const property = await properties.create({
  name: 'main-site',
  displayName: 'Main Site Analytics',
  provider: AnalyticsProvider.GA4,
  externalId: 'properties/123456789',
  measurementId: 'G-XXXXXXXXXX',
  apiSecret: 'server-side-secret',
  status: 'active',
});

// Add a web data stream
await streams.create({
  propertyId: property.id,
  displayName: 'Web Traffic',
  streamType: DataStreamType.WEB,
  measurementId: 'G-XXXXXXXXXX',
  defaultUri: 'https://example.com',
  status: 'active',
});

// Track a server-side event with retry support
const event = await events.create({
  propertyId: property.id,
  eventName: 'purchase',
  clientId: 'client-uuid',
  params: JSON.stringify({ value: 99.99, currency: 'USD' }),
  status: 'pending',
});

// After sending: markSent() or markFailed('timeout')
await event.markSent();

Core Models

AnalyticsProperty

typescript
class AnalyticsProperty extends SmrtObject {
  name: string
  displayName: string
  provider: 'ga4' | 'plausible'   // AnalyticsProvider enum
  externalId?: string              // e.g. 'properties/123456789'
  measurementId?: string           // GA4 (G-XXXXXXXXXX)
  apiSecret?: string               // GA4 server-side secret
  siteDomain?: string              // Plausible site domain
  status: 'active' | 'inactive' | 'pending'
  lastSyncAt?: Date

  async analyzePerformance(): Promise<string>  // AI (do())
  async isPerformingWell(): Promise<boolean>   // AI (is())
}

AnalyticsEvent

typescript
class AnalyticsEvent extends SmrtObject {
  propertyId: string
  eventName: string           // 'page_view', 'purchase', 'sign_up', etc.
  clientId: string            // Anonymous client identifier
  userId?: string             // Authenticated user
  params: string              // JSON string (use getter/setter helpers)
  eventTimestamp: Date
  status: 'pending' | 'sent' | 'failed'  // TrackingEventStatus enum
  retryCount: number
  sentAt?: Date
  errorMessage?: string

  isPageview(): boolean
  isConversion(): boolean
  async markSent(): Promise<void>       // Sets sentAt timestamp
  async markFailed(error: string): Promise<void>  // Increments retryCount
  shouldRetry(maxRetries: number): boolean
  resetForRetry(): void                 // Reset to pending for retry
  toTrackEvent(): SDKTrackEvent         // Convert to SDK payload
}

AnalyticsReport

typescript
class AnalyticsReport extends SmrtObject {
  propertyId: string
  name: string
  dimensions: string          // JSON array of dimension objects
  metrics: string             // JSON array of metric objects
  dateRangeStart: string      // e.g. '7daysAgo'
  dateRangeEnd: string        // e.g. 'today'
  frequency: 'once' | 'daily' | 'weekly' | 'monthly'  // ReportFrequency
  status: 'draft' | 'scheduled' | 'running' | 'completed' | 'failed'
  resultData?: string         // Cached results (JSON)
  rowCount?: number
  lastRunAt?: Date
  nextRunAt?: Date

  isDue(): boolean
  calculateNextRun(): Date | null
  async analyzeResults(): Promise<string>     // AI (do())
  async hasPositiveTrends(): Promise<boolean> // AI (is())
}

Event Tracking

typescript
// Track page view
const pageView = await events.create({
  propertyId: property.id,
  eventName: 'page_view',
  clientId: req.cookies.clientId,
  userId: req.user?.id,
  params: {
    page_location: req.url,
    page_title: 'Product Page',
    page_referrer: req.headers.referer
  },
  eventTimestamp: new Date()
});
await pageView.save();

// Track purchase
const purchase = await events.create({
  propertyId: property.id,
  eventName: 'purchase',
  clientId: req.cookies.clientId,
  userId: req.user.id,
  params: {
    transaction_id: order.id,
    value: order.total,
    currency: 'USD',
    items: order.items.map(item => ({
      item_id: item.productId,
      item_name: item.name,
      quantity: item.quantity,
      price: item.price
    }))
  },
  eventTimestamp: new Date()
});
await purchase.save();

// Get stats
const stats = await events.getPropertyStats(property.id);
console.log(`Total: ${stats.total}, Sent: ${stats.sent}`);

Scheduled Reports

typescript
// Create weekly report
const report = await reports.create({
  propertyId: property.id,
  name: 'Weekly Traffic Report',
  dimensions: ['country', 'deviceCategory', 'date'],
  metrics: ['activeUsers', 'sessions', 'bounceRate'],
  dateRange: 'last7Days',
  frequency: 'WEEKLY',
  status: 'SCHEDULED'
});
await report.save();

// Check if due
if (report.isDue()) {
  report.status = 'RUNNING';
  await report.save();

  // Run report (integrate with SDK)
  const results = await runAnalyticsReport(report);

  report.resultData = results;
  report.rowCount = results.length;
  report.lastRunAt = new Date();
  report.status = 'COMPLETED';
  await report.save();

  // AI analysis
  const insights = await report.analyzeResults();
  console.log(insights);
}

AI-Powered Analysis

typescript
// Analyze property performance
const analysis = await property.analyzePerformance();
// "Traffic up 15% this week. Top sources: organic search (45%),
//  direct (30%). Mobile usage increased to 68%."

const isHealthy = await property.isPerformingWell();
// true if metrics trending positively

// Analyze report trends
const reportInsights = await report.analyzeResults();
// "US traffic grew 20%, UK declined 5%. Mobile bounce rate
//  improved from 65% to 58%."

const hasGrowth = await report.hasPositiveTrends();
// true if key metrics improving

Best Practices

Related Modules