Menu
Products
Products
Video Hosting
Upload and manage your videos in a centralized video library.
Image Hosting
Upload and manage all your images in a centralized library.
Galleries
Choose from 100+templates to showcase your media in style.
Video Messaging
Record, and send personalized video messages.
CincoTube
Create your own community video hub your team, students or fans.
Pages
Create dedicated webpages to share your videos and images.
Live
Create dedicated webpages to share your videos and images.
For Developers
Video API
Build a unique video experience.
DeepUploader
Collect and store user content from anywhere with our file uploader.
Solutions
Solutions
Enterprise
Supercharge your business with secure, internal communication.
Townhall
Webinars
Team Collaboration
Learning & Development
Creative Professionals
Get creative with a built in-suite of editing and marketing tools.
eCommerce
Boost sales with interactive video and easy-embedding.
Townhall
Webinars
Team Collaboration
Learning & Development
eLearning & Training
Host and share course materials in a centralized portal.
Sales & Marketing
Attract, engage and convert with interactive tools and analytics.
"Cincopa helped my Enterprise organization collaborate better through video."
Book a Demo
Resources
Resources
Blog
Learn about the latest industry trends, tips & tricks.
Help Centre
Get access to help articles FAQs, and all things Cincopa.
Partners
Check out our valued list of partners.
Product Updates
Stay up-to-date with our latest greatest features.
Ebooks, Guides & More
Customer Stories
Hear how we've helped businesses succeed.
Boost Campaign Performance Through Video
Discover how to boost your next campaign by using video.
Download Now
Pricing
Log in
Get a demo
Get Started
Building a video-calling feature in Agora starts with understanding how the platform handles real-time audio and video. Before writing any code, it helps to know why these pieces matter: each part you set up defines how smoothly users can see and hear one another. Video calling isn’t just about connecting two screens; it’s about creating a stable, clear, real-time link that reacts quickly to changing network conditions. With a clear view of these basics, it becomes easier to move into the implementation with purpose and confidence. Prerequisites Computer and Browser : Use a computer with a modern web browser like Chrome or Firefox. Ensure your camera and microphone are working. Agora Account : Sign up for a free account on the Agora Console website to get an App ID and generate temporary tokens. Text Editor : Have a simple text editor for writing HTML and JavaScript code. Local Server : Install a way to run a local web server, such as Python's built-in server (run python -m http.server 8000 in the project folder) or a browser extension. Step-by-Step Process Set up your video call app piece by piece to build a solid foundation for real-time communication, making sure everything connects properly and works as expected. Create a Vite Project npm create vite@latest agora-video-call --template vanilla-ts cd agora-video-call npm install Install Agora SDK npm install agora-rtc-sdk-ng@4.24.0 npm install -D vite @types/node Agora Console Setup 1. agora.io/console → New Project → Get App ID 2. Generate Temp Token (channel: 'test', uid: null) 3. HTTPS Required → Vite dev server = localhost OK Update index.html (index.html):
Agora Video Call v4.24.0
Agora Video Call (v4.24.0)
Join
Mute
Leave
Complete Implementation (src/main.ts) import * as AgoraRTC from 'agora-rtc-sdk-ng'; interface Config { appid: string; token: string; channel: string; } const config: Partial
= { appid: '', token: '', channel: '', }; let client: AgoraRTC.IRTCCreateClient; let localAudioTrack: AgoraRTC.IMicrophoneAudioTrack; let localVideoTrack: AgoraRTC.ICameraVideoTrack; let remoteUsers: Record
= {}; async function createClient() { client = AgoraRTC.createClient({ mode: 'rtc', codec: 'vp8' }); client.on('user-published', async (user, mediaType) => { await client.subscribe(user, mediaType); if (mediaType === 'video') { const remoteVideo = document.createElement('div'); remoteVideo.id = `remote-video-${user.uid}`; remoteVideo.className = 'remote-video'; document.getElementById('remote container')!.appendChild(remoteVideo); user.videoTrack!.play(remoteVideo.id); } if (mediaType === 'audio') { user.audioTrack!.play(); } }); client.on('user-unpublished', (user, mediaType) => { if (mediaType === 'video') { const remoteVideo = document.getElementById(`remote video-${user.uid}`); if (remoteVideo) remoteVideo.remove(); } }); client.on('user-left', (user) => { const remoteVideo = document.getElementById(`remote video-${user.uid}`); if (remoteVideo) remoteVideo.remove(); delete remoteUsers[user.uid]; }); } async function join() { if (!config.appid || !config.token || !config.channel) { alert('Please fill all fields'); return; } try { // Join channel await client.join(config.appid, config.channel, config.token, null); // Create tracks [localAudioTrack, localVideoTrack] = await AgoraRTC.createMicrophoneAndCameraTracks( {}, { encoderConfig: '720p_3' } ); // Play local video localVideoTrack.play('local-video'); // Publish tracks await client.publish([localAudioTrack, localVideoTrack]); // Update UI document.getElementById('join')!.disabled = true; document.getElementById('mute')!.disabled = false; document.getElementById('leave')!.disabled = false; } catch (error) { console.error('Join failed:', error); alert('Join failed: ' + error); } } async function leave() { try { await client.unpublish([localAudioTrack, localVideoTrack]); localAudioTrack.close(); localVideoTrack.close(); await client.leave(); // Reset UI document.getElementById('local-video')!.innerHTML = ''; document.getElementById('remote-container')!.innerHTML = ''; document.getElementById('join')!.disabled = false; document.getElementById('mute')!.disabled = true; document.getElementById('leave')!.disabled = true; } catch (error) { console.error('Leave failed:', error); } } async function toggleMute() { if (localVideoTrack.isMuted) { await localVideoTrack.setEnabled(true); (document.getElementById('mute') as HTMLButtonElement).textContent = 'Mute'; } else { await localVideoTrack.setEnabled(false); (document.getElementById('mute') as HTMLButtonElement).textContent = 'Unmute'; } } // Event listeners document.getElementById('app-id')!.addEventListener('input', (e) => { config.appid = (e.target as HTMLInputElement).value; }); document.getElementById('channel')!.addEventListener('input', (e) => { config.channel = (e.target as HTMLInputElement).value; }); document.getElementById('token')!.addEventListener('input', (e) => { config.token = (e.target as HTMLInputElement).value; }); document.getElementById('join')!.addEventListener('click', join); document.getElementById('leave')!.addEventListener('click', leave); document.getElementById('mute')!.addEventListener('click', toggleMute); // Initialize createClient(); Run & Test npm run dev # Open http://localhost:5173 # Test User1: Join 'test' → See local video # Test User2: Same browser incognito → Join 'test' → See both videos Production Checklist ✅ Vite dev server (HTTPS localhost) ✅ agora-rtc-sdk-ng@4.24.0 (current) ✅ TypeScript + ES modules ✅ Error handling + cleanup ✅ Multi-user remote video grid ✅ Token auth (no uid conflicts) ✅ Responsive design Production Deployment 1. Token Server (Node.js/Agora Token Builder) 2. npm run build → Static hosting 3. HTTPS required (Vercel/Netlify) 4. Scales to 10k+ concurrent calls [web:173]