Skip to main content
← Back to Quickstart Guides

Stream Analytics (PULSE)

Real-time metrics powered by Cloudflare GraphQL Analytics Engine

15 minutes
Intermediate
REST API
GraphQL
WebSocket
10M+
Data Points/Sec
<50ms
Query Latency
365 days
Data Retention
275+
Global Edge

Analytics Overview

WAVE PULSE provides comprehensive analytics powered by Cloudflare's GraphQL Analytics Engine. Access real-time viewer counts, engagement metrics, quality of experience data, geographic distribution, and revenue tracking for all your streams.

Viewership

Concurrent, unique, segments

Engagement

Watch time, chat, reactions

Quality

Rebuffer, startup, bitrate

Geography

Country, region, city

Revenue

Ads, subs, donations

API Endpoints

RESTful and GraphQL endpoints for analytics data

GET /api/v1/streams/:id/analytics

Get aggregated analytics for a specific stream

start (ISO timestamp)
end (ISO timestamp)
granularity (minute|hour|day)
GET /api/v1/streams/:id/analytics/realtime

Get real-time viewer count and quality metrics

window (seconds, default 60)
GET /api/v1/analytics/overview

Get account-wide analytics summary

start
end
streams[] (optional filter)
GET /api/v1/streams/:id/analytics/geography

Get viewer distribution by country/region

start
end
limit (default 50)
GET /api/v1/streams/:id/analytics/quality

Get quality of experience metrics

start
end
percentiles (p50|p90|p99)
POST /api/v1/analytics/events

Track custom events and user actions

event_name
properties (JSON)
user_id (optional)
GET /api/v1/analytics/funnels/:id

Get conversion funnel analytics

start
end
breakdown (optional)
POST /api/v1/analytics/query

Execute custom GraphQL analytics query

query (GraphQL)
variables (JSON)

SDK Examples

// Get stream analytics for the last 24 hours
import { WaveAnalytics } from '@wave/analytics';

const analytics = new WaveAnalytics({
  apiKey: process.env.WAVE_API_KEY
});

// Fetch aggregated metrics
const metrics = await analytics.streams.getMetrics('stream_abc123', {
  start: new Date(Date.now() - 86400000),
  end: new Date(),
  granularity: 'hour',
  metrics: ['views', 'watch_time', 'quality', 'geography']
});

console.log('Peak viewers:', metrics.peak_concurrent);
console.log('Avg watch time:', metrics.avg_watch_time_minutes, 'minutes');
console.log('Quality score:', metrics.quality_score);

// Real-time updates via WebSocket
const realtime = analytics.streams.subscribe('stream_abc123');

realtime.on('metrics', (data) => {
  console.log('Current viewers:', data.concurrent_viewers);
  console.log('Bitrate:', data.avg_bitrate_kbps, 'kbps');
  console.log('Buffer ratio:', data.rebuffer_rate, '%');
});

realtime.on('milestone', (milestone) => {
  console.log('Milestone reached:', milestone.type, milestone.value);
  // e.g., { type: 'viewers', value: 1000, label: '1K viewers!' }
});

Metrics Reference

Complete reference of available analytics metrics

Viewership

total_views
integer

Total unique viewer sessions

peak_concurrent
integer

Maximum simultaneous viewers

average_concurrent
float

Average simultaneous viewers

unique_viewers
integer

Distinct viewer IDs (authenticated)

new_viewers
integer

First-time viewers this period

returning_viewers
integer

Viewers who watched before

Engagement

total_watch_time_minutes
float

Sum of all viewer watch time

avg_watch_time_minutes
float

Average session duration

completion_rate
float

VOD: % who watched to end

chat_messages
integer

Total chat messages sent

reactions
integer

Total reactions (likes, emotes)

shares
integer

Stream shares to social media

Quality

rebuffer_rate
float

Percentage of time spent buffering

startup_time_ms
integer

Time to first frame (median)

bitrate_kbps
integer

Average delivered bitrate

error_rate
float

Percentage of failed playback attempts

quality_score
float

Composite QoE score (0-100)

frame_drops
integer

Total dropped frames

Geography

by_country
array

Views grouped by ISO country code

by_region
array

Views grouped by region/state

by_city
array

Views grouped by city (Enterprise)

by_asn
array

Views grouped by ISP/ASN

by_edge_location
array

Views by WAVE edge node

Revenue

total_revenue
float

Total revenue from stream

ad_impressions
integer

Total ad impressions served

ad_revenue
float

Revenue from advertisements

subscription_revenue
float

Revenue from subscriptions

donation_revenue
float

Revenue from donations/tips

arpu
float

Average revenue per user

Custom Event Tracking

Track custom events beyond built-in metrics. Use for purchases, subscriptions, engagement milestones, and any business-specific events.

// Track custom events for deeper analytics
import { WaveAnalytics } from '@wave/analytics';

const analytics = new WaveAnalytics({ apiKey: process.env.WAVE_API_KEY });

// Track viewer subscription
await analytics.track({
  event: 'subscription_started',
  userId: 'user_xyz789',
  streamId: 'stream_abc123',
  properties: {
    tier: 'premium',
    price: 9.99,
    currency: 'USD',
    trial: false,
    referrer: 'twitter_campaign'
  }
});

// Track purchase in stream
await analytics.track({
  event: 'purchase_completed',
  userId: 'user_xyz789',
  streamId: 'stream_abc123',
  properties: {
    product_id: 'merch_001',
    product_name: 'Team Jersey',
    price: 49.99,
    quantity: 1,
    category: 'merchandise'
  }
});

// Track engagement milestones
await analytics.track({
  event: 'engagement_milestone',
  userId: 'user_xyz789',
  streamId: 'stream_abc123',
  properties: {
    milestone: 'first_chat_message',
    watch_time_minutes: 5,
    session_number: 1
  }
});

// Track quality issues (auto-collected, but can supplement)
await analytics.track({
  event: 'quality_issue_reported',
  userId: 'user_xyz789',
  streamId: 'stream_abc123',
  properties: {
    issue_type: 'buffering',
    duration_seconds: 3,
    user_reported: true,
    network_type: '4g'
  }
});

Analytics Alerts

Configure real-time alerts for viewer milestones, quality issues, revenue targets, and anomaly detection.

// Configure analytics alerts
import { WaveAnalytics } from '@wave/analytics';

const analytics = new WaveAnalytics({ apiKey: process.env.WAVE_API_KEY });

// Viewer milestone alerts
await analytics.alerts.create({
  name: 'Viewer Milestone',
  type: 'threshold',
  metric: 'concurrent_viewers',
  condition: 'greater_than',
  thresholds: [100, 500, 1000, 5000, 10000],
  channels: ['webhook', 'email'],
  webhook_url: 'https://yourapp.com/webhooks/milestones',
  cooldown_minutes: 5
});

// Quality degradation alert
await analytics.alerts.create({
  name: 'Quality Alert',
  type: 'threshold',
  metric: 'rebuffer_rate',
  condition: 'greater_than',
  threshold: 5.0,  // 5% rebuffer rate
  channels: ['webhook', 'slack'],
  slack_channel: '#streaming-ops',
  severity: 'warning'
});

// Revenue target alert
await analytics.alerts.create({
  name: 'Revenue Goal',
  type: 'cumulative',
  metric: 'total_revenue',
  condition: 'greater_than',
  threshold: 10000,  // $10,000
  period: 'day',
  channels: ['email'],
  recipients: ['[email protected]']
});

// Anomaly detection (ML-powered)
await analytics.alerts.create({
  name: 'Traffic Anomaly',
  type: 'anomaly',
  metric: 'concurrent_viewers',
  sensitivity: 'medium',  // low, medium, high
  channels: ['webhook', 'pagerduty'],
  severity: 'critical'
});

Data Warehouse Export

Export analytics data to your data warehouse for advanced analysis, ML training, and integration with your existing BI tools.

BigQuery
Snowflake
Redshift
Databricks
S3/GCS
Webhook
// Export analytics to data warehouses
import { WaveAnalytics } from '@wave/analytics';

const analytics = new WaveAnalytics({ apiKey: process.env.WAVE_API_KEY });

// Configure BigQuery export
await analytics.exports.configure({
  destination: 'bigquery',
  project_id: 'your-gcp-project',
  dataset: 'wave_analytics',
  credentials: process.env.GCP_SERVICE_ACCOUNT_KEY,
  tables: {
    events: 'stream_events',
    metrics: 'stream_metrics',
    sessions: 'viewer_sessions'
  },
  schedule: 'hourly',  // hourly, daily, realtime
  partitioning: {
    field: 'timestamp',
    type: 'DAY'
  }
});

// Configure Snowflake export
await analytics.exports.configure({
  destination: 'snowflake',
  account: 'your-account.us-east-1',
  warehouse: 'WAVE_WH',
  database: 'ANALYTICS',
  schema: 'STREAMING',
  credentials: {
    user: process.env.SNOWFLAKE_USER,
    private_key: process.env.SNOWFLAKE_PRIVATE_KEY
  },
  schedule: 'daily'
});

// S3 export for custom processing
await analytics.exports.configure({
  destination: 's3',
  bucket: 'your-analytics-bucket',
  prefix: 'wave-analytics/',
  format: 'parquet',  // parquet, json, csv
  compression: 'snappy',
  partition_by: ['date', 'stream_id'],
  schedule: 'hourly'
});

// Webhook for real-time streaming
await analytics.exports.configure({
  destination: 'webhook',
  url: 'https://your-pipeline.com/ingest',
  format: 'json',
  batch_size: 100,
  batch_timeout_ms: 5000,
  headers: {
    'Authorization': 'Bearer YOUR_PIPELINE_TOKEN'
  }
});

Conversion Funnels

Track user journeys from first view to conversion. Analyze drop-off points and optimize your streaming experience for better conversion rates.

// Create and analyze conversion funnels
import { WaveAnalytics } from '@wave/analytics';

const analytics = new WaveAnalytics({ apiKey: process.env.WAVE_API_KEY });

// Define a subscription conversion funnel
const funnel = await analytics.funnels.create({
  name: 'Subscription Conversion',
  steps: [
    { event: 'stream_viewed', label: 'Watched Stream' },
    { event: 'signup_started', label: 'Started Signup' },
    { event: 'signup_completed', label: 'Completed Signup' },
    { event: 'trial_started', label: 'Started Trial' },
    { event: 'subscription_started', label: 'Subscribed' }
  ],
  window_days: 7,  // 7-day conversion window
  breakdown_by: ['country', 'device', 'referrer']
});

// Get funnel analytics
const funnelData = await analytics.funnels.get(funnel.id, {
  start: new Date(Date.now() - 30 * 86400000),  // Last 30 days
  end: new Date(),
  breakdown: 'referrer'
});

console.log('Funnel Analysis:');
funnelData.steps.forEach((step, i) => {
  const conversionRate = i > 0
    ? ((step.count / funnelData.steps[i-1].count) * 100).toFixed(1)
    : '100.0';
  console.log(`${step.label}: ${step.count.toLocaleString()} (${conversionRate}%)`);
});

console.log('\nBreakdown by Referrer:');
funnelData.breakdown.forEach(segment => {
  console.log(`${segment.value}: ${segment.conversion_rate.toFixed(1)}% conversion`);
});

Rate Limits & Data Retention

TierRate LimitRetentionMin GranularityExports
Free100/minute7 dayshourCSV only
Pro500/minute30 daysminuteCSV, JSON
Business2000/minute90 daysminuteAll formats
Enterprise10000/minute365 dayssecondAll + Streaming

Best Practices

Use appropriate granularity

Use minute granularity for real-time dashboards, hourly for daily reports, daily for long-term trends.

granularity=minute for last-hour data
granularity=minute for 30-day reports (too much data)

Cache appropriately

Historical analytics are immutable. Cache aggressively for past periods.

Cache completed periods (yesterday, last week)
Cache current period data (changes constantly)

Use WebSocket for real-time

For live dashboards, use the WebSocket endpoint instead of polling.

WebSocket connection with 5-second updates
Polling REST API every second

Batch requests efficiently

Request multiple streams in a single call when possible.

GET /analytics/overview?streams[]=a&streams[]=b
Multiple individual stream requests

Use server-side aggregation

Let the API aggregate data instead of fetching raw events.

Request pre-aggregated metrics with granularity
Fetch all raw events and aggregate client-side

Index custom events properly

Use consistent event names and property schemas for queryability.

snake_case event names, typed properties
Dynamic event names, unstructured properties

Troubleshooting

Missing Analytics Data
Inaccurate Viewer Counts
Slow Query Performance
Real-time Data Lag
Export/Integration Failures

Success Stories

Real-Time Viewer Dashboards

ESPN DigitalSports Broadcasting

Challenge

Building real-time dashboards for 50+ concurrent live sports events with viewer counts updating every second

Solution

WebSocket-based analytics with edge aggregation for sub-second updates across global CDN

Results

<100ms dashboard latency
50M concurrent viewer tracking
99.99% data accuracy
"

WAVE's analytics infrastructure handles our biggest events without breaking a sweat. Super Bowl data flows as smoothly as a regular Tuesday game.

JM
Jennifer Martinez
Director of Digital Products

ML-Powered Churn Prediction

StreamMaxSubscription Streaming

Challenge

Predicting subscriber churn using viewing behavior patterns to enable proactive retention

Solution

Custom event tracking with BigQuery export feeding ML models for real-time churn scores

Results

67% churn prediction accuracy
23% reduction in churn rate
$4.2M annual savings
"

The granularity of WAVE analytics data transformed our ML models. We can now predict churn 14 days in advance with high confidence.

AK
Dr. Alex Kim
Head of Data Science

Ad Revenue Optimization

MediaCorp GlobalDigital Advertising

Challenge

Optimizing mid-roll ad placement to maximize revenue without impacting viewer engagement

Solution

Engagement analytics with A/B testing framework to find optimal ad insertion points

Results

340% increase in ad completion
45% higher CPMs
No drop in viewer retention
"

Data-driven ad placement using WAVE analytics increased our streaming ad revenue by 3x in six months.

MC
Michael Chen
VP of Advertising
WAVE - Enterprise Live Streaming Platform