Documentation Index
Fetch the complete documentation index at: https://docs.streamforge.com/llms.txt
Use this file to discover all available pages before exploring further.
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 |
| Instagram | post, 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'
);
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.