Gated Video Rooms
Create token-gated video rooms accessible only to NFT holders, token holders, or DAO members.
Overview
Gated rooms allow you to:
- š« NFT-gated: Access for specific NFT holders
- š Token-gated: Require minimum token balance
- šļø DAO-gated: Members-only spaces
- š Multi-gate: Combine multiple conditions
Creating a Gated Room
NFT-Gated Room
const room = await dial.gatedRooms.create({
name: 'Exclusive Holder Meetup',
maxParticipants: 100,
gateType: 'nft',
gate: {
collection: '0x...', // NFT collection address
chain: 'ethereum',
minQuantity: 1
}
});
console.log('Gated room URL:', room.url);Token-Gated Room
const room = await dial.gatedRooms.create({
name: '$DIAL Holders Only',
maxParticipants: 50,
gateType: 'token',
gate: {
token: '0x...', // Token contract address
chain: 'solana',
minBalance: '1000', // Minimum balance required
decimals: 9
}
});DAO-Gated Room
const room = await dial.gatedRooms.create({
name: 'DAO Governance Call',
maxParticipants: 200,
gateType: 'dao',
gate: {
daoAddress: '0x...', // DAO contract address
chain: 'ethereum',
proposalThreshold: true // Requires ability to create proposals
}
});Multi-Gated Room
const room = await dial.gatedRooms.create({
name: 'Elite Community',
maxParticipants: 20,
gateType: 'multi',
gates: [
{
type: 'nft',
collection: '0x...',
chain: 'ethereum'
},
{
type: 'token',
token: '0x...',
chain: 'solana',
minBalance: '5000'
}
],
gateLogic: 'OR' // 'AND' or 'OR'
});Gate Types
NFT Gate Options
interface NFTGate {
collection: string; // Contract address
chain: 'ethereum' | 'solana' | 'polygon' | 'base';
minQuantity?: number; // Minimum NFTs to own
specificTokenIds?: string[]; // Specific token IDs
traits?: {
traitType: string;
value: string;
}[];
}Token Gate Options
interface TokenGate {
token: string; // Token contract address
chain: 'ethereum' | 'solana' | 'polygon' | 'base';
minBalance: string; // Minimum token balance
decimals: number;
snapshot?: Date; // Balance at specific time
}DAO Gate Options
interface DAOGate {
daoAddress: string;
chain: 'ethereum' | 'solana';
proposalThreshold?: boolean; // Must be able to create proposals
votingPower?: string; // Minimum voting power
}Joining Gated Rooms
Check Access
const hasAccess = await dial.gatedRooms.checkAccess({
roomId: room.id,
walletAddress: '0x...'
});
if (hasAccess.allowed) {
console.log('Access granted!');
} else {
console.log('Access denied:', hasAccess.reason);
}Join Room
try {
await dial.gatedRooms.join({
roomId: room.id,
walletAddress: '0x...',
signature: await wallet.signMessage('Join gated room')
});
} catch (error) {
if (error.code === 'ACCESS_DENIED') {
console.log('You do not meet the requirements');
}
}Verification Process
The SDK automatically verifies gate conditions:
// Verification flow
const verification = await dial.gatedRooms.verify({
roomId: room.id,
walletAddress: '0x...'
});
console.log('Verification status:', verification.status);
console.log('Requirements met:', verification.requirementsMet);
console.log('Missing requirements:', verification.missingRequirements);Managing Gated Rooms
Update Gate Requirements
await dial.gatedRooms.updateGate(roomId, {
gate: {
collection: '0x...', // New collection
minQuantity: 2 // Updated requirement
}
});Add Whitelist
// Add specific addresses to whitelist
await dial.gatedRooms.addToWhitelist(roomId, [
'0x...',
'0x...'
]);
// Remove from whitelist
await dial.gatedRooms.removeFromWhitelist(roomId, ['0x...']);Temporary Access Passes
// Create temporary pass
const pass = await dial.gatedRooms.createPass({
roomId: room.id,
recipientAddress: '0x...',
expiresAt: new Date('2025-12-31'),
maxUses: 5
});
console.log('Pass URL:', pass.url);Room Analytics
const analytics = await dial.gatedRooms.getAnalytics(roomId);
console.log('Total participants:', analytics.totalParticipants);
console.log('Unique holders:', analytics.uniqueHolders);
console.log('Access attempts:', analytics.accessAttempts);
console.log('Denied attempts:', analytics.deniedAttempts);Complete Example: React Gated Room Component
import { useState, useEffect } from 'react';
import { DialClient } from '@dial/sdk';
import { useAccount, useSignMessage } from 'wagmi';
export function GatedRoomAccess({ dial, roomId }) {
const { address } = useAccount();
const { signMessageAsync } = useSignMessage();
const [room, setRoom] = useState(null);
const [access, setAccess] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
checkAccess();
}, [roomId, address]);
const checkAccess = async () => {
if (!address) return;
setLoading(true);
// Get room details
const roomDetails = await dial.gatedRooms.get(roomId);
setRoom(roomDetails);
// Check access
const accessStatus = await dial.gatedRooms.checkAccess({
roomId,
walletAddress: address
});
setAccess(accessStatus);
setLoading(false);
};
const joinRoom = async () => {
try {
const signature = await signMessageAsync({
message: 'Join gated room'
});
await dial.gatedRooms.join({
roomId,
walletAddress: address,
signature
});
// Redirect to room
window.location.href = room.url;
} catch (error) {
console.error('Failed to join:', error);
}
};
if (loading) {
return <div>Checking access...</div>;
}
if (!access?.allowed) {
return (
<div className="access-denied">
<h2>š Access Restricted</h2>
<p>{room.name}</p>
<div className="requirements">
<h3>Requirements:</h3>
{room.gate.type === 'nft' && (
<p>
Hold at least {room.gate.minQuantity} NFT(s) from{' '}
{room.gate.collection}
</p>
)}
{room.gate.type === 'token' && (
<p>
Hold at least {room.gate.minBalance} tokens
</p>
)}
</div>
{access?.missingRequirements && (
<div className="missing">
<h4>You're missing:</h4>
<ul>
{access.missingRequirements.map((req, i) => (
<li key={i}>{req}</li>
))}
</ul>
</div>
)}
</div>
);
}
return (
<div className="access-granted">
<h2>ā
Access Granted</h2>
<p>{room.name}</p>
<button onClick={joinRoom}>Join Room</button>
</div>
);
}Advanced Features
Dynamic Gates
Update gate requirements based on conditions:
// Gate changes based on time
await dial.gatedRooms.createScheduledGate({
roomId,
schedule: [
{
from: '2025-01-01T00:00:00Z',
to: '2025-06-01T00:00:00Z',
gate: { /* early access gate */ }
},
{
from: '2025-06-01T00:00:00Z',
gate: { /* general access gate */ }
}
]
});Tiered Access
// Create tiers with different privileges
await dial.gatedRooms.createTiers(roomId, [
{
name: 'Diamond',
gate: { token: '0x...', minBalance: '10000' },
privileges: ['host', 'recording', 'priority_audio']
},
{
name: 'Gold',
gate: { token: '0x...', minBalance: '5000' },
privileges: ['priority_audio']
},
{
name: 'Silver',
gate: { token: '0x...', minBalance: '1000' },
privileges: []
}
]);Snapshot Verification
Verify holdings at a specific block/time:
const room = await dial.gatedRooms.create({
name: 'Snapshot Holders',
gateType: 'token',
gate: {
token: '0x...',
minBalance: '1000',
snapshot: {
blockNumber: 12345678,
chain: 'ethereum'
}
}
});Next Steps
Last updated on