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:
| Platform | Content Types |
|---|
| Twitch | stream, video |
| YouTube | video, short |
| TikTok | video, 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'
);
Analyze Trends Over Time
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
}));
}
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
}));
}
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.