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
Instagrampost, video, story
Instagram stories are only available via direct ID lookup and are excluded from list operations. Story availability is limited and depends on internal data collection processes - do not expect comprehensive story coverage for any given creator.

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.