API Quick Start
Get started building Stream CoHost plugins in minutes with our comprehensive API.
Create Plugin
Set up a new plugin with our template
Add Commands
Register chat commands and handlers
Store Data
Use the database API for persistence
Add UI
Create admin interface and overlays
5-Minute Plugin
Create a simple "Hello World" plugin to get familiar with the API:
class HelloPlugin {
constructor(bot) {
this.bot = bot;
this.name = 'Hello';
this.version = '1.0.0';
this.description = 'A simple hello world plugin';
}
async onLoad() {
console.log(`${this.name} plugin loaded!`);
// Register a chat command
this.bot.registerCommand('!hello', this.handleHello.bind(this));
// Set up a web route for admin
this.setupRoutes();
}
async handleHello(context) {
const { username } = context;
// Store greeting in memory
await this.bot.memory.store(username,
`${username} used the hello command`,
'interactions'
);
return {
success: true,
response: `Hello ${username}! Welcome to Stream CoHost! 👋`
};
}
setupRoutes() {
this.bot.app.get('/api/hello/stats', (req, res) => {
res.json({
plugin: this.name,
version: this.version,
commands: ['!hello']
});
});
}
async onUnload() {
this.bot.unregisterCommand('!hello');
console.log(`${this.name} plugin unloaded`);
}
}
module.exports = HelloPlugin;
Bot Core API
The main bot instance provides access to all core functionality and services.
bot.registerCommand(trigger, handler, options)
MethodRegister a new chat command with the bot.
Parameters
Name | Type | Required | Description |
---|---|---|---|
trigger |
string | Yes | Command trigger (e.g., "!hello") |
handler |
function | Yes | Async function to handle command |
options |
object | No | Command configuration options |
Example
bot.registerCommand('!dice', async (context) => {
const roll = Math.floor(Math.random() * 6) + 1;
return {
success: true,
response: `🎲 ${context.username} rolled a ${roll}!`
};
}, {
description: 'Roll a 6-sided die',
cooldown: 5000, // 5 second cooldown
permissions: ['everyone']
});
bot.unregisterCommand(trigger)
MethodRemove a previously registered command.
Parameters
Name | Type | Description |
---|---|---|
trigger |
string | Command trigger to remove |
bot.sendMessage(message, channel)
MethodSend a message to the Twitch chat.
Parameters
Name | Type | Required | Description |
---|---|---|---|
message |
string | Yes | Message content to send |
channel |
string | No | Channel name (defaults to bot's channel) |
Database API
Access SQLite database for persistent data storage across plugin sessions.
bot.database.query(sql, params)
MethodExecute a SQL query with optional parameters.
Example
// Create a table for your plugin
await bot.database.query(`
CREATE TABLE IF NOT EXISTS user_scores (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE,
score INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
// Insert or update user score
await bot.database.query(`
INSERT OR REPLACE INTO user_scores (username, score)
VALUES (?, ?)
`, [username, newScore]);
// Query user scores
const topScores = await bot.database.query(`
SELECT username, score
FROM user_scores
ORDER BY score DESC
LIMIT 10
`);
bot.database.prepare(sql)
MethodPrepare a SQL statement for better performance with repeated queries.
Example
// Prepare statements for better performance
const insertScore = bot.database.prepare(`
INSERT OR REPLACE INTO user_scores (username, score) VALUES (?, ?)
`);
const getScore = bot.database.prepare(`
SELECT score FROM user_scores WHERE username = ?
`);
// Use prepared statements
insertScore.run(username, score);
const result = getScore.get(username);
Memory API
Interact with Stream CoHost's intelligent AI memory system.
bot.memory.store(username, content, category)
Async MethodStore a memory for a specific user with categorization.
Parameters
Name | Type | Description |
---|---|---|
username |
string | User to store memory for |
content |
string | Memory content |
category |
string | Memory category (preferences, achievements, etc.) |
Example
// Store user achievement
await bot.memory.store(username,
`${username} completed the charades challenge in record time!`,
'achievements'
);
// Store user preference
await bot.memory.store(username,
`${username} prefers playing horror games on Friday nights`,
'preferences'
);
bot.memory.recall(username, category)
Async MethodRetrieve memories for a user, optionally filtered by category.
Example
// Get all memories for a user
const memories = await bot.memory.recall(username);
// Get specific category memories
const achievements = await bot.memory.recall(username, 'achievements');
// Use memories in responses
if (achievements.length > 0) {
return {
success: true,
response: `${username}, I remember when ${achievements[0].content}`
};
}
WebSocket API
Real-time communication with overlays and external applications.
bot.websocket.broadcast(data)
MethodBroadcast data to all connected WebSocket clients.
Example
// Send game state update to overlay
bot.websocket.broadcast({
type: 'game-update',
plugin: 'charades',
data: {
currentWord: 'elephant',
guessesRemaining: 3,
score: 150
}
});
// Send notification to all clients
bot.websocket.broadcast({
type: 'notification',
message: 'New follower: CoolViewer123!',
level: 'success'
});
bot.websocket.sendTo(clientId, data)
MethodSend data to a specific WebSocket client.
OpenAI API
Access OpenAI services with built-in caching and optimization.
bot.ai.generateResponse(prompt, options)
Async MethodGenerate AI responses with context awareness and caching.
Example
// Generate contextual response
const response = await bot.ai.generateResponse(
`Help ${username} with their question: "${userMessage}"`,
{
maxTokens: 100,
temperature: 0.7,
includeMemory: true,
username: username
}
);
// Generate creative content
const storyPrompt = `Write a short fantasy story about ${username}'s adventure`;
const story = await bot.ai.generateResponse(storyPrompt, {
maxTokens: 200,
temperature: 0.9
});
bot.ai.generateImage(prompt, options)
Async MethodGenerate images using DALL-E with automatic storage and caching.
Example
// Generate charades visual clue
const imageUrl = await bot.ai.generateImage(
`A movie scene showing ${clueText}, cinematic style`,
{
size: '512x512',
style: 'vivid',
quality: 'standard'
}
);
// Display in overlay
bot.websocket.broadcast({
type: 'image-update',
plugin: 'charades',
imageUrl: imageUrl,
caption: 'Guess the movie!'
});
Example: Basic Plugin
A complete example of a simple quote plugin with database storage.
class QuotesPlugin {
constructor(bot) {
this.bot = bot;
this.name = 'Quotes';
this.version = '1.0.0';
this.description = 'Store and retrieve memorable quotes from chat';
}
async onLoad() {
console.log(`${this.name} plugin loaded`);
// Create quotes table
await this.initDatabase();
// Register commands
this.bot.registerCommand('!addquote', this.addQuote.bind(this));
this.bot.registerCommand('!quote', this.getQuote.bind(this));
this.bot.registerCommand('!quotes', this.listQuotes.bind(this));
// Set up web routes
this.setupRoutes();
}
async initDatabase() {
await this.bot.database.query(`
CREATE TABLE IF NOT EXISTS quotes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
author TEXT NOT NULL,
added_by TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
}
async addQuote(context) {
const { username, args } = context;
if (args.length < 2) {
return {
success: false,
response: 'Usage: !addquote [author] [quote text]'
};
}
const author = args[0];
const content = args.slice(1).join(' ');
try {
await this.bot.database.query(
'INSERT INTO quotes (content, author, added_by) VALUES (?, ?, ?)',
[content, author, username]
);
// Store memory of this action
await this.bot.memory.store(username,
`${username} added a quote by ${author}: "${content}"`,
'contributions'
);
return {
success: true,
response: `Quote added! "${content}" - ${author}`
};
} catch (error) {
console.error('Error adding quote:', error);
return {
success: false,
response: 'Failed to add quote. Please try again.'
};
}
}
async getQuote(context) {
const { args } = context;
try {
let quote;
if (args.length > 0) {
// Get quote by author
const author = args.join(' ');
const quotes = await this.bot.database.query(
'SELECT * FROM quotes WHERE author LIKE ? ORDER BY RANDOM() LIMIT 1',
[`%${author}%`]
);
quote = quotes[0];
} else {
// Get random quote
const quotes = await this.bot.database.query(
'SELECT * FROM quotes ORDER BY RANDOM() LIMIT 1'
);
quote = quotes[0];
}
if (!quote) {
return {
success: false,
response: args.length > 0
? `No quotes found for "${args.join(' ')}"`
: 'No quotes available yet! Add one with !addquote'
};
}
return {
success: true,
response: `"${quote.content}" - ${quote.author}`
};
} catch (error) {
console.error('Error getting quote:', error);
return {
success: false,
response: 'Failed to retrieve quote. Please try again.'
};
}
}
async listQuotes(context) {
try {
const count = await this.bot.database.query(
'SELECT COUNT(*) as count FROM quotes'
);
const recentQuotes = await this.bot.database.query(
'SELECT author FROM quotes GROUP BY author ORDER BY MAX(created_at) DESC LIMIT 5'
);
const authors = recentQuotes.map(q => q.author).join(', ');
return {
success: true,
response: `We have ${count[0].count} quotes! Recent authors: ${authors}`
};
} catch (error) {
console.error('Error listing quotes:', error);
return {
success: false,
response: 'Failed to list quotes.'
};
}
}
setupRoutes() {
// API endpoint for quotes
this.bot.app.get('/api/quotes', async (req, res) => {
try {
const quotes = await this.bot.database.query(
'SELECT * FROM quotes ORDER BY created_at DESC LIMIT 50'
);
res.json({ quotes });
} catch (error) {
res.status(500).json({ error: 'Failed to fetch quotes' });
}
});
// Admin interface
this.bot.app.get('/quotes', (req, res) => {
res.send(`
Quotes Plugin
Manage your chat quotes
`);
});
}
async onUnload() {
this.bot.unregisterCommand('!addquote');
this.bot.unregisterCommand('!quote');
this.bot.unregisterCommand('!quotes');
console.log(`${this.name} plugin unloaded`);
}
}
module.exports = QuotesPlugin;