Analytics
Analytics API
Monitor your video performance with comprehensive analytics and usage metrics. HesedVid’s Analytics API provides detailed insights into video delivery, storage usage, resolution distribution, and viewer engagement to help you optimize your video strategy and make data-driven decisions.
Tip
Analytics data is updated in real-time and provides insights into how your videos are being consumed across different devices and network conditions.
Why Analytics Matter
Video analytics help you:
- Optimize Performance: Understand which resolutions are most popular and adjust encoding strategies
- Control Costs: Monitor storage usage and delivery patterns to optimize spending
- Improve User Experience: Identify performance bottlenecks and optimize video delivery
- Make Data-Driven Decisions: Track trends and patterns to inform content strategy
- Monitor Health: Detect issues early through usage pattern analysis
Analytics Overview
The Analytics API provides five key endpoints for comprehensive video insights:
📊 Account Usage
Overall usage statistics and trends for your organization
GET /{orgID}/analytics/usage📅 Daily Usage
Day-by-day breakdown of video delivery metrics
GET /{orgID}/analytics/daily💾 Storage Usage
Storage consumption and video duration analytics
GET /{orgID}/analytics/storage🎥 Video Resolution
Individual video performance and resolution data
GET /{orgID}/videos/{publicID}/analytics/resolution📈 Resolution Distribution
Account-wide resolution usage patterns and trends
GET /{orgID}/analytics/resolution-distributionKey Metrics Explained
Segments vs Views
HesedVid tracks segments served rather than traditional “views” for more accurate analytics:
- Segment: A 6-second chunk of video data delivered to a player
- View: Typically calculated as
segments_served ÷ (video_duration_seconds ÷ 6) - Why Segments: More accurate than page views, accounts for seeking, buffering, and partial views
Resolution Categories
| Category | Resolution | Description |
|---|---|---|
| HD | 1080p+ | High definition segments |
| SD | 720p | Standard definition segments |
| LD | 480p and below | Low definition segments |
Quality Tiers
| Tier | Description | Use Case |
|---|---|---|
| Ultra | Highest quality encoding | Premium content, large screens |
| High | High quality encoding | Standard content, most use cases |
| Standard | Baseline quality encoding | Mobile, low bandwidth |
Account Usage Analytics
/{orgID}/analytics/usage
Get comprehensive usage statistics for your organization or specific environment. This endpoint provides high-level metrics about your video library, delivery performance, and growth trends.
When to Use
- Dashboard Overview: Display key metrics on your admin dashboard
- Growth Tracking: Monitor video uploads and delivery trends over time
- Account Health: Check if your account is actively serving content
- Billing Insights: Understand usage patterns for cost optimization
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orgID | string | Yes | Your organization’s unique identifier |
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
periodDays | int | No | 30 | Number of days to look back for statistics (1-365) |
Tip
Use shorter periods (7-14 days) for recent activity analysis, and longer periods (90-365 days) for trend analysis and growth tracking.
Response Fields Explained
| Field | Type | Description | Business Value |
|---|---|---|---|
totalVideos | int64 | Total videos in your account | Library size, content volume |
totalVideoDurationSeconds | float64 | Total duration of all videos | Storage usage, content hours |
totalSegmentsServed | int64 | All-time segments delivered | Total engagement, platform usage |
videosUploadedInPeriod | int64 | New videos in specified period | Content growth rate, upload activity |
segmentsServedInPeriod | int64 | Segments served in specified period | Recent engagement, delivery volume |
firstVideoUploaded | string | Timestamp of first upload | Account age, platform adoption |
lastSegmentServed | string | Most recent delivery | Account activity, content freshness |
Response Example
{ "body": { "usage": [ { "workosOrgId": "org_123456789", "envId": "env_prod_123456789", "totalVideos": 150, "totalVideoDurationSeconds": 45000.5, "totalSegmentsServed": 125000, "videosUploadedInPeriod": 25, "segmentsServedInPeriod": 15000, "firstVideoUploaded": "2024-01-01T10:00:00Z", "firstVideoUploadedValid": true, "lastSegmentServed": "2024-01-15T14:30:00Z", "lastSegmentServedValid": true } ] }}Calculating Key Metrics
// Calculate views from segmentsconst calculateViews = (segmentsServed, videoDurationSeconds) => { return Math.round(segmentsServed / (videoDurationSeconds / 6));};
// Calculate average video lengthconst avgVideoLength = totalVideoDurationSeconds / totalVideos;
// Calculate engagement rateconst engagementRate = segmentsServedInPeriod / videosUploadedInPeriod;Example Request
# Get usage for last 30 dayscurl -X GET "https://api.hesedvid.com/v1/api/org_123456789/analytics/usage" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"
# Get usage for last 7 dayscurl -X GET "https://api.hesedvid.com/v1/api/org_123456789/analytics/usage?periodDays=7" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"// Get account usage analyticsconst getAccountUsage = async (periodDays = 30) => { const response = await fetch(`https://api.hesedvid.com/v1/api/org_123456789/analytics/usage?periodDays=${periodDays}`, { headers: { 'X-Api-Key': 'hv_live_123456789abcdefghijklmnopqrstuvwxyz' } }); return response.json();};
// Get last 7 days usageconst response = await fetch(`/v1/api/org_123456789/analytics/usage?periodDays=7`);const weeklyUsage = await response.json();import requestsfrom datetime import datetime, timedelta
def get_account_usage(period_days=30): url = f"https://api.hesedvid.com/v1/api/org_123456789/analytics/usage" headers = { "X-Api-Key": "hv_live_123456789abcdefghijklmnopqrstuvwxyz" } params = {"periodDays": period_days}
response = requests.get(url, headers=headers, params=params) return response.json()
# Get last 7 days usageweekly_usage = get_account_usage(7)Daily Usage Analytics
/{orgID}/analytics/daily
Get day-by-day breakdown of video delivery metrics for trend analysis. This endpoint provides granular daily data to identify patterns, peak usage times, and quality distribution trends.
When to Use
- Trend Analysis: Identify daily, weekly, or monthly patterns in video consumption
- Performance Monitoring: Track delivery performance over time
- Quality Optimization: Understand resolution preferences by day
- Capacity Planning: Predict future bandwidth and storage needs
- Business Intelligence: Correlate video usage with business events
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orgID | string | Yes | Your organization’s unique identifier |
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
startDate | string | No | 30 days ago | Start date in YYYY-MM-DD format |
endDate | string | No | Today | End date in YYYY-MM-DD format |
Tip
For trend analysis, use 30-90 day periods. For detailed analysis, use 7-14 day periods. Maximum range is 365 days.
Response Fields Explained
| Field | Type | Description | Business Value |
|---|---|---|---|
deliveryDate | string | Date of delivery (UTC) | Time-based analysis, trend identification |
segmentsServed | int64 | Total segments delivered | Daily engagement volume |
uniqueVideosServed | int64 | Number of unique videos | Content diversity, catalog utilization |
hdSegments | int64 | High definition segments | Premium content consumption |
sdSegments | int64 | Standard definition segments | Standard content consumption |
ldSegments | int64 | Low definition segments | Mobile/low-bandwidth consumption |
Response Example
{ "body": { "dailyUsage": [ { "deliveryDate": "2024-01-15T00:00:00Z", "segmentsServed": 1250, "uniqueVideosServed": 45, "hdSegments": 800, "sdSegments": 350, "ldSegments": 100 }, { "deliveryDate": "2024-01-14T00:00:00Z", "segmentsServed": 980, "uniqueVideosServed": 32, "hdSegments": 650, "sdSegments": 250, "ldSegments": 80 } ] }}Analyzing Daily Trends
// Calculate quality distribution percentagesconst analyzeQualityDistribution = (dailyData) => { return dailyData.map(day => { const total = day.segmentsServed; return { date: day.deliveryDate, total: total, hdPercentage: (day.hdSegments / total) * 100, sdPercentage: (day.sdSegments / total) * 100, ldPercentage: (day.ldSegments / total) * 100 }; });};
// Find peak usage daysconst findPeakDays = (dailyData) => { return dailyData .sort((a, b) => b.segmentsServed - a.segmentsServed) .slice(0, 5);};
// Calculate weekly averagesconst calculateWeeklyAverage = (dailyData) => { const totalSegments = dailyData.reduce((sum, day) => sum + day.segmentsServed, 0); return totalSegments / dailyData.length;};Example Request
# Get daily usage for last 30 dayscurl -X GET "https://api.hesedvid.com/v1/api/org_123456789/analytics/daily" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"
# Get daily usage for specific date rangecurl -X GET "https://api.hesedvid.com/v1/api/org_123456789/analytics/daily?startDate=2024-01-01&endDate=2024-01-31" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"// Get daily usage analyticsconst getDailyUsage = async (startDate, endDate) => { const params = new URLSearchParams(); if (startDate) params.append('startDate', startDate); if (endDate) params.append('endDate', endDate);
const response = await fetch(`https://api.hesedvid.com/v1/api/org_123456789/analytics/daily?${params}`, { headers: { 'X-Api-Key': 'hv_live_123456789abcdefghijklmnopqrstuvwxyz' } }); return response.json();};
// Get January 2024 daily usageconst response = await fetch(`/v1/api/org_123456789/analytics/daily?startDate=2024-01-01&endDate=2024-01-31`);const januaryUsage = await response.json();Storage Usage Analytics
/{orgID}/analytics/storage
Get detailed storage consumption and video duration analytics. This endpoint helps you understand your storage footprint, optimize encoding strategies, and plan for storage costs.
When to Use
- Storage Optimization: Understand which quality tiers consume the most storage
- Cost Management: Calculate storage costs and identify optimization opportunities
- Content Strategy: Analyze video length patterns to inform content creation
- Capacity Planning: Plan for future storage needs based on current usage
- Quality Decisions: Balance quality vs. storage costs
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orgID | string | Yes | Your organization’s unique identifier |
Response Fields Explained
| Field | Type | Description | Business Value |
|---|---|---|---|
totalVideos | int64 | Total number of videos stored | Library size, content count |
totalDurationSeconds | float64 | Total duration of all videos | Storage baseline, content hours |
avgVideoDuration | float64 | Average video length | Content strategy insights |
ultraQualityDuration | float64 | Duration of ultra quality videos | Premium content storage |
highQualityDuration | float64 | Duration of high quality videos | Standard content storage |
standardQualityDuration | float64 | Duration of standard quality videos | Baseline content storage |
Response Example
{ "body": { "storage": { "totalVideos": 150, "totalDurationSeconds": 45000.5, "avgVideoDuration": 300.0, "ultraQualityDuration": 15000.2, "highQualityDuration": 20000.1, "standardQualityDuration": 10000.2 } }}Storage Analysis Examples
// Calculate storage distribution percentagesconst analyzeStorageDistribution = (storageData) => { const total = storageData.totalDurationSeconds; return { ultraPercentage: (storageData.ultraQualityDuration / total) * 100, highPercentage: (storageData.highQualityDuration / total) * 100, standardPercentage: (storageData.standardQualityDuration / total) * 100, totalHours: total / 3600, avgMinutes: storageData.avgVideoDuration / 60 };};
// Estimate storage costs (example rates)const estimateStorageCosts = (storageData, costPerHour = 0.01) => { const totalHours = storageData.totalDurationSeconds / 3600; return { monthlyCost: totalHours * costPerHour, ultraCost: (storageData.ultraQualityDuration / 3600) * costPerHour, highCost: (storageData.highQualityDuration / 3600) * costPerHour, standardCost: (storageData.standardQualityDuration / 3600) * costPerHour };};
// Identify optimization opportunitiesconst findOptimizationOpportunities = (storageData) => { const ultraRatio = storageData.ultraQualityDuration / storageData.totalDurationSeconds; const highRatio = storageData.highQualityDuration / storageData.totalDurationSeconds;
return { ultraOptimization: ultraRatio > 0.5 ? "Consider reducing ultra quality usage" : "Ultra quality usage is reasonable", highOptimization: highRatio > 0.7 ? "High quality dominates - consider standard for some content" : "Good quality distribution", avgLengthOptimization: storageData.avgVideoDuration > 600 ? "Consider shorter videos" : "Video length is appropriate" };};Example Request
curl -X GET "https://api.hesedvid.com/v1/api/org_123456789/analytics/storage" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"// Get storage usage analyticsconst getStorageUsage = async () => { const response = await fetch('https://api.hesedvid.com/v1/api/org_123456789/analytics/storage', { headers: { 'X-Api-Key': 'hv_live_123456789abcdefghijklmnopqrstuvwxyz' } }); return response.json();};
const response = await fetch('/v1/api/org_123456789/analytics/storage');const storageData = await response.json();console.log(`Total videos: ${storageData.body.storage.totalVideos}`);console.log(`Total duration: ${storageData.body.storage.totalDurationSeconds} seconds`);Video Resolution Analytics
/{orgID}/videos/{publicID}/analytics/resolution
Get detailed resolution analytics for a specific video. This endpoint provides insights into how individual videos are consumed across different resolutions and devices.
When to Use
- Content Performance: Understand which resolutions are most popular for specific videos
- Quality Optimization: Identify if certain videos need different encoding strategies
- Device Analysis: Understand viewer device capabilities and preferences
- Content Strategy: Optimize video content based on actual consumption patterns
- A/B Testing: Compare performance across different video versions
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orgID | string | Yes | Your organization’s unique identifier |
publicID | string | Yes | The public ID of the video asset |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
startDate | string | No | Start date in YYYY-MM-DD format (optional) |
endDate | string | No | End date in YYYY-MM-DD format (optional) |
Tip
Use date ranges to analyze specific campaigns, events, or time periods. Leave empty for all-time data.
Response Fields Explained
Summary Fields
| Field | Type | Description | Business Value |
|---|---|---|---|
totalSegmentsServed | int64 | Total segments delivered | Video popularity, engagement |
totalDaysServed | int64 | Days the video was actively served | Content longevity, sustained interest |
mostPopularResolution | int32 | Most requested resolution | Device preferences, quality optimization |
availableResolutions | int32 | Number of resolution variants | Encoding completeness |
Resolution Fields
| Field | Type | Description | Business Value |
|---|---|---|---|
resolutionHeight | int32 | Video resolution height | Device capability analysis |
timesServed | int64 | Segments served at this resolution | Resolution popularity |
daysServed | int64 | Days this resolution was active | Resolution longevity |
Response Example
{ "body": { "summary": { "vidId": "vid_123456789abcdef", "vidPublicId": "pubvid_AbCdEf", "vidName": "My Video", "vidNameValid": true, "vidLengthSeconds": 300.5, "availableResolutions": 3, "totalSegmentsServed": 1500, "totalDaysServed": 15, "firstServed": "2024-01-01T10:00:00Z", "firstServedValid": true, "lastServed": "2024-01-15T14:30:00Z", "lastServedValid": true, "mostPopularResolution": 1080, "mostPopularResolutionValid": true }, "resolutions": [ { "vidId": "vid_123456789abcdef", "vidPublicId": "pubvid_AbCdEf", "vidName": "My Video", "vidNameValid": true, "resolutionHeight": 1080, "timesServed": 800, "firstServed": "2024-01-01T10:00:00Z", "firstServedValid": true, "lastServed": "2024-01-15T14:30:00Z", "lastServedValid": true, "daysServed": 15 }, { "vidId": "vid_123456789abcdef", "vidPublicId": "pubvid_AbCdEf", "vidName": "My Video", "vidNameValid": true, "resolutionHeight": 720, "timesServed": 500, "firstServed": "2024-01-01T10:00:00Z", "firstServedValid": true, "lastServed": "2024-01-15T14:30:00Z", "lastServedValid": true, "daysServed": 12 } ] }}Video Performance Analysis
// Calculate resolution distributionconst analyzeVideoResolutions = (videoData) => { const totalSegments = videoData.summary.totalSegmentsServed;
return videoData.resolutions.map(res => ({ resolution: res.resolutionHeight, segments: res.timesServed, percentage: (res.timesServed / totalSegments) * 100, daysActive: res.daysServed, avgSegmentsPerDay: res.timesServed / res.daysServed }));};
// Calculate estimated viewsconst calculateVideoViews = (videoData) => { const videoLength = videoData.summary.vidLengthSeconds; const segmentsPerView = videoLength / 6; // 6 seconds per segment return Math.round(videoData.summary.totalSegmentsServed / segmentsPerView);};
// Identify optimization opportunitiesconst findVideoOptimizations = (videoData) => { const resolutions = videoData.resolutions.sort((a, b) => b.timesServed - a.timesServed); const topResolution = resolutions[0]; const topPercentage = (topResolution.timesServed / videoData.summary.totalSegmentsServed) * 100;
return { dominantResolution: topResolution.resolutionHeight, dominantPercentage: topPercentage, optimization: topPercentage > 80 ? `Consider focusing on ${topResolution.resolutionHeight}p encoding` : "Good resolution distribution", engagement: videoData.summary.totalDaysServed > 30 ? "High engagement - evergreen content" : "Consider content refresh" };};Example Request
# Get all-time resolution analyticscurl -X GET "https://api.hesedvid.com/v1/api/org_123456789/videos/pubvid_AbCdEf/analytics/resolution" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"
# Get resolution analytics for specific periodcurl -X GET "https://api.hesedvid.com/v1/api/org_123456789/videos/pubvid_AbCdEf/analytics/resolution?startDate=2024-01-01&endDate=2024-01-31" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"// Get video resolution analyticsconst getVideoResolution = async (videoId, startDate, endDate) => { const params = new URLSearchParams(); if (startDate) params.append('startDate', startDate); if (endDate) params.append('endDate', endDate);
const response = await fetch(`https://api.hesedvid.com/v1/api/org_123456789/videos/${videoId}/analytics/resolution?${params}`, { headers: { 'X-Api-Key': 'hv_live_123456789abcdefghijklmnopqrstuvwxyz' } }); return response.json();};
// Get video analytics for January 2024const response = await fetch(`/v1/api/org_123456789/videos/pubvid_AbCdEf/analytics/resolution?startDate=2024-01-01&endDate=2024-01-31`);const videoAnalytics = await response.json();Resolution Distribution Analytics
/{orgID}/analytics/resolution-distribution
Get account-wide resolution usage patterns and distribution. This endpoint provides insights into how your entire video library is consumed across different resolutions and helps optimize your encoding strategy.
When to Use
- Encoding Strategy: Understand which resolutions to prioritize in your encoding pipeline
- Device Analysis: Identify your audience’s device capabilities and preferences
- Cost Optimization: Balance quality vs. bandwidth costs based on actual usage
- Content Planning: Plan content strategy based on resolution preferences
- Infrastructure Planning: Optimize CDN and bandwidth allocation
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orgID | string | Yes | Your organization’s unique identifier |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
startDate | string | No | Start date in YYYY-MM-DD format (optional) |
endDate | string | No | End date in YYYY-MM-DD format (optional) |
Response Fields Explained
| Field | Type | Description | Business Value |
|---|---|---|---|
resolutionHeight | int32 | Video resolution height | Device capability analysis |
segmentsServed | int64 | Total segments served at this resolution | Resolution popularity |
uniqueVideos | int64 | Number of unique videos served at this resolution | Content diversity |
daysActive | int64 | Days this resolution was actively served | Resolution longevity |
Response Example
{ "body": { "distribution": [ { "resolutionHeight": 1080, "segmentsServed": 50000, "uniqueVideos": 45, "daysActive": 30, "firstServed": "2024-01-01T10:00:00Z", "firstServedValid": true, "lastServed": "2024-01-15T14:30:00Z", "lastServedValid": true }, { "resolutionHeight": 720, "segmentsServed": 35000, "uniqueVideos": 38, "daysActive": 28, "firstServed": "2024-01-01T10:00:00Z", "firstServedValid": true, "lastServed": "2024-01-15T14:30:00Z", "lastServedValid": true }, { "resolutionHeight": 480, "segmentsServed": 15000, "uniqueVideos": 25, "daysActive": 20, "firstServed": "2024-01-01T10:00:00Z", "firstServedValid": true, "lastServed": "2024-01-15T14:30:00Z", "lastServedValid": true } ] }}Resolution Distribution Analysis
// Calculate resolution market shareconst calculateResolutionShare = (distributionData) => { const totalSegments = distributionData.reduce((sum, res) => sum + res.segmentsServed, 0);
return distributionData.map(res => ({ resolution: res.resolutionHeight, segments: res.segmentsServed, percentage: (res.segmentsServed / totalSegments) * 100, videos: res.uniqueVideos, avgSegmentsPerVideo: res.segmentsServed / res.uniqueVideos }));};
// Identify encoding prioritiesconst identifyEncodingPriorities = (distributionData) => { const sorted = distributionData.sort((a, b) => b.segmentsServed - a.segmentsServed); const totalSegments = distributionData.reduce((sum, res) => sum + res.segmentsServed, 0);
return { primaryResolution: sorted[0].resolutionHeight, primaryPercentage: (sorted[0].segmentsServed / totalSegments) * 100, recommendations: sorted.slice(0, 3).map(res => ({ resolution: res.resolutionHeight, priority: sorted.indexOf(res) + 1, segments: res.segmentsServed, percentage: (res.segmentsServed / totalSegments) * 100 })) };};
// Analyze device preferencesconst analyzeDevicePreferences = (distributionData) => { const hdSegments = distributionData.filter(r => r.resolutionHeight >= 1080) .reduce((sum, r) => sum + r.segmentsServed, 0); const sdSegments = distributionData.filter(r => r.resolutionHeight === 720) .reduce((sum, r) => sum + r.segmentsServed, 0); const ldSegments = distributionData.filter(r => r.resolutionHeight <= 480) .reduce((sum, r) => sum + r.segmentsServed, 0);
const total = hdSegments + sdSegments + ldSegments;
return { highEndDevices: (hdSegments / total) * 100, standardDevices: (sdSegments / total) * 100, mobileDevices: (ldSegments / total) * 100, recommendation: hdSegments > total * 0.6 ? "Focus on high-quality encoding" : "Balanced encoding strategy recommended" };};Example Request
# Get all-time resolution distributioncurl -X GET "https://api.hesedvid.com/v1/api/org_123456789/analytics/resolution-distribution" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"
# Get resolution distribution for specific periodcurl -X GET "https://api.hesedvid.com/v1/api/org_123456789/analytics/resolution-distribution?startDate=2024-01-01&endDate=2024-01-31" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"// Get resolution distribution analyticsconst getResolutionDistribution = async (startDate, endDate) => { const params = new URLSearchParams(); if (startDate) params.append('startDate', startDate); if (endDate) params.append('endDate', endDate);
const response = await fetch(`https://api.hesedvid.com/v1/api/org_123456789/analytics/resolution-distribution?${params}`, { headers: { 'X-Api-Key': 'hv_live_123456789abcdefghijklmnopqrstuvwxyz' } }); return response.json();};
// Get January 2024 resolution distributionconst response = await fetch(`/v1/api/org_123456789/analytics/resolution-distribution?startDate=2024-01-01&endDate=2024-01-31`);const resolutionDistribution = await response.json();Environment-Specific Analytics
All analytics endpoints support environment-specific filtering by including the environment ID in the path:
/{orgID}/environments/{envID}/analytics/usage/{orgID}/environments/{envID}/analytics/daily/{orgID}/environments/{envID}/analytics/storage/{orgID}/environments/{envID}/analytics/resolution-distribution
Example: Environment-Specific Usage
# Get usage for specific environmentcurl -X GET "https://api.hesedvid.com/v1/api/org_123456789/environments/env_prod_123456789/analytics/usage" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"Analytics Data Types
Account Usage Metrics
| Field | Type | Description |
|---|---|---|
totalVideos | int64 | Total number of videos in account |
totalVideoDurationSeconds | float64 | Total duration of all videos in seconds |
totalSegmentsServed | int64 | Total video segments delivered |
videosUploadedInPeriod | int64 | Videos uploaded in the specified period |
segmentsServedInPeriod | int64 | Segments served in the specified period |
firstVideoUploaded | string | Timestamp of first video upload |
lastSegmentServed | string | Timestamp of most recent segment delivery |
Daily Usage Metrics
| Field | Type | Description |
|---|---|---|
deliveryDate | string | Date of delivery (YYYY-MM-DD) |
segmentsServed | int64 | Total segments served on this date |
uniqueVideosServed | int64 | Number of unique videos served |
hdSegments | int64 | High definition segments served |
sdSegments | int64 | Standard definition segments served |
ldSegments | int64 | Low definition segments served |
Storage Metrics
| Field | Type | Description |
|---|---|---|
totalVideos | int64 | Total number of videos stored |
totalDurationSeconds | float64 | Total duration of all videos |
avgVideoDuration | float64 | Average video duration |
ultraQualityDuration | float64 | Duration of ultra quality videos |
highQualityDuration | float64 | Duration of high quality videos |
standardQualityDuration | float64 | Duration of standard quality videos |
Video Resolution Metrics
| Field | Type | Description |
|---|---|---|
resolutionHeight | int32 | Video resolution height in pixels |
timesServed | int64 | Number of times this resolution was served |
daysServed | int64 | Number of days this resolution was active |
firstServed | string | First time this resolution was served |
lastServed | string | Most recent time this resolution was served |
Advanced Analytics Use Cases
Comprehensive Dashboard Analytics
// Build comprehensive analytics dashboardconst buildAnalyticsDashboard = async (orgId, periodDays = 30) => { const endDate = new Date().toISOString().split('T')[0]; const startDate = new Date(Date.now() - periodDays * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
// Example: Fetch all analytics data in parallel const [accountUsage, dailyUsage, storageUsage, resolutionDistribution] = await Promise.all([ fetch(`/v1/api/${orgId}/analytics/usage?periodDays=${periodDays}`), fetch(`/v1/api/${orgId}/analytics/daily?startDate=${startDate}&endDate=${endDate}`), fetch(`/v1/api/${orgId}/analytics/storage`), fetch(`/v1/api/${orgId}/analytics/resolution-distribution?startDate=${startDate}&endDate=${endDate}`) ]);
// Calculate key metrics const totalSegments = dailyUsage.body.dailyUsage.reduce((sum, day) => sum + day.segmentsServed, 0); const avgDailySegments = totalSegments / periodDays; const peakDay = dailyUsage.body.dailyUsage.reduce((max, day) => day.segmentsServed > max.segmentsServed ? day : max );
return { overview: { totalVideos: accountUsage.body.usage[0].totalVideos, totalSegments: accountUsage.body.usage[0].totalSegmentsServed, newVideosInPeriod: accountUsage.body.usage[0].videosUploadedInPeriod, segmentsInPeriod: accountUsage.body.usage[0].segmentsServedInPeriod }, trends: { dailyAverage: avgDailySegments, peakDay: peakDay.deliveryDate, peakSegments: peakDay.segmentsServed, growthRate: calculateGrowthRate(dailyUsage.body.dailyUsage) }, storage: { totalHours: storageUsage.body.storage.totalDurationSeconds / 3600, avgVideoLength: storageUsage.body.storage.avgVideoDuration / 60, qualityDistribution: { ultra: (storageUsage.body.storage.ultraQualityDuration / storageUsage.body.storage.totalDurationSeconds) * 100, high: (storageUsage.body.storage.highQualityDuration / storageUsage.body.storage.totalDurationSeconds) * 100, standard: (storageUsage.body.storage.standardQualityDuration / storageUsage.body.storage.totalDurationSeconds) * 100 } }, resolutionBreakdown: resolutionDistribution.body.distribution.map(d => ({ resolution: d.resolutionHeight, segments: d.segmentsServed, percentage: (d.segmentsServed / totalSegments) * 100, videos: d.uniqueVideos })) };};
// Calculate week-over-week growth rateconst calculateGrowthRate = (dailyData) => { if (dailyData.length < 14) return 0;
const firstWeek = dailyData.slice(0, 7).reduce((sum, day) => sum + day.segmentsServed, 0); const secondWeek = dailyData.slice(7, 14).reduce((sum, day) => sum + day.segmentsServed, 0);
return ((secondWeek - firstWeek) / firstWeek) * 100;};Performance Monitoring & Alerting
// Monitor video performance trends with alertingconst monitorVideoPerformance = async (videoId, orgId) => { const response = await fetch(`/v1/api/${orgId}/videos/${videoId}/analytics/resolution`); const analytics = await response.json();
const performance = { videoId: videoId, totalViews: calculateVideoViews(analytics.body.summary), mostPopularResolution: analytics.body.summary.mostPopularResolution, activeDays: analytics.body.summary.totalDaysServed, resolutionBreakdown: analytics.body.resolutions.map(r => ({ resolution: r.resolutionHeight, segments: r.timesServed, percentage: (r.timesServed / analytics.body.summary.totalSegmentsServed) * 100, avgSegmentsPerDay: r.timesServed / r.daysServed })), health: { engagement: analytics.body.summary.totalDaysServed > 30 ? 'high' : 'low', qualityDistribution: analyzeQualityDistribution(analytics.body.resolutions), recommendations: generateVideoRecommendations(analytics.body) } };
// Check for performance alerts if (performance.totalViews < 100 && performance.activeDays > 7) { console.warn(`Low engagement alert for video ${videoId}: ${performance.totalViews} views over ${performance.activeDays} days`); }
return performance;};
// Analyze quality distribution healthconst analyzeQualityDistribution = (resolutions) => { const totalSegments = resolutions.reduce((sum, r) => sum + r.timesServed, 0); const hdSegments = resolutions.filter(r => r.resolutionHeight >= 1080).reduce((sum, r) => sum + r.timesServed, 0); const hdPercentage = (hdSegments / totalSegments) * 100;
return { hdPercentage: hdPercentage, status: hdPercentage > 60 ? 'high-quality-focused' : hdPercentage > 30 ? 'balanced' : 'mobile-focused', recommendation: hdPercentage > 80 ? 'Consider optimizing for mobile' : 'Good quality distribution' };};Cost Optimization Analysis
// Comprehensive cost optimization analysisconst analyzeStorageCosts = async (orgId) => { const endDate = new Date().toISOString().split('T')[0]; const startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
const [storage, resolutionDistribution, dailyUsage] = await Promise.all([ fetch(`/v1/api/${orgId}/analytics/storage`), fetch(`/v1/api/${orgId}/analytics/resolution-distribution`), fetch(`/v1/api/${orgId}/analytics/daily?startDate=${startDate}&endDate=${endDate}`) ]);
const storageData = storage.body.storage; const totalHours = storageData.totalDurationSeconds / 3600; const avgVideoLength = storageData.avgVideoDuration / 60;
// Calculate estimated costs (example rates) const storageCostPerHour = 0.01; // $0.01 per hour per month const deliveryCostPerSegment = 0.0001; // $0.0001 per segment
const totalDeliverySegments = dailyUsage.body.dailyUsage.reduce((sum, day) => sum + day.segmentsServed, 0);
const analysis = { storage: { totalHours: totalHours, monthlyStorageCost: totalHours * storageCostPerHour, avgVideoLength: avgVideoLength, qualityBreakdown: { ultra: { hours: storageData.ultraQualityDuration / 3600, cost: (storageData.ultraQualityDuration / 3600) * storageCostPerHour, percentage: (storageData.ultraQualityDuration / storageData.totalDurationSeconds) * 100 }, high: { hours: storageData.highQualityDuration / 3600, cost: (storageData.highQualityDuration / 3600) * storageCostPerHour, percentage: (storageData.highQualityDuration / storageData.totalDurationSeconds) * 100 }, standard: { hours: storageData.standardQualityDuration / 3600, cost: (storageData.standardQualityDuration / 3600) * storageCostPerHour, percentage: (storageData.standardQualityDuration / storageData.totalDurationSeconds) * 100 } } }, delivery: { totalSegments: totalDeliverySegments, monthlyDeliveryCost: totalDeliverySegments * deliveryCostPerSegment, avgSegmentsPerDay: totalDeliverySegments / 30 }, optimization: { recommendations: generateOptimizationRecommendations(storageData, resolutionDistribution.body.distribution), potentialSavings: calculatePotentialSavings(storageData, resolutionDistribution.body.distribution) } };
return analysis;};
// Generate optimization recommendationsconst generateOptimizationRecommendations = (storageData, resolutionDistribution) => { const recommendations = [];
const ultraRatio = storageData.ultraQualityDuration / storageData.totalDurationSeconds; if (ultraRatio > 0.5) { recommendations.push({ type: 'storage', priority: 'high', message: 'High ultra-quality usage detected. Consider reducing ultra quality for non-premium content.', potentialSavings: `${Math.round(ultraRatio * 100)}% of storage costs` }); }
const avgLength = storageData.avgVideoDuration; if (avgLength > 600) { // 10 minutes recommendations.push({ type: 'content', priority: 'medium', message: 'Long average video length. Consider creating shorter, more focused content.', potentialSavings: 'Reduced storage and processing costs' }); }
return recommendations;};Business Intelligence & Reporting
// Generate comprehensive business intelligence reportconst generateBusinessIntelligenceReport = async (orgId, periodDays = 90) => { const endDate = new Date().toISOString().split('T')[0]; const startDate = new Date(Date.now() - periodDays * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
const [accountUsage, dailyUsage, storageUsage, resolutionDistribution] = await Promise.all([ fetch(`/v1/api/${orgId}/analytics/usage?periodDays=${periodDays}`), fetch(`/v1/api/${orgId}/analytics/daily?startDate=${startDate}&endDate=${endDate}`), fetch(`/v1/api/${orgId}/analytics/storage`), fetch(`/v1/api/${orgId}/analytics/resolution-distribution?startDate=${startDate}&endDate=${endDate}`) ]);
const report = { executiveSummary: { period: `${startDate} to ${endDate}`, totalVideos: accountUsage.body.usage[0].totalVideos, totalViews: calculateTotalViews(dailyUsage.body.dailyUsage), growthRate: calculateGrowthRate(dailyUsage.body.dailyUsage), avgEngagement: calculateAverageEngagement(dailyUsage.body.dailyUsage) }, contentPerformance: { topPerformingDays: findTopPerformingDays(dailyUsage.body.dailyUsage, 5), qualityPreferences: analyzeQualityPreferences(resolutionDistribution.body.distribution), contentStrategy: generateContentStrategyRecommendations(storageUsage.body.storage, dailyUsage.body.dailyUsage) }, technicalInsights: { deviceAnalysis: analyzeDeviceCapabilities(resolutionDistribution.body.distribution), bandwidthOptimization: analyzeBandwidthUsage(dailyUsage.body.dailyUsage), storageEfficiency: analyzeStorageEfficiency(storageUsage.body.storage) }, recommendations: { shortTerm: generateShortTermRecommendations(dailyUsage.body.dailyUsage), longTerm: generateLongTermRecommendations(accountUsage.body.usage[0], storageUsage.body.storage) } };
return report;};
// Calculate total estimated viewsconst calculateTotalViews = (dailyData) => { const totalSegments = dailyData.reduce((sum, day) => sum + day.segmentsServed, 0); const avgSegmentsPerView = 50; // Estimated based on average video length return Math.round(totalSegments / avgSegmentsPerView);};
// Find top performing daysconst findTopPerformingDays = (dailyData, count = 5) => { return dailyData .sort((a, b) => b.segmentsServed - a.segmentsServed) .slice(0, count) .map(day => ({ date: day.deliveryDate, segments: day.segmentsServed, videos: day.uniqueVideosServed, qualityBreakdown: { hd: day.hdSegments, sd: day.sdSegments, ld: day.ldSegments } }));};Best Practices
Data Collection Strategy
Start with Overview: Begin with account usage analytics to understand your baseline metrics
Monitor Trends: Use daily usage analytics to identify patterns and anomalies
Optimize Storage: Regularly review storage analytics to control costs
Analyze Performance: Use video resolution analytics to optimize individual content
Plan Strategy: Use resolution distribution to inform encoding and content decisions
Performance Optimization
Caching Strategy
// Implement intelligent caching for analytics dataclass AnalyticsCache { constructor() { this.cache = new Map(); this.cacheExpiry = { accountUsage: 5 * 60 * 1000, // 5 minutes dailyUsage: 15 * 60 * 1000, // 15 minutes storageUsage: 30 * 60 * 1000, // 30 minutes videoResolution: 10 * 60 * 1000, // 10 minutes resolutionDistribution: 20 * 60 * 1000 // 20 minutes }; }
async getCachedData(endpoint, params) { const key = `${endpoint}_${JSON.stringify(params)}`; const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.cacheExpiry[endpoint]) { return cached.data; }
return null; }
setCachedData(endpoint, params, data) { const key = `${endpoint}_${JSON.stringify(params)}`; this.cache.set(key, { data: data, timestamp: Date.now() }); }}Batch Processing
// Batch multiple analytics requests for efficiencyconst batchAnalyticsRequests = async (orgId, requests) => { const results = await Promise.allSettled(requests.map(req => { switch(req.type) { case 'accountUsage': return fetch(`/v1/api/${orgId}/analytics/usage?periodDays=${req.periodDays}`); case 'dailyUsage': return fetch(`/v1/api/${orgId}/analytics/daily?startDate=${req.startDate}&endDate=${req.endDate}`); case 'storageUsage': return fetch(`/v1/api/${orgId}/analytics/storage`); case 'videoResolution': return fetch(`/v1/api/${orgId}/videos/${req.videoId}/analytics/resolution?startDate=${req.startDate}&endDate=${req.endDate}`); case 'resolutionDistribution': return fetch(`/v1/api/${orgId}/analytics/resolution-distribution?startDate=${req.startDate}&endDate=${req.endDate}`); default: throw new Error(`Unknown request type: ${req.type}`); } }));
return results.map((result, index) => ({ request: requests[index], success: result.status === 'fulfilled', data: result.status === 'fulfilled' ? result.value : null, error: result.status === 'rejected' ? result.reason : null }));};Dashboard Implementation
Real-time Updates
// Implement real-time analytics dashboardclass AnalyticsDashboard { constructor(orgId, updateInterval = 300000) { // 5 minutes this.orgId = orgId; this.updateInterval = updateInterval; this.subscribers = []; this.isRunning = false; }
subscribe(callback) { this.subscribers.push(callback); if (!this.isRunning) { this.start(); } }
unsubscribe(callback) { this.subscribers = this.subscribers.filter(sub => sub !== callback); if (this.subscribers.length === 0) { this.stop(); } }
async start() { this.isRunning = true; this.updateLoop(); }
stop() { this.isRunning = false; if (this.updateTimer) { clearTimeout(this.updateTimer); } }
async updateLoop() { if (!this.isRunning) return;
try { const data = await this.fetchDashboardData(); this.subscribers.forEach(callback => callback(data)); } catch (error) { console.error('Dashboard update failed:', error); }
this.updateTimer = setTimeout(() => this.updateLoop(), this.updateInterval); }
async fetchDashboardData() { const endDate = new Date().toISOString().split('T')[0]; const startDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
const [accountUsage, dailyUsage, storageUsage] = await Promise.all([ fetch(`/v1/api/${this.orgId}/analytics/usage?periodDays=7`), fetch(`/v1/api/${this.orgId}/analytics/daily?startDate=${startDate}&endDate=${endDate}`), fetch(`/v1/api/${this.orgId}/analytics/storage`) ]);
return { timestamp: new Date().toISOString(), accountUsage: accountUsage.body.usage[0], dailyUsage: dailyUsage.body.dailyUsage, storageUsage: storageUsage.body.storage }; }}Error Handling & Resilience
Retry Logic
// Implement retry logic for analytics requestsconst fetchWithRetry = async (fetchFn, maxRetries = 3, delay = 1000) => { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { return await fetchFn(); } catch (error) { if (attempt === maxRetries) { throw error; }
// Exponential backoff const waitTime = delay * Math.pow(2, attempt - 1); await new Promise(resolve => setTimeout(resolve, waitTime)); } }};
// Usage exampleconst getAccountUsageWithRetry = (orgId, periodDays) => { return fetchWithRetry(() => fetch(`/v1/api/${orgId}/analytics/usage?periodDays=${periodDays}`));};Error Monitoring
// Monitor analytics API healthclass AnalyticsHealthMonitor { constructor(orgId) { this.orgId = orgId; this.healthStatus = 'unknown'; this.lastCheck = null; this.errorCount = 0; }
async checkHealth() { try { const startTime = Date.now(); await fetch(`/v1/api/${this.orgId}/analytics/usage?periodDays=1`); const responseTime = Date.now() - startTime;
this.healthStatus = 'healthy'; this.errorCount = 0; this.lastCheck = new Date();
return { status: 'healthy', responseTime: responseTime, lastCheck: this.lastCheck }; } catch (error) { this.errorCount++; this.healthStatus = this.errorCount > 3 ? 'unhealthy' : 'degraded';
return { status: this.healthStatus, error: error.message, errorCount: this.errorCount, lastCheck: this.lastCheck }; } }}Error Handling
Common Errors
| Status Code | Error | Description | Solution |
|---|---|---|---|
| 400 | Bad Request | Invalid date format | Use YYYY-MM-DD format for dates |
| 401 | Unauthorized | Invalid API key | Verify API key is correct and active |
| 403 | Forbidden | Video doesn’t belong to organization | Ensure video belongs to your organization |
| 404 | Not Found | Video not found | Verify video public ID is correct |
| 422 | Unprocessable Entity | Invalid date range | Ensure start date is before end date |
| 429 | Too Many Requests | Rate limit exceeded | Wait before making more requests |
Error Response Example
{ "title": "Bad Request", "status": 400, "detail": "Invalid date format", "errors": [ { "message": "Invalid start date format, use YYYY-MM-DD", "location": "query.startDate", "value": "2024/01/01" } ]}Rate Limits
| Operation | Limit | Window |
|---|---|---|
| Analytics queries | 100 requests | 1 hour |
| Account usage | 50 requests | 1 hour |
| Daily usage | 100 requests | 1 hour |
| Storage analytics | 50 requests | 1 hour |
| Video resolution | 200 requests | 1 hour |
| Resolution distribution | 100 requests | 1 hour |
Tip
Analytics data is updated in real-time. Use appropriate date ranges to avoid large response payloads and consider caching results for dashboard applications.
Caution
Large date ranges may result in significant response sizes. Consider pagination or shorter time periods for better performance.
Integration Examples
React Dashboard Component
import React, { useState, useEffect } from 'react';
const AnalyticsDashboard = ({ orgId }) => { const [analytics, setAnalytics] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null);
useEffect(() => { const fetchAnalytics = async () => { try { setLoading(true); const data = await buildAnalyticsDashboard(orgId, 30); setAnalytics(data); } catch (err) { setError(err.message); } finally { setLoading(false); } };
fetchAnalytics();
// Refresh every 5 minutes const interval = setInterval(fetchAnalytics, 5 * 60 * 1000); return () => clearInterval(interval); }, [orgId]);
if (loading) return <div>Loading analytics...</div>; if (error) return <div>Error: {error}</div>; if (!analytics) return <div>No data available</div>;
return ( <div className="analytics-dashboard"> <h2>Analytics Overview</h2> <div className="metrics-grid"> <div className="metric-card"> <h3>Total Videos</h3> <p>{analytics.overview.totalVideos}</p> </div> <div className="metric-card"> <h3>Total Views</h3> <p>{analytics.overview.totalSegments}</p> </div> <div className="metric-card"> <h3>Daily Average</h3> <p>{Math.round(analytics.trends.dailyAverage)}</p> </div> <div className="metric-card"> <h3>Growth Rate</h3> <p>{analytics.trends.growthRate.toFixed(1)}%</p> </div> </div>
<div className="resolution-breakdown"> <h3>Resolution Distribution</h3> {analytics.resolutionBreakdown.map(res => ( <div key={res.resolution} className="resolution-bar"> <span>{res.resolution}p</span> <div className="bar" style={{ width: `${res.percentage}%` }}> {res.percentage.toFixed(1)}% </div> </div> ))} </div> </div> );};Python Analytics Script
import requestsimport pandas as pdfrom datetime import datetime, timedeltaimport matplotlib.pyplot as plt
class HesedVidAnalytics: def __init__(self, api_key, org_id): self.api_key = api_key self.org_id = org_id self.base_url = "https://api.hesedvid.com/v1/api" self.headers = {"X-Api-Key": api_key}
def get_daily_usage(self, start_date, end_date): url = f"{self.base_url}/{self.org_id}/analytics/daily" params = {"startDate": start_date, "endDate": end_date}
response = requests.get(url, headers=self.headers, params=params) response.raise_for_status() return response.json()["body"]["dailyUsage"]
def analyze_trends(self, days=30): end_date = datetime.now().strftime("%Y-%m-%d") start_date = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
daily_data = self.get_daily_usage(start_date, end_date) df = pd.DataFrame(daily_data)
# Convert delivery date to datetime df['deliveryDate'] = pd.to_datetime(df['deliveryDate'])
# Calculate trends trends = { 'total_segments': df['segmentsServed'].sum(), 'avg_daily_segments': df['segmentsServed'].mean(), 'peak_day': df.loc[df['segmentsServed'].idxmax()]['deliveryDate'], 'peak_segments': df['segmentsServed'].max(), 'quality_distribution': { 'hd': df['hdSegments'].sum(), 'sd': df['sdSegments'].sum(), 'ld': df['ldSegments'].sum() } }
return trends, df
def plot_usage_trends(self, df): plt.figure(figsize=(12, 6)) plt.plot(df['deliveryDate'], df['segmentsServed'], marker='o') plt.title('Daily Video Usage Trends') plt.xlabel('Date') plt.ylabel('Segments Served') plt.xticks(rotation=45) plt.tight_layout() plt.show()
def generate_report(self, days=30): trends, df = self.analyze_trends(days)
print(f"HesedVid Analytics Report - Last {days} days") print("=" * 50) print(f"Total Segments Served: {trends['total_segments']:,}") print(f"Average Daily Segments: {trends['avg_daily_segments']:,.0f}") print(f"Peak Day: {trends['peak_day'].strftime('%Y-%m-%d')}") print(f"Peak Segments: {trends['peak_segments']:,}") print("\nQuality Distribution:") total_quality = sum(trends['quality_distribution'].values()) for quality, segments in trends['quality_distribution'].items(): percentage = (segments / total_quality) * 100 print(f" {quality.upper()}: {segments:,} ({percentage:.1f}%)")
return trends, df
# Usage exampleanalytics = HesedVidAnalytics("your_api_key", "your_org_id")trends, df = analytics.generate_report(30)analytics.plot_usage_trends(df)