Skip to main content

Why Track Hourly Instead of Daily?

Most analytics tools update daily. ContentStats.io provides hourly snapshots, giving you 24× more data points and critical advantages.

Benefits of Hourly Tracking

Catch Viral Moments

Detect when content goes viral within hours, not days

Granular Growth Data

See exactly when and how your content gains traction

Optimize Posting Times

Discover the exact hours when your audience is most active

Daily vs Hourly Tracking Comparison

MetricDaily TrackingHourly Tracking
Data Points7 per week168 per week
Viral Detection24+ hours delayReal-time
Cost OptimizationCan’t stop earlyStop when needed
Algorithm InsightsLimitedDetailed

Real-World Examples

Example 1: Catching Viral Moments

Daily Tracking:
Day 1: 10,000 views
Day 2: 500,000 views ← Went viral sometime yesterday
Day 3: 750,000 views
Result: You don’t know when it went viral or why. Hourly Tracking:
Hour 1: 10,000 views
Hour 2: 12,000 views
Hour 3: 15,000 views
...
Hour 16: 45,000 views
Hour 17: 250,000 views ← Viral moment detected!
Hour 18: 400,000 views
Result: You know it went viral at 5 PM. Check what happened at that exact time!

Use Cases Perfect for Hourly Tracking

1. Product Launches

Track minute-by-minute performance:
async function trackProductLaunch(launchVideos) {
  // Start tracking all launch videos
  const tracked = await Promise.all(
    launchVideos.map(url => trackVideo(url, 7))
  );
  
  // Check every hour for viral potential
  const checkInterval = setInterval(async () => {
    for (const video of tracked) {
      const data = await getVideo(video.id);
      const latest = data.snapshots[data.snapshots.length - 1];
      const hourAgo = data.snapshots[data.snapshots.length - 2];
      
      const hourlyGrowth = parseInt(latest.views) - parseInt(hourAgo.views);
      
      if (hourlyGrowth > 10000) { // Viral threshold
        console.log('🔥 VIRAL ALERT:', data.video_link);
        console.log('Hourly growth:', hourlyGrowth, 'views');
        
        // Boost paid promotion
        await boostPromotion(data.video_link);
      }
    }
  }, 60 * 60 * 1000); // Check hourly
}

2. Influencer Campaign Monitoring

Verify influencers deliver results in real-time:
async function monitorInfluencerPost(videoId, expectedHourlyViews) {
  const video = await getVideo(videoId);
  const snapshots = video.snapshots;
  
  if (snapshots.length < 2) return;
  
  const latest = snapshots[snapshots.length - 1];
  const hourAgo = snapshots[snapshots.length - 2];
  
  const actualGrowth = parseInt(latest.views) - parseInt(hourAgo.views);
  
  if (actualGrowth < expectedHourlyViews * 0.5) {
    // Underperforming - alert immediately
    await sendAlert({
      type: 'underperforming',
      influencer: video.current_metadata.creator,
      expected: expectedHourlyViews,
      actual: actualGrowth,
      hoursPassed: snapshots.length
    });
  }
}

3. Algorithm Testing

Test how platform algorithms respond to your content:
function analyzeAlgorithmBoost(snapshots) {
  const boostPatterns = [];
  
  for (let i = 1; i < snapshots.length; i++) {
    const current = parseInt(snapshots[i].views);
    const previous = parseInt(snapshots[i - 1].views);
    const growth = current - previous;
    
    // Calculate average growth excluding current hour
    const avgGrowth = snapshots
      .slice(0, i)
      .reduce((sum, s, idx, arr) => {
        if (idx === 0) return sum;
        return sum + (parseInt(arr[idx].views) - parseInt(arr[idx - 1].views));
      }, 0) / (i - 1);
    
    // Detect algorithm boost (2x average growth)
    if (growth > avgGrowth * 2) {
      boostPatterns.push({
        hour: i,
        time: snapshots[i].snapshot_time,
        growth: growth,
        multiplier: (growth / avgGrowth).toFixed(1) + 'x'
      });
    }
  }
  
  return boostPatterns;
}

// Example output:
// [
//   { hour: 12, time: '2024-01-29T12:00:00Z', growth: 15000, multiplier: '2.5x' },
//   { hour: 18, time: '2024-01-29T18:00:00Z', growth: 12000, multiplier: '2.0x' }
// ]
// Insight: Algorithm boost at 12 PM and 6 PM

4. Competitive Response

React to competitor activity immediately:
async function monitorCompetitorLaunch(competitorVideos) {
  const trackedCompetitors = await Promise.all(
    competitorVideos.map(url => trackVideo(url, 3))
  );
  
  // Check every hour
  setInterval(async () => {
    for (const comp of trackedCompetitors) {
      const data = await getVideo(comp.id);
      
      if (data.snapshots.length >= 2) {
        const latest = data.snapshots[data.snapshots.length - 1];
        const previous = data.snapshots[data.snapshots.length - 2];
        
        const growth = parseInt(latest.views) - parseInt(previous.views);
        
        if (growth > 50000) { // High performing
          // Competitor content performing well - analyze and respond
          await analyzeCompetitorStrategy(data);
          await createResponseContent(data.current_metadata);
        }
      }
    }
  }, 60 * 60 * 1000);
}

Insights Only Possible with Hourly Data

1. Peak Engagement Hours

function findPeakHours(snapshots) {
  const hourlyEngagement = snapshots.map((snapshot, i) => {
    if (i === 0) return null;
    
    const previous = snapshots[i - 1];
    const hour = new Date(snapshot.snapshot_time).getHours();
    
    return {
      hour: hour,
      engagementGrowth: (
        (parseInt(snapshot.likes) - parseInt(previous.likes)) +
        (parseInt(snapshot.comments) - parseInt(previous.comments))
      )
    };
  }).filter(Boolean);
  
  // Group by hour of day
  const hourlyAvg = {};
  hourlyEngagement.forEach(entry => {
    if (!hourlyAvg[entry.hour]) {
      hourlyAvg[entry.hour] = [];
    }
    hourlyAvg[entry.hour].push(entry.engagementGrowth);
  });
  
  // Calculate averages
  const avgByHour = Object.keys(hourlyAvg).map(hour => ({
    hour: parseInt(hour),
    avgEngagement: hourlyAvg[hour].reduce((a, b) => a + b) / hourlyAvg[hour].length
  })).sort((a, b) => b.avgEngagement - a.avgEngagement);
  
  return avgByHour.slice(0, 3); // Top 3 hours
}

// Example output:
// [
//   { hour: 18, avgEngagement: 1250 }, // 6 PM best
//   { hour: 12, avgEngagement: 980 },  // 12 PM second
//   { hour: 21, avgEngagement: 870 }   // 9 PM third
// ]

2. Content Half-Life

How long does content stay relevant?
function calculateContentHalfLife(snapshots) {
  const peakSnapshot = snapshots.reduce((max, s) => {
    const maxGrowth = max.growth || 0;
    const currentGrowth = parseInt(s.views);
    return currentGrowth > maxGrowth ? { ...s, growth: currentGrowth } : max;
  }, {});
  
  const peakIndex = snapshots.indexOf(peakSnapshot);
  const peakViews = parseInt(peakSnapshot.views);
  
  // Find when views drop to 50% of peak growth rate
  for (let i = peakIndex + 1; i < snapshots.length; i++) {
    const current = snapshots[i];
    const previous = snapshots[i - 1];
    
    const currentGrowth = parseInt(current.views) - parseInt(previous.views);
    const peakGrowth = peakViews - (peakIndex > 0 ? parseInt(snapshots[peakIndex - 1].views) : 0);
    
    if (currentGrowth < peakGrowth * 0.5) {
      return {
        peakHour: peakIndex,
        halfLifeHours: i - peakIndex,
        message: `Content peaked at hour ${peakIndex}, half-life reached after ${i - peakIndex} hours`
      };
    }
  }
  
  return { message: 'Content still growing' };
}

3. Viral Velocity Score

Measure how fast content goes viral:
function calculateViralVelocity(snapshots) {
  const velocities = [];
  
  for (let i = 1; i < Math.min(snapshots.length, 25); i++) { // First 24 hours
    const current = parseInt(snapshots[i].views);
    const initial = parseInt(snapshots[0].views);
    
    const totalGrowth = current - initial;
    const velocityScore = totalGrowth / i; // Views per hour
    
    velocities.push(velocityScore);
  }
  
  const avgVelocity = velocities.reduce((a, b) => a + b) / velocities.length;
  
  // Classify viral potential
  let classification;
  if (avgVelocity > 10000) classification = '🔥 VIRAL';
  else if (avgVelocity > 5000) classification = '📈 HIGH POTENTIAL';
  else if (avgVelocity > 1000) classification = '✅ GOOD';
  else classification = '📊 NORMAL';
  
  return {
    avgVelocity: Math.round(avgVelocity),
    classification,
    viewsPerHour: Math.round(avgVelocity)
  };
}

Cost Efficiency

Hourly tracking lets you stop early when you have enough data:
async function trackUntilConfident(videoUrl, maxDays = 7) {
  const tracking = await trackVideo(videoUrl, maxDays);
  
  // Check every hour
  const checkInterval = setInterval(async () => {
    const video = await getVideo(tracking.id);
    
    // Stop if we have 48 hours of data and clear pattern
    if (video.snapshots.length >= 48) {
      const velocity = calculateViralVelocity(video.snapshots);
      
      // Clear conclusion reached
      if (velocity.classification === '🔥 VIRAL' || 
          velocity.classification === '📊 NORMAL') {
        
        await stopVideo(tracking.id);
        clearInterval(checkInterval);
        
        console.log('Stopped early - conclusion:', velocity.classification);
        console.log('Saved:', maxDays - 2, 'days of tracking costs');
      }
    }
  }, 60 * 60 * 1000);
}

Best Practices

Data updates hourly, so don’t poll more frequently:
// ✅ Good: Check hourly
setInterval(checkVideo, 60 * 60 * 1000);

// ❌ Bad: Wastes API calls
setInterval(checkVideo, 5 * 60 * 1000);
Build your own database of performance patterns:
async function archiveSnapshots(videoId) {
  const video = await getVideo(videoId);
  
  await db.snapshots.insertMany(
    video.snapshots.map(s => ({
      ...s,
      videoId: video.id,
      platform: video.platform,
      archivedAt: new Date()
    }))
  );
}

Next Steps

Real-Time Analytics

Build real-time dashboards

Automate Analytics

Set up automated tracking

Track Videos

Start tracking hourly

Quickstart

Get started now