@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-analyticsQuick 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