Skip to main content
The Streamer Alerts Bot is designed to be extensible. Follow this guide to add support for new streaming platforms.

Overview

Adding a new platform requires:
  1. Creating a platform checker function
  2. Defining platform configuration
  3. Registering the platform in the platform registry
  4. Adding platform constants (color, emoji, URL template)

Understanding the PlatformChecker Interface

Every platform must implement the PlatformChecker type:
src/platforms/types.ts
export type PlatformChecker = (username: string) => Promise<LiveStatus>;
The LiveStatus interface defines what data your checker should return:
src/types/streamer.ts
export interface LiveStatus {
  /** Whether the streamer is currently live */
  isLive: boolean;
  /** Platform name */
  platform: Platform;
  /** Username checked */
  username: string;
  /** Stream title */
  title?: string;
  /** Current viewer count */
  viewers?: number;
  /** Follower/subscriber count */
  followers?: number;
  /** Stream thumbnail URL */
  thumbnail?: string;
  /** Profile image URL */
  profileImage?: string;
  /** Stream start time (ISO timestamp) */
  startedAt?: string;
  /** Direct URL to the stream */
  url: string;
  /** Verified status */
  verified?: boolean;
  /** Bio/description */
  bio?: string;
  /** Stream category/game */
  category?: string;
  /** Category icon URL */
  categoryIcon?: string;
  /** Stream tags */
  tags?: string[];
  /** Stream language */
  language?: string;
  /** Whether stream is marked as mature */
  isMature?: boolean;
  /** Error message if check failed */
  error?: string;
}

Step-by-Step Implementation

1

Create the platform checker file

Create a new file in src/platforms/ named after your platform (e.g., newplatform.ts).Here’s the basic structure using Kick as an example:
src/platforms/kick.ts
import type { LiveStatus } from "./types.js";
import { cleanString } from "../utils/formatters.js";
import { logger } from "../utils/logger.js";

/**
 * Check if a Kick streamer is live via API fetch
 */
export async function checkKickLive(username: string): Promise<LiveStatus> {
  const url = `https://kick.com/${username}`;
  const apiUrl = `https://kick.com/api/v2/channels/${username}`;

  const baseResult: LiveStatus = {
    isLive: false,
    platform: "kick",
    username,
    url,
  };

  try {
    const response = await fetch(apiUrl, {
      headers: {
        "User-Agent":
          "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        Accept: "application/json",
      },
    });

    if (!response.ok) {
      if (response.status === 404) {
        return baseResult;
      }
      throw new Error(`HTTP ${response.status}`);
    }

    const data = await response.json();

    // Check if livestream exists and is live
    if (data.livestream?.is_live) {
      return {
        isLive: true,
        platform: "kick",
        username: data.user?.username ?? username,
        title: data.livestream.session_title ?? undefined,
        viewers: data.livestream.viewer_count ?? undefined,
        followers: data.followers_count ?? undefined,
        profileImage: data.user?.profile_pic ?? undefined,
        startedAt: data.livestream.start_time ?? undefined,
        url,
        verified: data.verified ?? false,
        category: data.livestream.categories?.[0]?.name,
        tags: data.livestream.tags,
        language: data.livestream.language,
        isMature: data.livestream.is_mature,
      };
    }

    // Not live, but return profile data
    return {
      ...baseResult,
      followers: data.followers_count ?? undefined,
      profileImage: data.user?.profile_pic ?? undefined,
      verified: data.verified ?? false,
    };
  } catch (error) {
    logger.error(`Error checking Kick live status for ${username}:`, error);
    return { ...baseResult, error: String(error) };
  }
}
Key points:
  • Always return a LiveStatus object
  • Set isLive: false by default
  • Handle errors gracefully with try/catch
  • Return partial data even when the streamer is offline
  • Use the logger utility for error logging
2

Define API response types

Define TypeScript interfaces for the API response to ensure type safety:
interface KickChannelResponse {
  id: number;
  slug: string;
  followers_count: number;
  verified: boolean;
  user: {
    username: string;
    profile_pic: string;
  };
  livestream: {
    session_title: string;
    is_live: boolean;
    viewer_count: number;
    start_time: string;
    language: string;
    is_mature: boolean;
    tags: string[];
    categories: Array<{ name: string }>;
  } | null;
}
3

Add platform type

Update the Platform type in src/types/streamer.ts:
src/types/streamer.ts
export type Platform = "kick" | "twitch" | "youtube" | "rumble" | "tiktok" | "newplatform";
4

Register the platform

Add your platform to the registry in src/platforms/index.ts:
src/platforms/index.ts
import { checkNewPlatformLive } from "./newplatform.js";

export const platformCheckers: Record<Platform, PlatformChecker> = {
  kick: checkKickLive,
  twitch: checkTwitchLive,
  youtube: checkYouTubeLive,
  rumble: checkRumbleLive,
  tiktok: checkTikTokLive,
  newplatform: checkNewPlatformLive, // Add your platform here
};

// Also export the checker
export { checkNewPlatformLive } from "./newplatform.js";
5

Add platform constants

Add platform configuration in src/utils/constants.ts:
src/utils/constants.ts
export const PLATFORMS = {
  newplatform: {
    name: "NewPlatform",
    color: 0x00FF00, // Hex color as number
    emoji: "🟢",
    urlTemplate: "https://newplatform.com/{username}",
  },
  // ... other platforms
};
Platform branding guidelines:
  • Use the platform’s official brand color
  • Choose an appropriate emoji (or use the platform’s emoji if available)
  • Ensure the URL template uses {username} as a placeholder
6

Update slash command choices

Add your platform to the /streamer add command choices in src/commands/streamer.ts:
.addStringOption(option =>
  option
    .setName('platform')
    .setDescription('Streaming platform')
    .setRequired(true)
    .addChoices(
      { name: '🟢 Kick', value: 'kick' },
      { name: '🟣 Twitch', value: 'twitch' },
      { name: '🔴 YouTube', value: 'youtube' },
      { name: '🟢 Rumble', value: 'rumble' },
      { name: '⚫ TikTok', value: 'tiktok' },
      { name: '🟢 NewPlatform', value: 'newplatform' } // Add here
    )
)
7

Test your implementation

Test your platform checker:
npm run dev
Test with a known live streamer and a non-live streamer to ensure both cases work correctly.

Implementation Patterns

Using Public APIs

If the platform has a public API:
const apiUrl = `https://api.platform.com/users/${username}/live`;
const response = await fetch(apiUrl, {
  headers: {
    'Accept': 'application/json',
    'User-Agent': 'Mozilla/5.0 ...'
  }
});
const data = await response.json();

HTML Parsing (when no API available)

If you need to parse HTML:
const response = await fetch(`https://platform.com/${username}`);
const html = await response.text();

// Use regex or a parser to extract data
const isLiveMatch = html.match(/"isLive":(true|false)/);
const isLive = isLiveMatch?.[1] === 'true';
HTML parsing is fragile and can break if the platform changes their HTML structure. Always prefer official APIs when available.

Error Handling

Always handle common error cases:
try {
  const response = await fetch(apiUrl);
  
  // User not found
  if (response.status === 404) {
    return baseResult;
  }
  
  // Other errors
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }
  
  // Process data...
} catch (error) {
  logger.error(`Error checking platform:`, error);
  return { ...baseResult, error: String(error) };
}

Best Practices

Many platforms require a User-Agent header to avoid being blocked:
headers: {
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
Even when a streamer is offline, return their profile data (followers, profile image, etc.) for a better user experience.
For startedAt and other timestamps, use ISO 8601 format:
startedAt: new Date(timestamp).toISOString()
Use the cleanString utility to sanitize text fields:
import { cleanString } from "../utils/formatters.js";

bio: data.bio ? cleanString(data.bio) : undefined

Testing Checklist

Before submitting your platform implementation:
  • Live streamer shows isLive: true with all data
  • Offline streamer shows isLive: false with profile data
  • Non-existent user returns gracefully (no crash)
  • API errors are caught and logged
  • TypeScript compilation passes (npm run typecheck)
  • ESLint passes (npm run lint)
  • Code is formatted (npm run format)
  • Platform appears in /streamer add command
  • Alerts show correct color and emoji
  • URLs link to the correct platform profile

Need Help?

If you’re stuck or have questions:

Build docs developers (and LLMs) love