# How to Use FlutterFlow to Develop a Custom Video Conferencing App

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 45-60 min
- Compatibility: FlutterFlow Free+ (Cloud Functions require Firebase Blaze plan, Agora.io free tier: 10,000 minutes/month)
- Last updated: March 2026

## TL;DR

Integrate Agora.io video calling into FlutterFlow via a Custom Widget that handles WebRTC streams and a Cloud Function that generates secure channel tokens. Store room state in Firestore with participant tracking. Build controls for mute, camera toggle, and screen sharing, with a dynamic grid layout that adapts from one-on-one to multi-participant calls.

## Building a Video Conferencing App with Agora SDK in FlutterFlow

Video conferencing requires real-time media streaming, token-based authentication, and dynamic UI that adapts as participants join or leave. This tutorial uses Agora.io's Flutter SDK wrapped in a Custom Widget, Cloud Functions for secure token generation, and Firestore for room state management.

## Before you start

- A FlutterFlow project with Firestore and Firebase Authentication configured
- An Agora.io account with an App ID and App Certificate from the Agora Console
- Firebase Blaze plan for Cloud Functions deployment
- Agora App Certificate stored in Cloud Function environment config (never on client)

## Step-by-step guide

### 1. Set up the Firestore room model and Cloud Function for token generation

Create a rooms collection with fields: roomId (String, short joinable code), createdBy (Reference to users), participants (Array of user References), status (String: waiting/active/ended), createdAt (Timestamp). Deploy a Cloud Function generateAgoraToken(channelName, uid) that uses the Agora RTC Token Builder with your App Certificate to generate a temporary token valid for 1 hour. Store the App Certificate only in the Cloud Function environment config, never expose it to the client. The function returns the token and the Agora App ID.

**Expected result:** Firestore has a rooms collection for call state, and a Cloud Function securely generates Agora tokens without exposing credentials.

### 2. Build the Custom Widget that initializes Agora and renders video streams

Create a Custom Widget named VideoCallView with parameters: agoraAppId (String), agoraToken (String), channelName (String), localUid (Int). Add the agora_rtc_engine package as a dependency. In initState, create an RtcEngine instance, enable video, set channel profile to communication, and join the channel with the token. Use onUserJoined and onUserOffline callbacks to maintain a local list of remote UIDs. Render the local video with AgoraVideoView(controller: VideoViewController) and each remote video with AgoraVideoView(controller: VideoViewController.remote(uid)). Arrange them in a layout that switches between full-screen for one participant and a GridView for multiple.

**Expected result:** The Custom Widget connects to the Agora channel and displays local and remote video feeds that update as participants join and leave.

### 3. Build the room creation and join flow with Firestore tracking

On the Create Room page, generate a 6-character alphanumeric room code. On tap, create a Firestore room doc with the code, createdBy as the current user, participants array containing the current user, and status waiting. Then call the generateAgoraToken Cloud Function with the room code as channelName. Navigate to the Call page passing the token, appId, and channelName. On the Join Room page, provide a TextField for entering the room code. On tap, query rooms where roomId equals the entered code and status is not ended. If found, add the current user to the participants array, call generateAgoraToken, and navigate to the Call page.

**Expected result:** Users can create rooms with shareable codes or join existing rooms, with Firestore tracking all participants.

### 4. Add mute audio, mute video, camera switch, and end call controls

On the Call page, place the VideoCallView Custom Widget in the center. At the bottom, add a Row of circular IconButtons: microphone (toggle mute), camera (toggle video), camera switch (front/back), and red phone (end call). Create Page State booleans: isMuted and isVideoOff. On microphone tap, toggle isMuted and call the Custom Widget's muteLocalAudioStream method. On camera tap, toggle isVideoOff and call enableLocalVideo. On camera switch, call switchCamera. On end call, leave the Agora channel, remove the current user from the Firestore room participants array, and navigate back. If participants array is empty after removal, update room status to ended.

**Expected result:** Users can mute audio, disable video, switch cameras, and end the call with proper cleanup of Firestore room state.

### 5. Build the dynamic participant grid layout for multi-person calls

Inside the VideoCallView Custom Widget, implement adaptive layout logic. For 1 remote participant: local video as small overlay in top-right corner (Positioned inside a Stack), remote video full-screen. For 2 remote participants: Column with two equal-height video views plus local overlay. For 3 or more: GridView with crossAxisCount of 2, each cell containing a remote video, with the local video occupying one cell. Display participant display names by querying Firestore user docs by UID. Show a subtle name label at the bottom of each video tile. Add a participant count badge in the AppBar.

**Expected result:** The video layout dynamically adapts as participants join or leave, showing an optimal arrangement for any group size.

## Complete code example

File: `FlutterFlow Video Conferencing Setup`

```text
FIRESTORE DATA MODEL:
  rooms/{roomDocId}
    roomId: String (6-char code, e.g., 'XK4M9P')
    createdBy: Reference (users)
    participants: Array of References (users)
    status: String (waiting | active | ended)
    createdAt: Timestamp

CLOUD FUNCTION: generateAgoraToken
  Input: channelName (String), uid (Int)
  Process: RtcTokenBuilder.buildTokenWithUid(
    appId, appCertificate, channelName, uid,
    RtcRole.PUBLISHER, tokenExpireSeconds: 3600
  )
  Returns: { token: '...', appId: '...' }

CUSTOM WIDGET: VideoCallView
  Dependencies: agora_rtc_engine
  Parameters: agoraAppId, agoraToken, channelName, localUid
  Action Parameters: onCallEnded callback
  State: List<int> remoteUids, bool isMuted, bool isVideoOff

PAGE: CreateRoomPage
  Column (center)
    Text "Start a Video Call" (headlineMedium)
    SizedBox(24)
    Button "Create Room"
      On Tap:
        1. Generate 6-char room code
        2. Create Firestore room doc
        3. Call generateAgoraToken Cloud Function
        4. Navigate to CallPage with token + appId + channelName

PAGE: JoinRoomPage
  Column (center)
    Text "Join a Call" (headlineMedium)
    TextField (room code, maxLength: 6, uppercase)
    Button "Join"
      On Tap:
        1. Query room by roomId
        2. Add user to participants array
        3. Call generateAgoraToken
        4. Navigate to CallPage

PAGE: CallPage
  Stack
    VideoCallView (fills screen)
    Positioned (bottom: 32, centerHorizontal)
      Row (mainAxisAlignment: spaceEvenly)
        CircleAvatar IconButton (mic / mic_off) → toggle mute
        CircleAvatar IconButton (videocam / videocam_off) → toggle video
        CircleAvatar IconButton (cameraswitch) → switch camera
        CircleAvatar IconButton (call_end, red) → leave + navigate back

LAYOUT LOGIC (inside VideoCallView):
  if remoteUids.isEmpty → local video full screen + "Waiting..."
  if remoteUids.length == 1 → Stack: remote full + local small overlay
  if remoteUids.length == 2 → Column of 2 remotes + local overlay
  if remoteUids.length >= 3 → GridView(crossAxisCount:2) all videos
```

## Common mistakes

- **Generating Agora tokens on the client side, exposing the App Certificate** — The App Certificate is a secret key. Exposing it in client code lets anyone generate tokens and join any channel in your Agora project. Fix: Always generate tokens in a Cloud Function. Store the App Certificate in the function's environment config. Return only the temporary token to the client.
- **Creating a new RtcEngine instance every time the call page rebuilds** — Multiple engine instances cause audio echo, video flickering, and memory leaks. The Agora SDK expects a single engine instance per call session. Fix: Initialize RtcEngine once in the Custom Widget's initState and dispose it in dispose(). Do not reinitialize on rebuilds.
- **Not cleaning up the Firestore room document when all participants leave** — Orphaned active rooms accumulate in Firestore and could be joined by new users expecting an active call. Fix: On end call, remove the user from participants. If the array becomes empty, set room status to ended. Run a scheduled Cloud Function to clean up rooms stuck in active status for more than 2 hours.

## Best practices

- Store the Agora App Certificate exclusively in Cloud Function environment config, never in client code
- Generate tokens with a 1-hour expiry and refresh them if the call lasts longer
- Use Firestore real-time listeners on the room doc to detect when participants join or leave
- Dispose the Agora RtcEngine in the Custom Widget's dispose method to free camera and microphone resources
- Show a connection quality indicator using Agora's onNetworkQuality callback
- Add a lobby or waiting room screen before joining the actual call so users can check their camera and mic
- Limit maximum participants to 8-12 for communication mode to maintain call quality

## Frequently asked questions

### Do I need to pay for Agora to build a video conferencing app?

Agora offers 10,000 free minutes per month. For a small app or MVP, this is usually sufficient. Beyond that, pricing starts at $0.99 per 1,000 minutes for video calls.

### Can I add screen sharing to the video call?

Yes. Agora supports screen sharing via the startScreenCapture method. Add a screen share IconButton that calls this method. The shared screen appears as a video stream to other participants.

### How do I handle poor network conditions during a call?

Use Agora's onNetworkQuality callback to monitor connection quality. Display a signal strength indicator to the user. If quality degrades, you can programmatically lower video resolution using setVideoEncoderConfiguration.

### Can I record video calls for later playback?

Yes. Agora offers cloud recording as a paid add-on. Trigger recording via Agora's REST API from a Cloud Function when the call starts. The recording is saved to your cloud storage bucket.

### What is the maximum number of participants supported?

Agora communication mode supports up to 17 simultaneous video streams. For larger meetings, switch to Agora's live broadcasting mode where a few hosts broadcast and the audience watches without sending video.

### What if I need help integrating complex video features like recording and breakout rooms?

RapidDev has integrated Agora, 100ms, and custom WebRTC solutions into FlutterFlow apps with features like recording, breakout rooms, virtual backgrounds, and participant management across hundreds of projects.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-use-flutterflow-to-develop-a-custom-video-conferencing-app
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-use-flutterflow-to-develop-a-custom-video-conferencing-app
