Examples
Complete code examples for common Dial SDK use cases.
Quick Examples
Basic Audio Call
import { DialClient } from '@dial/sdk';
import { SiweMessage } from 'siwe';
const dial = new DialClient({
apiKey: process.env.DIAL_API_KEY
});
// Authenticate with SIWE
const nonce = await dial.auth.getNonce();
const siweMessage = new SiweMessage({
domain: 'dial.wtf',
address: walletAddress,
statement: 'Sign in to Dial',
uri: 'https://dial.wtf',
version: '1',
chainId: 1,
nonce,
});
const message = siweMessage.prepareMessage();
const signature = await wallet.signMessage(message);
const userDialer = await dial.asUser({
siwe: { message, signature }
});
// Make call
const call = await userDialer.calls.start({
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
type: 'audio'
});
console.log('Calling...', call.id);Video Call with React
import { useState, useEffect } from 'react';
import { DialClient } from '@dial/sdk';
export function VideoCall() {
const [dial] = useState(() => new DialClient({
apiKey: process.env.NEXT_PUBLIC_DIAL_API_KEY
}));
const [call, setCall] = useState(null);
const [localStream, setLocalStream] = useState(null);
const [remoteStream, setRemoteStream] = useState(null);
useEffect(() => {
dial.on('call:incoming', handleIncomingCall);
dial.on('stream:local', setLocalStream);
dial.on('stream:remote', setRemoteStream);
return () => {
dial.off('call:incoming');
dial.off('stream:local');
dial.off('stream:remote');
};
}, []);
const handleIncomingCall = (incomingCall) => {
setCall(incomingCall);
};
const startCall = async () => {
const newCall = await dial.calls.start({
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
type: 'video'
});
setCall(newCall);
};
return (
<div>
{!call ? (
<button onClick={startCall}>Start Video Call</button>
) : (
<div>
<video
ref={(el) => { if (el) el.srcObject = remoteStream }}
autoPlay
/>
<video
ref={(el) => { if (el) el.srcObject = localStream }}
autoPlay
muted
/>
<button onClick={() => call.end()}>End Call</button>
</div>
)}
</div>
);
}Send Message
await dial.messages.send({
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
content: 'Hey! How are you?',
type: 'text'
});Real-time Chat
import { useState, useEffect } from 'react';
export function Chat({ dial, recipient }) {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
useEffect(() => {
loadHistory();
dial.on('message:received', (msg) => {
if (msg.from === recipient) {
setMessages(prev => [...prev, msg]);
}
});
}, [recipient]);
const loadHistory = async () => {
const history = await dial.messages.getMessages({
with: recipient,
limit: 50
});
setMessages(history);
};
const send = async () => {
await dial.messages.send({
to: recipient,
content: input,
type: 'text'
});
setInput('');
};
return (
<div>
<div className="messages">
{messages.map(msg => (
<div key={msg.id}>
<strong>{msg.from}:</strong> {msg.content}
</div>
))}
</div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && send()}
/>
</div>
);
}Full Applications
Complete Calling App (React + Next.js)
// pages/_app.tsx
import { DialProvider } from '@dial/sdk/react';
export default function App({ Component, pageProps }) {
return (
<DialProvider apiKey={process.env.NEXT_PUBLIC_DIAL_API_KEY}>
<Component {...pageProps} />
</DialProvider>
);
}
// components/CallInterface.tsx
import { useState, useEffect } from 'react';
import { useDial } from '@dial/sdk/react';
export function CallInterface() {
const { dial, isConnected } = useDial();
const [call, setCall] = useState(null);
const [recipient, setRecipient] = useState('');
const [isMuted, setIsMuted] = useState(false);
const [isVideoEnabled, setIsVideoEnabled] = useState(true);
useEffect(() => {
if (!dial) return;
dial.on('call:incoming', setCall);
dial.on('call:ended', () => setCall(null));
return () => {
dial.off('call:incoming');
dial.off('call:ended');
};
}, [dial]);
const startCall = async (type) => {
const newCall = await dial.calls.start({
to: recipient,
type
});
setCall(newCall);
};
const answerCall = () => dial.calls.answer(call.id);
const declineCall = () => dial.calls.decline(call.id);
const endCall = () => dial.calls.end(call.id);
const toggleMute = async () => {
await dial.calls.toggleMute(call.id);
setIsMuted(!isMuted);
};
const toggleVideo = async () => {
await dial.calls.toggleVideo(call.id);
setIsVideoEnabled(!isVideoEnabled);
};
if (!isConnected) {
return <div>Connecting to Dial...</div>;
}
if (!call) {
return (
<div className="call-setup">
<input
type="text"
placeholder="Enter wallet address"
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
/>
<button onClick={() => startCall('audio')}>
š Audio Call
</button>
<button onClick={() => startCall('video')}>
š¹ Video Call
</button>
</div>
);
}
if (call.status === 'ringing' && call.direction === 'incoming') {
return (
<div className="incoming-call">
<h2>Incoming Call</h2>
<p>From: {call.from}</p>
<button onClick={answerCall}>ā
Answer</button>
<button onClick={declineCall}>ā Decline</button>
</div>
);
}
return (
<div className="active-call">
<div className="video-container">
<video
ref={(el) => {
if (el && call) {
el.srcObject = dial.calls.getRemoteStream(call.id);
}
}}
autoPlay
className="remote-video"
/>
{call.type === 'video' && (
<video
ref={(el) => {
if (el && call) {
el.srcObject = dial.calls.getLocalStream(call.id);
}
}}
autoPlay
muted
className="local-video"
/>
)}
</div>
<div className="call-controls">
<button onClick={toggleMute}>
{isMuted ? 'š' : 'š¤'}
</button>
{call.type === 'video' && (
<button onClick={toggleVideo}>
{isVideoEnabled ? 'š¹' : 'š«'}
</button>
)}
<button onClick={endCall} className="end-call">
š End Call
</button>
</div>
</div>
);
}
// pages/index.tsx
export default function Home() {
return (
<div>
<h1>Dial Video Calling</h1>
<CallInterface />
</div>
);
}NFT-Gated Video Room
import { useAccount } from 'wagmi';
import { useDial } from '@dial/sdk/react';
export function GatedRoom() {
const { address } = useAccount();
const { dial } = useDial();
const [room, setRoom] = useState(null);
const [hasAccess, setHasAccess] = useState(false);
useEffect(() => {
checkAccess();
}, [address]);
const checkAccess = async () => {
if (!address) return;
const access = await dial.gatedRooms.checkAccess({
roomId: 'your-room-id',
walletAddress: address
});
setHasAccess(access.allowed);
};
const joinRoom = async () => {
if (!hasAccess) {
alert('You need to hold the required NFT');
return;
}
const joinedRoom = await dial.gatedRooms.join({
roomId: 'your-room-id',
walletAddress: address
});
setRoom(joinedRoom);
};
if (!address) {
return <div>Please connect your wallet</div>;
}
if (!hasAccess) {
return (
<div>
<h2>š Access Denied</h2>
<p>You need to hold an NFT from the collection to enter</p>
</div>
);
}
return (
<div>
<h2>ā
Access Granted</h2>
{!room ? (
<button onClick={joinRoom}>Join Room</button>
) : (
<ConferenceView room={room} />
)}
</div>
);
}Live Streaming Dashboard
export function StreamDashboard() {
const { dial } = useDial();
const [stream, setStream] = useState(null);
const [isLive, setIsLive] = useState(false);
const [viewers, setViewers] = useState(0);
const createStream = async () => {
const newStream = await dial.streaming.create({
title: 'My Live Stream',
description: 'Going live!',
isPublic: true
});
setStream(newStream);
};
const goLive = async () => {
await dial.streaming.start({
streamId: stream.id,
video: true,
audio: true,
quality: '1080p'
});
setIsLive(true);
};
useEffect(() => {
if (!stream) return;
dial.on('stream:viewer:count', ({ count }) => {
setViewers(count);
});
}, [stream]);
return (
<div>
{!stream ? (
<button onClick={createStream}>Create Stream</button>
) : (
<div>
<h2>{stream.title}</h2>
<p>Stream Key: {stream.streamKey}</p>
{isLive && <div>š“ LIVE ⢠{viewers} viewers</div>}
<button onClick={isLive ? endStream : goLive}>
{isLive ? 'End Stream' : 'Go Live'}
</button>
</div>
)}
</div>
);
}Integration Examples
With wagmi (Ethereum + SIWE)
import { useAccount, useSignMessage, useChainId } from 'wagmi';
import { useDial } from '@dial/sdk/react';
import { SiweMessage } from 'siwe';
export function WalletIntegration() {
const { address } = useAccount();
const { signMessageAsync } = useSignMessage();
const chainId = useChainId();
const { dial } = useDial();
const authenticate = async () => {
// Get nonce from Dial
const nonce = await dial.auth.getNonce();
// Create SIWE message
const siweMessage = new SiweMessage({
domain: 'dial.wtf',
address,
statement: 'Sign in to Dial',
uri: 'https://dial.wtf',
version: '1',
chainId,
nonce,
issuedAt: new Date().toISOString(),
});
const message = siweMessage.prepareMessage();
const signature = await signMessageAsync({ message });
const userDialer = await dial.asUser({
siwe: { message, signature }
});
return userDialer;
};
return (
<button onClick={authenticate}>
Connect to Dial
</button>
);
}With Solana Wallet Adapter (SIWS)
import { useWallet } from '@solana/wallet-adapter-react';
import { useDial } from '@dial/sdk/react';
import { SigninMessage } from '@solana/wallet-standard-util';
import bs58 from 'bs58';
export function SolanaIntegration() {
const { publicKey, signMessage } = useWallet();
const { dial } = useDial();
const authenticate = async () => {
if (!publicKey || !signMessage) return;
// Get nonce from Dial
const nonce = await dial.auth.getNonce();
// Create SIWS message
const siwsMessage = new SigninMessage({
domain: 'dial.wtf',
address: publicKey.toBase58(),
statement: 'Sign in to Dial',
uri: 'https://dial.wtf',
version: '1',
chainId: 'mainnet',
nonce,
issuedAt: new Date().toISOString(),
});
const messageText = siwsMessage.prepare();
const messageBytes = new TextEncoder().encode(messageText);
const signatureBytes = await signMessage(messageBytes);
const signature = bs58.encode(signatureBytes);
const userDialer = await dial.asUser({
siws: { message: messageText, signature }
});
return userDialer;
};
return (
<button onClick={authenticate}>
Connect to Dial
</button>
);
}More Examples
Browse our example repositories:
Next Steps
Last updated on