Back to Blog
General

Twitch Scraper API: Extract Profiles, VODs, and Clips Without the Hassle

June 14, 2026
10 min read
S
By SociaVault Team
twitch scrapertwitch apitwitch datastreaming data

Twitch Scraper API: Extract Profiles, VODs, and Clips Without the Hassle

TL;DR: SociaVault provides four Twitch endpoints — profile, user videos (VODs), user schedule, and clip details — each costing 1 credit per request. No OAuth tokens, no app registration, no Twitch Developer Console hoops. Pass a handle, get data. This guide covers all four endpoints with working Python examples.

Two months ago, a developer named Marcus was building an esports talent scouting tool. He started with the official Twitch API. By hour three, he had: one OAuth client-ID, one OAuth secret, a token refresh flow that broke twice, and exactly zero data in his database.

The official Twitch API isn't bad — it's actually well-documented. But the authentication overhead for simple data extraction is absurd when all you need is "give me this streamer's follower count and recent VODs." Marcus needed public profile data, not chat bot permissions or webhook subscriptions.

He switched to SociaVault's Twitch endpoints the next day. His scouting tool was pulling data from 200 streamers by lunch.

The thing is, most Twitch data use cases are read-only. You're pulling profiles, checking VOD history, analyzing clip virality, or monitoring schedules. None of that requires the ability to write to Twitch — so why go through an OAuth flow designed for apps that need write access?

The Four Twitch Endpoints

Here's what's available:

EndpointPathCostUse Case
Profile/v1/scrape/twitch/profile1 creditStreamer stats, bio, game, followers
User Videos/v1/scrape/twitch/user/videos1 creditVODs, highlights, uploads
User Schedule/v1/scrape/twitch/user/schedule1 creditStreaming schedule
Clip/v1/scrape/twitch/clip1 creditIndividual clip details

All endpoints accept a handle parameter (the streamer's Twitch username) except the clip endpoint, which takes a clip URL.

Endpoint 1: Streamer Profiles

The profile endpoint gives you the core stats you'd see on someone's Twitch channel page.

import requests

API_KEY = "your_sociavault_api_key"
BASE_URL = "https://api.sociavault.com/v1/scrape/twitch"
HEADERS = {"X-API-Key": API_KEY}

def get_twitch_profile(handle):
    """Fetch a Twitch streamer's profile data."""
    response = requests.get(
        f"{BASE_URL}/profile",
        params={"handle": handle},
        headers=HEADERS
    )

    if response.status_code != 200:
        print(f"Error: {response.status_code}")
        return None

    data = response.json()
    if data.get("success"):
        return data["data"]
    return None

# Example usage
profile = get_twitch_profile("shroud")

if profile:
    print(f"Display Name: {profile.get('displayName')}")
    print(f"Followers: {profile.get('followers', 0):,}")
    print(f"Bio: {profile.get('bio', 'No bio')}")
    print(f"Last Game: {profile.get('lastBroadcast', {}).get('game', 'Unknown')}")
    print(f"Is Live: {profile.get('stream') is not None}")

What you get back:

  • Display name, username, ID
  • Follower count
  • Bio/description
  • Profile and banner images
  • Current/last game played
  • Stream status (live or offline)
  • Broadcaster type (partner, affiliate, or none)
  • Account creation date
  • Last broadcast info

Common use cases:

  • Building influencer databases with follower counts and categories
  • Checking if a streamer is currently live
  • Verifying partner/affiliate status for sponsorship deals
  • Tracking follower growth over time (with periodic polling)

Endpoint 2: User Videos (VODs & Highlights)

The videos endpoint returns a streamer's video archive — past broadcasts, highlights, and uploads.

def get_twitch_videos(handle, filter_by="ARCHIVE", sort_by="TIME"):
    """Fetch a streamer's video history.

    filter_by: ARCHIVE (past broadcasts), HIGHLIGHT, or UPLOAD
    sort_by: TIME (newest first) or VIEWS (most viewed first)
    """
    response = requests.get(
        f"{BASE_URL}/user/videos",
        params={
            "handle": handle,
            "filter_by": filter_by,
            "sort_by": sort_by,
        },
        headers=HEADERS
    )

    if response.status_code != 200:
        return None

    data = response.json()
    if data.get("success"):
        return data["data"]
    return None

# Get past broadcasts sorted by views
vods = get_twitch_videos("pokimane", filter_by="ARCHIVE", sort_by="VIEWS")

if vods:
    videos = vods.get("videos", [])
    print(f"Found {len(videos)} VODs\n")

    for video in videos[:5]:
        title = video.get("title", "Untitled")[:60]
        views = video.get("viewCount", 0)
        duration = video.get("lengthSeconds", 0)
        hours = duration // 3600
        minutes = (duration % 3600) // 60
        game = video.get("game", {}).get("name", "Unknown")

        print(f"  {title}")
        print(f"    Views: {views:,} | Duration: {hours}h {minutes}m | Game: {game}")
        print()

Filter options:

ValueDescription
ARCHIVEPast broadcasts (auto-saved VODs)
HIGHLIGHTCreator-curated highlights
UPLOADManually uploaded videos

Sort options:

ValueDescription
TIMENewest first (default)
VIEWSMost viewed first

Pagination: The response includes a cursor value. Pass it back as the cursor parameter to get the next page.

def get_all_videos(handle, filter_by="ARCHIVE", max_pages=5):
    """Paginate through all videos for a streamer."""
    all_videos = []
    cursor = None

    for page in range(max_pages):
        params = {
            "handle": handle,
            "filter_by": filter_by,
            "sort_by": "TIME",
        }
        if cursor:
            params["cursor"] = cursor

        response = requests.get(
            f"{BASE_URL}/user/videos",
            params=params,
            headers=HEADERS
        )

        if response.status_code != 200:
            break

        data = response.json()
        if not data.get("success"):
            break

        videos = data.get("data", {}).get("videos", [])
        all_videos.extend(videos)

        cursor = data.get("data", {}).get("cursor")
        if not cursor:
            break

    return all_videos

Endpoint 3: Streamer Schedule

The schedule endpoint returns a streamer's planned broadcast times — useful for knowing when they intend to be live.

def get_twitch_schedule(handle):
    """Fetch a streamer's broadcast schedule."""
    response = requests.get(
        f"{BASE_URL}/user/schedule",
        params={"handle": handle},
        headers=HEADERS
    )

    if response.status_code != 200:
        return None

    data = response.json()
    if data.get("success"):
        return data["data"]
    return None

# Example
schedule = get_twitch_schedule("cohhcarnage")

if schedule:
    segments = schedule.get("segments", [])
    print(f"Schedule has {len(segments)} upcoming segments\n")

    for segment in segments[:7]:
        title = segment.get("title", "Untitled stream")
        start = segment.get("startAt", "TBD")
        end = segment.get("endAt", "TBD")
        category = segment.get("category", {}).get("name", "No category")

        print(f"  {start[:10]} | {title} | {category}")

What you get:

  • Scheduled stream segments with start/end times
  • Stream titles (if set in advance)
  • Categories/games planned
  • Vacation/hiatus indicators
  • Recurring vs. one-time segments

Use cases:

  • Monitoring schedule consistency (do they stream when they say they will?)
  • Planning sponsorship activations around confirmed stream times
  • Competitive intel — know when rivals will be live before they go live

Endpoint 4: Clip Details

The clip endpoint takes a Twitch clip URL and returns full metadata about that clip.

def get_twitch_clip(clip_url):
    """Fetch details about a specific Twitch clip."""
    response = requests.get(
        f"{BASE_URL}/clip",
        params={"url": clip_url},
        headers=HEADERS
    )

    if response.status_code != 200:
        return None

    data = response.json()
    if data.get("success"):
        return data["data"]
    return None

# Example
clip = get_twitch_clip("https://clips.twitch.tv/TastyBrightPigDuDudu-abc123xyz")

if clip:
    print(f"Title: {clip.get('title')}")
    print(f"Streamer: {clip.get('broadcaster', {}).get('displayName')}")
    print(f"Views: {clip.get('viewCount', 0):,}")
    print(f"Duration: {clip.get('durationSeconds', 0)}s")
    print(f"Game: {clip.get('game', {}).get('name')}")
    print(f"Created: {clip.get('createdAt')}")
    print(f"Clipper: {clip.get('curator', {}).get('displayName')}")

What you get:

  • Clip title, duration, view count
  • Broadcaster info (who was streaming)
  • Curator info (who clipped it)
  • Game/category at time of clip
  • Creation timestamp
  • Thumbnail and video URLs

Putting It All Together: Streamer Assessment Script

Here's a combined script that profiles a streamer across all dimensions:

import requests
import json
from datetime import datetime

API_KEY = "your_sociavault_api_key"
BASE_URL = "https://api.sociavault.com/v1/scrape/twitch"
HEADERS = {"X-API-Key": API_KEY}

def assess_streamer(handle):
    """Full streamer assessment using all endpoints."""
    print(f"\n{'='*50}")
    print(f"TWITCH ASSESSMENT: {handle}")
    print(f"{'='*50}\n")

    assessment = {"handle": handle, "timestamp": datetime.now().isoformat()}

    # Profile (1 credit)
    profile_resp = requests.get(
        f"{BASE_URL}/profile",
        params={"handle": handle},
        headers=HEADERS
    )

    if profile_resp.status_code == 200 and profile_resp.json().get("success"):
        profile = profile_resp.json()["data"]
        assessment["profile"] = {
            "display_name": profile.get("displayName"),
            "followers": profile.get("followers", 0),
            "broadcaster_type": profile.get("broadcasterType", "none"),
            "is_live": profile.get("stream") is not None,
            "last_game": profile.get("lastBroadcast", {}).get("game"),
        }
        print(f"Profile: {profile.get('displayName')} | {profile.get('followers', 0):,} followers")
        print(f"  Type: {profile.get('broadcasterType', 'none')} | Live: {profile.get('stream') is not None}")

    # Videos (1 credit)
    videos_resp = requests.get(
        f"{BASE_URL}/user/videos",
        params={"handle": handle, "filter_by": "ARCHIVE", "sort_by": "TIME"},
        headers=HEADERS
    )

    if videos_resp.status_code == 200 and videos_resp.json().get("success"):
        videos = videos_resp.json()["data"].get("videos", [])

        total_views = sum(v.get("viewCount", 0) for v in videos)
        avg_views = total_views // len(videos) if videos else 0
        avg_duration_hrs = sum(
            v.get("lengthSeconds", 0) for v in videos
        ) / max(len(videos), 1) / 3600

        assessment["videos"] = {
            "recent_vod_count": len(videos),
            "avg_views": avg_views,
            "avg_duration_hours": round(avg_duration_hrs, 1),
            "total_views_recent": total_views,
        }
        print(f"\nVODs: {len(videos)} recent | Avg views: {avg_views:,} | Avg duration: {avg_duration_hrs:.1f}h")

    # Schedule (1 credit)
    schedule_resp = requests.get(
        f"{BASE_URL}/user/schedule",
        params={"handle": handle},
        headers=HEADERS
    )

    if schedule_resp.status_code == 200 and schedule_resp.json().get("success"):
        schedule = schedule_resp.json()["data"]
        segments = schedule.get("segments", [])
        assessment["schedule"] = {
            "has_schedule": len(segments) > 0,
            "upcoming_streams": len(segments),
        }
        print(f"\nSchedule: {'Set' if segments else 'Not set'} | {len(segments)} upcoming segments")

    # Total: 3 credits for a full assessment
    print(f"\nTotal credits used: 3")

    return assessment

# Run assessment
result = assess_streamer("shroud")
print(json.dumps(result, indent=2, default=str))

Credit Cost Summary

OperationCreditsWhat You Get
Single profile check1Full streamer stats
VOD history (1 page)1~20 recent videos
Full VOD history (5 pages)5~100 videos
Schedule check1All planned streams
Single clip lookup1Complete clip metadata
Full streamer assessment3Profile + VODs + schedule
Batch assess 50 streamers150Full portfolio overview

Comparison: SociaVault vs. Official Twitch API

FactorOfficial Twitch APISociaVault
AuthenticationOAuth2 (Client ID + Secret + Token)Single API key
Setup time30-60 minutes2 minutes
Rate limits800 requests/minute (with token)No rate limits
Token managementTokens expire, need refresh flowNo tokens
App review requiredFor some endpoints, yesNo
Webhook supportYes (complex setup)No (polling only)
Write accessYes (chat, clips, etc.)No (read-only)

If you need to do things on Twitch (send chat messages, create clips, manage subscriptions), the official API is required. If you need to read data from Twitch, SociaVault removes the ceremony.

Error Handling and Best Practices

def safe_twitch_request(endpoint, params, retries=3):
    """Robust request wrapper with retries."""
    for attempt in range(retries):
        try:
            response = requests.get(
                f"{BASE_URL}/{endpoint}",
                params=params,
                headers=HEADERS,
                timeout=30
            )

            if response.status_code == 200:
                data = response.json()
                if data.get("success"):
                    return data["data"]
                else:
                    print(f"API returned error: {data.get('error')}")
                    return None

            elif response.status_code == 402:
                print("Insufficient credits")
                return None

            elif response.status_code == 429:
                # Rate limited — wait and retry
                import time
                time.sleep(2 ** attempt)
                continue

            else:
                print(f"HTTP {response.status_code} on attempt {attempt + 1}")

        except requests.exceptions.Timeout:
            print(f"Timeout on attempt {attempt + 1}")
        except requests.exceptions.ConnectionError:
            print(f"Connection error on attempt {attempt + 1}")

    return None

Frequently Asked Questions

Does the profile endpoint show if someone is currently live?

Yes. If the streamer is live, the profile response includes a stream object with current viewer count, game, and stream title. If they're offline, stream is null.

Can I get subscriber count (not just followers)?

Twitch subscriber counts are private — they're only visible to the streamer and their moderators. The profile endpoint returns follower count, which is public.

How far back do VODs go?

Twitch auto-deletes VODs after 14 days for non-partners (60 days for partners/Turbo users). The videos endpoint returns whatever is currently available on the channel.

Can I search for Twitch streamers by game or category?

The current endpoints are per-streamer. You need to know the handle. For discovery by category, you'd combine this with other data sources to build your initial streamer list, then use SociaVault for detailed profile data.

What if a streamer changed their username?

Use their current handle. Twitch allows name changes, and the API resolves based on current username. Old handles won't work if they've been changed.

Are there any streamers that can't be looked up?

Banned or suspended accounts may return errors. Private/deleted accounts won't return data. Otherwise, any public Twitch channel is accessible.

Try SociaVault free → — 50 free credits, enough to assess 16 streamers end-to-end. No OAuth tokens, no Twitch Developer Console, just data.


Related reading:

Found this helpful?

Share it with others who might benefit

Ready to Try SociaVault?

Start extracting social media data with our powerful API. No credit card required.