Skip to main content
Learn how to fetch, filter, and analyze content (streams, videos, and posts) from creators and platforms.

Content Endpoints

The API provides several ways to access content:
  • GET /platforms/{platform}/content/{content_id} - Get single content item
  • GET /platforms/{platform}/content - List all content for a platform
  • GET /platforms/{platform}/profiles/{profile_id}/content - List content by creator
  • GET /platforms/{platform}/games/{game_id}/content - List content for a game
  • POST /platforms/{platform}/content - Get multiple content items

Content Types

Content types vary by platform:
PlatformContent Types
Twitchstream, video
YouTubevideo, short
TikTokvideo, short

Getting Content by Creator

Fetch all content from a specific creator:
async function getCreatorContent(platform, profileId) {
  let cursor = null;
  const allContent = [];

  do {
    const response = await fetch(
      `/platforms/${platform}/profiles/${profileId}/content?limit=50${cursor ? `&cursor=${cursor}` : ''}`,
      {
        headers: { 'x-api-key': 'YOUR_API_KEY' }
      }
    );

    const data = await response.json();
    allContent.push(...data.payload);
    cursor = data.meta.paging.next_cursor;
  } while (cursor !== null);

  return allContent;
}

Content statistics

Content items include detailed statistics:
{
  "id": "987654321",
  "title": "Awesome Stream",
  "type": "stream",
  "created_at": "2024-07-04T10:00:00.000Z",
  "ended_at": "2024-07-04T11:30:00.000Z",
  "duration": 5400000,
  "statistics": {
    "viewers": {
      "avg": 2345.6,
      "max": 6789
    },
    "watched_minutes": {
      "sum": 123456
    },
    "views": {
      "sum": 45678
    },
    "comments": {
      "sum": 900
    }
  }
}

Understanding Statistics

  • statistics.views.sum: Total view count
  • statistics.viewers.avg: Average concurrent viewers (for streams)
  • statistics.viewers.max: Peak concurrent viewers
  • statistics.watched_minutes.sum: Total watch time in minutes
  • duration: Content duration in milliseconds

Analyzing Content Performance

Calculate Average Views

function calculateAverageViews(content) {
  const views = content
    .map(item => item.statistics?.views?.sum || 0)
    .filter(views => views > 0);

  if (views.length === 0) return 0;

  const sum = views.reduce((a, b) => a + b, 0);
  return sum / views.length;
}

Find Top Performing Content

function getTopContent(content, metric = 'views', limit = 10) {
  return content
    .sort((a, b) => {
      // Handle nested statistics like views.sum
      const aValue = metric === 'views'
        ? (a.statistics?.views?.sum || 0)
        : (a.statistics?.[metric]?.sum || a.statistics?.[metric] || 0);
      const bValue = metric === 'views'
        ? (b.statistics?.views?.sum || 0)
        : (b.statistics?.[metric]?.sum || b.statistics?.[metric] || 0);
      return bValue - aValue;
    })
    .slice(0, limit);
}

// Usage
const topVideos = getTopContent(content, 'views', 5);

Calculate Engagement Rate

function calculateEngagementRate(content) {
  return content.map(item => {
    const views = item.statistics?.views?.sum || 0;
    const comments = item.statistics?.comments?.sum || 0;
    const engagementRate = views > 0 ? (comments / views) * 100 : 0;

    return {
      ...item,
      engagementRate: engagementRate.toFixed(2)
    };
  });
}

Time-Based Analysis

Filter by Date Range

function filterByDateRange(content, startDate, endDate) {
  const start = new Date(startDate);
  const end = new Date(endDate);

  return content.filter(item => {
    const createdAt = new Date(item.created_at);
    return createdAt >= start && createdAt <= end;
  });
}

// Usage
const recentContent = filterByDateRange(
  content,
  '2024-01-01',
  '2024-12-31'
);
function analyzeTrends(content) {
  // Group by month
  const byMonth = content.reduce((acc, item) => {
    const date = new Date(item.created_at);
    const month = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;

    if (!acc[month]) {
      acc[month] = { count: 0, totalViews: 0 };
    }

    acc[month].count++;
    acc[month].totalViews += item.statistics?.views?.sum || 0;

    return acc;
  }, {});

  return Object.entries(byMonth).map(([month, stats]) => ({
    month,
    contentCount: stats.count,
    totalViews: stats.totalViews,
    averageViews: stats.totalViews / stats.count
  }));
}

Platform-Specific Features

Twitch Chapters

Twitch streams include aggregated chapter data:
{
  "chapters": [
    {
      "id": "chapter-1",
      "title": "Opening",
      "created_at": "2024-07-04T10:00:00.000Z",
      "ended_at": "2024-07-04T10:30:00.000Z",
      "duration": 1800000,
      "statistics": {
        "viewers": {
          "avg": 2000,
          "max": 4000
        }
      }
    }
  ]
}
Analyze chapter performance:
function analyzeChapters(stream) {
  if (!stream.chapters || stream.chapters.length === 0) {
    return null;
  }

  return stream.chapters.map(chapter => ({
    title: chapter.title,
    duration: chapter.duration / 1000 / 60, // minutes
    avgViewers: chapter.statistics?.viewers?.avg || 0,
    peakViewers: chapter.statistics?.viewers?.max || 0
  }));
}

Categories and Tags

Content includes categories (games) and tags:
{
  "categories": [
    {
      "id": "1234",
      "name": "Some Game",
      "type": "twitch_game",
      "igdb_id": 5678,
      "igdb_name": "Some Game",
      "igdb_slug": "some-game"
    }
  ],
  "tags": ["gaming", "live"]
}
Find most common games:
function findMostCommonGames(content) {
  const gameCounts = {};

  content.forEach(item => {
    item.categories?.forEach(category => {
      if (category.type.includes('game')) {
        const gameName = category.igdb_name || category.name;
        gameCounts[gameName] = (gameCounts[gameName] || 0) + 1;
      }
    });
  });

  return Object.entries(gameCounts)
    .sort(([, a], [, b]) => b - a)
    .map(([game, count]) => ({ game, count }));
}

Content Comparison

Compare Creators

async function compareCreators(platform, profileIds) {
  const results = await Promise.all(
    profileIds.map(id =>
      fetch(`/platforms/${platform}/profiles/${id}/content?limit=10`)
        .then(r => r.json())
    )
  );

  return results.map((data, index) => ({
    profileId: profileIds[index],
    contentCount: data.payload.length,
    totalViews: data.payload.reduce(
      (sum, item) => sum + (item.statistics?.views?.sum || 0),
      0
    ),
    averageViews: calculateAverageViews(data.payload)
  }));
}

Compare Time Periods

function comparePeriods(content, period1, period2) {
  const p1 = filterByDateRange(content, period1.start, period1.end);
  const p2 = filterByDateRange(content, period2.start, period2.end);

  return {
    period1: {
      count: p1.length,
      totalViews: p1.reduce((sum, item) => sum + (item.statistics?.views?.sum || 0), 0),
      avgViews: calculateAverageViews(p1)
    },
    period2: {
      count: p2.length,
      totalViews: p2.reduce((sum, item) => sum + (item.statistics?.views?.sum || 0), 0),
      avgViews: calculateAverageViews(p2)
    },
    change: {
      count: ((p2.length - p1.length) / p1.length * 100).toFixed(1),
      views: ((p2.reduce((sum, item) => sum + (item.statistics?.views?.sum || 0), 0) -
               p1.reduce((sum, item) => sum + (item.statistics?.views?.sum || 0), 0)) /
              p1.reduce((sum, item) => sum + (item.statistics?.views?.sum || 0), 0) * 100).toFixed(1)
    }
  };
}

Best Practices

Use bulk endpoints when fetching multiple content items. It’s more efficient than individual requests.
  • Paginate efficiently: Use appropriate limit values (10-50) based on your needs
  • Cache content data: Content metrics don’t change frequently; cache for performance
  • Filter client-side: Use date ranges and filters to reduce unnecessary requests
  • Handle missing metrics: Some content may not have all metrics; handle nulls gracefully
  • Monitor quota: List endpoints consume quota per item returned

Use Cases

Content Performance Dashboard

async function buildContentDashboard(platform, profileId) {
  const content = await getCreatorContent(platform, profileId);

  return {
    totalContent: content.length,
    totalViews: content.reduce((sum, item) => sum + (item.statistics?.views?.sum || 0), 0),
    averageViews: calculateAverageViews(content),
    topContent: getTopContent(content, 'views', 10),
    trends: analyzeTrends(content),
    commonGames: findMostCommonGames(content)
  };
}

Content Discovery

async function discoverTrendingContent(platform, limit = 20) {
  const response = await fetch(
    `/platforms/${platform}/content?limit=${limit}&sort=views&order=desc`,
    {
      headers: { 'x-api-key': 'YOUR_API_KEY' }
    }
  );

  return response.json();
}
Content list endpoints consume quota equal to the number of items returned. Use appropriate limit values to manage quota usage.