How Bilistream Detects Twitch Stream Status: GraphQL Implementation Guide

Bilistream determines Twitch stream status by posting a GraphQL StreamMetadata query to https://gql.twitch.tv/gql and verifying that res["data"]["user"]["stream"]["type"] equals "live".

The limitcool/bilistream repository implements Twitch stream status detection through a dedicated plugin architecture that abstracts platform-specific logic behind a common trait. This approach allows the application to treat Twitch, YouTube, and other platforms uniformly while maintaining precise control over each service's unique API requirements.

The Architecture Behind Twitch Stream Status Detection

The detection system relies on the Live trait defined in src/plugins/live.rs, which establishes a standard contract for all streaming platforms. This abstraction enables polymorphic handling of different live-streaming services through a boxed trait object.

The Live Trait Abstraction

In src/plugins/live.rs, the Live trait declares the interface that every platform plugin must implement:

// src/plugins/live.rs
pub trait Live {
    async fn get_status(&self) -> Result<bool, Box<dyn Error>>;
    fn room(&self) -> &str;
}

The select_live function (lines 42‑53) acts as a factory that instantiates the appropriate concrete type based on the configuration's platform field. When cfg.platform == "Twitch", it constructs a Twitch struct instance via Twitch::new, passing the channel name, a reqwest client with retry middleware, and the global configuration.

Twitch Plugin Structure

The Twitch struct in src/plugins/twitch.rs encapsulates all state required for GraphQL communication:

  • room: The target channel login name
  • client: A reqwest HTTP client configured with retry policies
  • config: Global application settings

This structure is instantiated during the platform selection phase and persists throughout the application's lifecycle, allowing efficient reuse of the HTTP connection pool.

GraphQL Query Implementation

Bilistream bypasses Twitch's private REST API in favor of the public GraphQL endpoint, using a persisted query that requires no OAuth tokens.

Endpoint and Authentication Headers

The get_status method constructs a POST request to https://gql.twitch.tv/gql with the following mandatory headers:

  • Client-ID: kimne78kx3ncx6brgo4mv6wki5h1ko (Twitch's public web client ID)
  • Content-Type: application/json

These headers authenticate the request as a standard Twitch web client, allowing access to public stream metadata without user credentials.

The StreamMetadata Operation

The GraphQL payload queries the StreamMetadata operation with a specific SHA256 hash that identifies the persisted query:

// src/plugins/twitch.rs (lines 35‑46)
let j = json!({
    "operationName": "StreamMetadata",
    "variables": {
        "channelLogin": &self.room
    },
    "extensions": {
        "persistedQuery": {
            "version": 1,
            "sha256Hash": "1c719a40e481453e5c48d9bb585d971b8b372f8ebb105b17076722264dfa5b3e"
        }
    }
});

This operation returns stream metadata for the specified channelLogin, including the critical type field that indicates live status.

Parsing the Live Status Response

After receiving the JSON response, bilistream deserializes it into serde_json::Value and inspects a specific nested path to determine status:

// src/plugins/twitch.rs (lines 50‑55)
if let Some(stream_type) = res["data"]["user"]["stream"]["type"].as_str() {
    Ok(stream_type == "live")
} else {
    Ok(false)
}

The logic returns Ok(true) only when the type field equals "live". Any other value—including "archive", "highlight", or null—results in Ok(false), accurately distinguishing between active broadcasts and offline or recorded content.

Complete Usage Example

The following example demonstrates the complete workflow for checking a Twitch channel's status using bilistream's API:

use bilistream::config::load_config;
use bilistream::plugins::select_live;
use std::path::Path;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load configuration containing platform = "Twitch" and room = "channel_name"
    let cfg = load_config(Path::new("config.yaml"))?;
    
    // Factory returns Box<dyn Live> configured for Twitch
    let live = select_live(cfg).await?;
    
    // Execute GraphQL query and parse response
    let is_live = live.get_status().await?;
    println!("Channel '{}' is live: {}", live.room(), is_live);
    
    Ok(())
}

This pattern delegates platform-specific details to the plugin layer while providing a unified interface for the main application logic.

Summary

  • File location: Twitch detection logic resides in src/plugins/twitch.rs, implementing the Live trait from src/plugins/live.rs.
  • API method: Uses Twitch's public GraphQL endpoint at https://gql.twitch.tv/gql with client ID kimne78kx3ncx6brgo4mv6wki5h1ko.
  • Query details: Sends a StreamMetadata persisted query (SHA256: 1c719a40e481453e5c48d9bb585d971b8b372f8ebb105b17076722264dfa5b3e) with the channel login as a variable.
  • Status logic: Returns true only when data.user.stream.type equals "live", ensuring accurate detection of active broadcasts versus offline or recorded states.
  • Integration: The select_live factory in src/plugins/live.rs instantiates the correct plugin based on configuration, enabling seamless multi-platform support.

Frequently Asked Questions

What GraphQL endpoint does bilistream use for Twitch?

Bilistream queries https://gql.twitch.tv/gql, Twitch's public GraphQL API. This endpoint serves the Twitch web interface and requires only a public client ID header, avoiding the need for OAuth tokens or private API keys.

How does bilistream authenticate with Twitch's API?

The plugin sends the public client ID kimne78kx3ncx6brgo4mv6wki5h1ko in the request headers. This identifier matches Twitch's official web application and grants access to public stream metadata without user authentication.

What specific field indicates a live stream in the response?

The code inspects res["data"]["user"]["stream"]["type"]. If this field exists and equals the string "live", the channel is currently broadcasting. Any other value or a missing field indicates the channel is offline or hosting non-live content.

Can bilistream check other platforms besides Twitch?

Yes. The Live trait abstraction in src/plugins/live.rs supports multiple platforms through the select_live factory. When configured for different platforms (such as YouTube), the factory instantiates the appropriate plugin that implements the same get_status interface, allowing bilistream to handle diverse streaming services through uniform code paths.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →