Skip to Content
Dial v1 live 🎉
SdkLive Streaming

Live Streaming

Broadcast live audio and video to your Web3 community with support for chat, reactions, and token-gating.

Creating a Live Stream

Basic Stream

const stream = await dial.streaming.create({ title: 'Weekly AMA', description: 'Ask me anything about Web3', isPublic: true }); console.log('Stream URL:', stream.url); console.log('Stream Key:', stream.streamKey);

Gated Stream

const stream = await dial.streaming.create({ title: 'Exclusive Holder Stream', description: 'NFT holders only', isPublic: false, gate: { type: 'nft', collection: '0x...', chain: 'ethereum' } });

Stream Object

interface LiveStream { id: string; title: string; description: string; host: string; // Wallet address streamKey: string; url: string; playbackUrl: string; status: 'idle' | 'live' | 'ended'; viewerCount: number; startedAt?: Date; endedAt?: Date; isPublic: boolean; gate?: GateConfig; }

Starting a Stream

Browser-Based Streaming

// Start streaming from browser await dial.streaming.start({ streamId: stream.id, video: true, audio: true, quality: '1080p' });

External Encoder (OBS, etc.)

// Get RTMP details for external encoders const rtmpDetails = await dial.streaming.getRTMPDetails(stream.id); console.log('RTMP URL:', rtmpDetails.url); console.log('Stream Key:', rtmpDetails.streamKey); // Configure in OBS: // Server: rtmpDetails.url // Stream Key: rtmpDetails.streamKey

Watching a Stream

// Get stream details const stream = await dial.streaming.get(streamId); // Check if live if (stream.status === 'live') { // Load player const player = dial.streaming.createPlayer({ streamId: stream.id, container: document.getElementById('player'), autoplay: true }); }

Viewer Management

Get Viewers

const viewers = await dial.streaming.getViewers(streamId); console.log(`${viewers.length} watching`);

Listen for Viewer Events

dial.on('stream:viewer:joined', ({ viewer }) => { console.log(`${viewer.displayName} joined`); }); dial.on('stream:viewer:left', ({ viewer }) => { console.log(`${viewer.displayName} left`); }); dial.on('stream:viewer:count', ({ count }) => { console.log(`${count} viewers`); });

Live Chat

Send Message

await dial.streaming.sendChatMessage(streamId, { content: 'Great stream!', type: 'text' });

Receive Messages

dial.on('stream:chat:message', ({ message, sender }) => { console.log(`${sender.displayName}: ${message.content}`); });

Moderate Chat

// Delete message (host/moderator only) await dial.streaming.deleteChatMessage(streamId, messageId); // Ban user from chat await dial.streaming.banFromChat(streamId, walletAddress); // Enable slow mode await dial.streaming.setChatSlowMode(streamId, { enabled: true, interval: 5 // seconds between messages });

Reactions

Send Reaction

await dial.streaming.sendReaction(streamId, { emoji: '🔥' });

Listen for Reactions

dial.on('stream:reaction', ({ emoji, sender }) => { console.log(`${sender.displayName} reacted with ${emoji}`); });

Stream Settings

Update Stream Info

await dial.streaming.update(streamId, { title: 'Updated Title', description: 'New description' });

Stream Quality Settings

await dial.streaming.setQuality(streamId, { resolution: '1080p', // '720p', '1080p', '4k' frameRate: 60, bitrate: 6000 // kbps });

Enable DVR

// Allow viewers to rewind await dial.streaming.enableDVR(streamId, { enabled: true, bufferDuration: 3600 // 1 hour in seconds });

Recording

Auto-Record

const stream = await dial.streaming.create({ title: 'Recorded Stream', autoRecord: true });

Manual Recording

// Start recording await dial.streaming.startRecording(streamId); // Stop recording const recording = await dial.streaming.stopRecording(streamId); console.log('Recording URL:', recording.url);

Get Recordings

const recordings = await dial.streaming.getRecordings(streamId); recordings.forEach(rec => { console.log(`Recording: ${rec.url}`); console.log(`Duration: ${rec.duration}s`); });

Ending a Stream

await dial.streaming.end(streamId);

Complete Example: React Live Stream Component

import { useState, useEffect } from 'react'; import { DialClient, LiveStream } from '@dial/sdk'; export function LiveStreamHost({ dial }) { const [stream, setStream] = useState<LiveStream | null>(null); const [isLive, setIsLive] = useState(false); const [viewerCount, setViewerCount] = useState(0); const [chatMessages, setChatMessages] = useState([]); useEffect(() => { if (stream) { setupEventListeners(); } return () => { if (stream && isLive) { dial.streaming.end(stream.id); } }; }, [stream]); const setupEventListeners = () => { dial.on('stream:viewer:count', ({ count }) => { setViewerCount(count); }); dial.on('stream:chat:message', ({ message, sender }) => { setChatMessages(prev => [...prev, { message, sender }]); }); }; const createStream = async () => { const newStream = await dial.streaming.create({ title: 'My Live Stream', description: 'Going live!', isPublic: true }); setStream(newStream); }; const goLive = async () => { if (!stream) return; await dial.streaming.start({ streamId: stream.id, video: true, audio: true, quality: '1080p' }); setIsLive(true); }; const endStream = async () => { if (!stream) return; await dial.streaming.end(stream.id); setIsLive(false); }; if (!stream) { return ( <button onClick={createStream}> Create Stream </button> ); } return ( <div className="stream-host"> <div className="stream-preview"> <video ref={(el) => { if (el && isLive) { const localStream = dial.streaming.getLocalStream(stream.id); el.srcObject = localStream; } }} autoPlay muted /> {isLive && ( <div className="live-indicator"> 🔴 LIVE • {viewerCount} viewers </div> )} </div> <div className="stream-controls"> {!isLive ? ( <button onClick={goLive}>Go Live</button> ) : ( <button onClick={endStream} className="danger"> End Stream </button> )} </div> <div className="stream-chat"> <h3>Live Chat</h3> <div className="messages"> {chatMessages.map((msg, i) => ( <div key={i} className="message"> <strong>{msg.sender.displayName}:</strong> {msg.message.content} </div> ))} </div> </div> <div className="stream-info"> <h3>Stream Details</h3> <p>URL: {stream.url}</p> <p>Stream Key: {stream.streamKey}</p> </div> </div> ); } export function LiveStreamViewer({ dial, streamId }) { const [stream, setStream] = useState<LiveStream | null>(null); const [chatInput, setChatInput] = useState(''); useEffect(() => { loadStream(); }, [streamId]); const loadStream = async () => { const streamData = await dial.streaming.get(streamId); setStream(streamData); }; const sendMessage = async () => { if (!chatInput.trim()) return; await dial.streaming.sendChatMessage(streamId, { content: chatInput, type: 'text' }); setChatInput(''); }; const sendReaction = async (emoji: string) => { await dial.streaming.sendReaction(streamId, { emoji }); }; if (!stream) return <div>Loading...</div>; return ( <div className="stream-viewer"> <div id="player" className="player-container" /> <div className="reactions"> <button onClick={() => sendReaction('🔥')}>🔥</button> <button onClick={() => sendReaction('❤️')}>❤️</button> <button onClick={() => sendReaction('👍')}>👍</button> <button onClick={() => sendReaction('😂')}>😂</button> </div> <div className="chat"> <input value={chatInput} onChange={(e) => setChatInput(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && sendMessage()} placeholder="Send a message..." /> <button onClick={sendMessage}>Send</button> </div> </div> ); }

Analytics

const analytics = await dial.streaming.getAnalytics(streamId); console.log('Total views:', analytics.totalViews); console.log('Peak viewers:', analytics.peakViewers); console.log('Average watch time:', analytics.avgWatchTime); console.log('Chat messages:', analytics.chatMessageCount); console.log('Reactions:', analytics.reactionCount);

Multi-Stream (Simulcast)

Stream to multiple platforms simultaneously:

await dial.streaming.enableSimulcast(streamId, [ { platform: 'youtube', streamKey: 'your-youtube-key' }, { platform: 'twitch', streamKey: 'your-twitch-key' } ]);

Next Steps

Last updated on