DEV Community

Cover image for How to Build a Self-Hosted Zoom-Like App: A Complete Guide
Alexander Samuel
Alexander Samuel

Posted on

How to Build a Self-Hosted Zoom-Like App: A Complete Guide

The modern workplace is all about video calls and real-time chat. But what happens when those meetings require a server you do not own? It raises security concerns and lacks data control.

So, the answer for most enterprises is to build your own communication platform. This helps businesses subject to strict data regulations maintain complete control and avoid relying on a vendor.

This guide shows you how to build a self-hosted app like Zoom, from architecture to features to the tech stack.

What is a Zoom App?

Build a Zoom-Like App

Zoom is a popular video conferencing app that boomed during the pandemic as work from home turned normal. It lets people talk, meet, and work online in HD video and audio.

This tool usually includes meeting rooms, chat rooms, screen sharing, file sharing and more. Think of it as a virtual meeting room that is always open, just without the commute.

Common Pain Points or Challenges Enterprises Face When Using Zoom

In many cases, enterprises using ready-made tools like Zoom hit brick walls. Here are the challenges they face regularly:

  1. Privacy Concerns - Sensitive meeting data is stored on third-party servers that the enterprise has no direct access to.
  2. Rising Subscription Cost - Per-user, per-month pricing gets expensive as teams grow.
  3. Limited Branding - Not all SaaS tools support full white label customization and can be very limited.
  4. Compliance Gaps - Industries like healthcare and finance require higher standards for data handling than generic platforms provide.
  5. Dependency on Third-Party Uptime - When the vendor's servers fail, your business communications go down as well.

Why Build a Self-Hosted Zoom App?

A self-hosted communication tool changes the game entirely. Instead of renting infrastructure, enterprises own it outright. Here's why more businesses are building their own Zoom app:

  1. Full Source Code Ownership - Modify and expand the platform as your business grows.
  2. 100% Data Ownership - Your data stays on your servers, not on the vendors.
  3. Complete White Label - Make it look and feel like your own product, not just a rented tool.
  4. Private Deployment - Host on your own cloud or on-premises infrastructure.
  5. Better Security - You have full control over end-to-end encryption, access and storage.
  6. Deeper Customization - Add/remove features according to your business needs.
  7. No Recurring Cost - Pay a one-time license fee and scale up without additional costs.
  8. Enterprise Integrations - Connect to your existing CRM, HRMS and internal tools.
  9. Better Compliance - You can meet industry standards like HIPAA, SOC 2 or GDPR more easily.
  10. Multi-Tenant Support - Serve multiple business units/clients from a single deployment.
  11. Enterprise-Level Security - Built-in end-to-end encryption and access control.

How Does Custom Zoom App Architecture Work?

Most of these custom video conferencing apps are client-server based with WebRTC for live audio and video, signaling servers for connection coordination, media servers for multi-party calls, and a backend for user authentication, chat and file storage. Combined, these layers allow for low latency meetings.

Custom Zoom App Architecture Work

Top 10 Features of a Custom App Like Zoom

Building a communication app like Zoom for your enterprise is not about video calls, it’s all about creating a complete workspace for your team. Here are the essential features that make a video conferencing tool work for teams.

  1. Team Workspace -Dedicated spaces for departments and projects to collaborate without clutter.
  2. Channels - Organized and topical conversations that are easy to follow and manage.
  3. Direct Messaging - One-to-one chats for instant private conversations.
  4. Voice Calling - When video is not needed, instant audio calls are made using voice calling.
  5. HD Meetings - Crystal clear video conferencing that can handle larger teams.
  6. Screen Sharing - Present documents, slides, product demos and more on your screen in real time.
  7. Calendar - Meetings can be scheduled and managed using a calendar app.
  8. File Sharing - Share documents, images and files in chat or meetings.
  9. Admin Dashboard - Access all your users, permissions and settings from one control panel.
  10. Enterprise Security - SSO, MFA, end-to-end encryption and compliance to protect every conversation.

Recommended Technology Stack

Picking the right stack affects how your app performs in real-life scenarios. Here’s the recommendations for building a scalable and secure video conferencing app:

Recommended Zoom Technology Stack

How To Build An App Like Zoom?
When I was searching for better ways to build a secure messaging app, I found MirrorFly IM solution and Apphitect. Where MirrorFly offered a self-hosted solution with source code access and real-time communication built in.

Let’s see how we developed an app like Zoom for our enterprise using MirrorFly SDK on JAVA.

Step 1: Initial Setup

Install the dependencies and get your license key.

Requirements (Android, iOS, Web):

Android Lollipop 5.0 and above (API Level 21)

Java 7 and above

Gradle 4.1.0 and above

targetSdkVersion / compileSdk 34 and above

Get your license key:

If you’re already a registered user? Find it under Application Info in your account.

If not registered? contact the MirrorFly Team to set up your account.

1. Set up your project - Open a new or existing project in Android Studio.

2. Add the repository

For Gradle 6.8 and above, add to settings.gradle

For Gradle 6.7 or lower, add to root build.gradle
(Check the release notes for Gradle-specific details.)

dependencyResolutionManagement {
   repositories {
       mavenCentral()
       google()
       jcenter()
       maven {
           url "https://repo.mirrorfly.com/release"
       }
   }

}
Enter fullscreen mode Exit fullscreen mode

3. Add dependencies - Add the required dependencies to app/build.gradle file.

dependencies {
  implementation 'com.mirrorfly.sdk:mirrorflysdk:7.13.7'
}
Enter fullscreen mode Exit fullscreen mode

4. Update Gradle properties - Add the specified line to gradle.properties to avoid library conflicts.

android.enableJetifier=truedssdcs
Enter fullscreen mode Exit fullscreen mode

5. Add permissions - Open AndroidManifest.xml and add the required permissions for calls.

6. Initialize the Chat SDK for Calls

Make sure all requirements are met, then call ChatManager inside onCreate() in your Application class to initialize the SDK.

ChatManager.initializeSDK("LICENSE_KEY", (isSuccess, throwable, data) -> {

           if(isSuccess){
               Log.d("TAG", "initializeSDK success ");
           }else {
               Log.d("TAG", "initializeSDK failed with reason "+data.get("message"));
           }
    });
Enter fullscreen mode Exit fullscreen mode

ChatManager initializeSDK Function Description

build zoom like app

Step 2: Add MyApplication

Register the MyApplication class in your AndroidManifest.xml file.

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

   package="com.example.uikitapplication">

<application

       android:name=".MyApplication"  // Add this line.

       android:icon="@mipmap/ic_launcher"

       android:label="@string/app_name"

       android:roundIcon="@mipmap/ic_launcher_round"

       android:theme="@style/AppTheme">

       <activity android:name=".MainActivity">

           <intent-filter>

               <action android:name="android.intent.action.MAIN" />

               ...

               <category android:name="android.intent.category.LAUNCHER" />

           </intent-filter>

       </activity>
   </application>
Enter fullscreen mode Exit fullscreen mode

Step 3: Register User

Register a user in Sandbox or Live mode, depending on your setIsTrialLicenceKey setting.

FlyCore.registerUser(USER_IDENTIFIER, (isSuccess, throwable, data ) -> {

       if(isSuccess) {

           Boolean isNewUser = (Boolean) data.get("is_new_user"); // true - if the current user is different from the previous session's logged-in user, false - if the same user is logging in again

           String userJid = (String) data.get("userJid"); //Ex. 12345678@xmpp-preprod-sandbox.mirrorfly.com (USER_IDENTIFIER+@+domain of the chat server)

           JSONObject responseObject = (JSONObject) data.get("data");

           String username = responseObject.getString("username");

       } else {

          // Register user failed print throwable to find the exception details.
       }
  });

Enter fullscreen mode Exit fullscreen mode

Step 4: Connect To Chat Server

Once registration succeeds, the SDK auto-connects to the chat server and manages the connection based on your app's lifecycle.

Observe Connection Events:

Set ChatConnectionListener to receive connection updates.

ChatManager.setConnectionListener(new ChatConnectionListener() {

   @Override

   public void onConnected() {

       // Write your success logic here to navigate Profile Page or

       // To Start your one-one chat with your friends
   }

@Override

   public void onDisconnected() {

       // Connection disconnected
   }
@Override

   public void onConnectionFailed(@NonNull FlyException e) {

       // Connection Not authorized or Unable to establish connection with server
   }
@Override

   public void onReconnecting() {

       // Automatic reconnection enabled
   }
});
Enter fullscreen mode Exit fullscreen mode

Step 5: Initialize Call SDK

Add the below line inside OnCreate() to initialize the call SDK:

@Override
public void onCreate() {
super.onCreate();

//set your call activity
CallManager.setCallActivityClass(CALL_UI_ACTIVITY.class);
CallManager.setMissedCallListener((isOneToOneCall, userJid, groupId, callType, userList,CallMetaData[] callMetaDataArray) -> {
  //show missed call notification
});

CallManager.setCallHelper(new CallHelper() {
    @NonNull
    @Override
    public String getNotificationContent(@NonNull String callDirection,CallMetaData[] callMetaDataArray) {
        return CallNotificationHelper.getNotificationMessage();
    }

  });

CallManager.setCallNameHelper(new CallNameHelper() {
    @NonNull
    @Override
    public String getDisplayName(@NonNull String jid,CallMetaData[] callMetaDataArray) {
        return ContactManager.getDisplayName(jid);
    }
  });
}

Enter fullscreen mode Exit fullscreen mode

Setup your call activity

Add this to OnCreate() to configure call activity

<activity
            android:name="YOUR_CALL_ACTIVITY"
            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
            android:excludeFromRecents="true"
            android:launchMode="singleTask"
            android:resizeableActivity="false"
            android:screenOrientation="portrait"
            android:supportsPictureInPicture="true"
            android:showOnLockScreen="true"
            android:turnScreenOn="true"
            android:taskAffinity="call.video"
            tools:targetApi="o_mr1" />
Enter fullscreen mode Exit fullscreen mode
CallManager.configureCallActivity(ACTIVITY);
Enter fullscreen mode Exit fullscreen mode

To remove the ongoing call notification, add this to onStart()

CallManager.bindCallService();
Enter fullscreen mode Exit fullscreen mode

Add this to show the ongoing call notification

CallManager.unbindCallService();
Enter fullscreen mode Exit fullscreen mode

Now generate User JID, using the following code

FlyUtils.getJid(USER_NAME)
Enter fullscreen mode Exit fullscreen mode

Step 6: Making a Audio call

Required runtime permissions for audio Call

Manifest.permission.RECORD_AUDIO
Manifest.permission.READ_PHONE_STATE
Enter fullscreen mode Exit fullscreen mode

Check audio call permissions

 CallManager.isAudioCallPermissionsGranted();
Enter fullscreen mode Exit fullscreen mode

Add below permission to show ongoing call notification

Manifest.permission.POST_NOTIFICATIONS

Enter fullscreen mode Exit fullscreen mode

Make a Voice Call

Allow users to make one-to-one audio call with call metadata.

 CallManager.makeVoiceCall("TO_JID",CALL_METADATA, (isSuccess, flyException) -> {
            if(isSuccess){
                //SDK will take care of presenting the Call UI. It will present the activity that is passed using the method `CallManager.setCallActivityClass()`
                Log.d("MakeCall","call success");
            }else{
                if(flyException!=null){
                    String errorMessage = flyException.getMessage();
                    Log.d("MakeCall","Call failed with error: "+errorMessage);
                    //toast error message
                }
            }
        });
Enter fullscreen mode Exit fullscreen mode

Make a Group Voice Call

Allow users to make group video calls with call metadata.

CallManager.makeGroupVoiceCall(JID_LIST, GROUP_ID,CALL_METADATA, new CallActionListener() {
            @Override
            public void onResponse(boolean isSuccess, @Nullable FlyException flyException) {
                if (isSuccess) {
                    //SDK will take care of presenting the Call UI. It will present the activity that is passed using the method `CallManager.setCallActivityClass()`
                    Log.d("MakeCall", "call success");
                } else {
                    if (flyException != null) {
                        String errorMessage = flyException.getMessage();
                        Log.d("MakeCall", "Call failed with error: " + errorMessage);
                        //toast error message
                    }
                }
            }
        });
Enter fullscreen mode Exit fullscreen mode

Step 8: Adding Other Calling Features

Add participants to the call

Using the below method, you can enable to add users to the ongoing calls.

CallManager.inviteUsersToOngoingCall(JID_LIST, new CallActionListener() {
            @Override
            public void onResponse(boolean isSuccess, @Nullable FlyException flyException) {

            }
        });
Enter fullscreen mode Exit fullscreen mode

Answer the incoming call

Add the below method, so whenever the user presses the accept button from your call UI it answers the call and notifies the caller.

  CallManager.answerCall((isSuccess, flyException) -> {
            if(isSuccess){
                Log.d("AnswerCall","call answered success");
            }else{
                if(flyException!=null){
                    String errorMessage = flyException.getMessage();
                    Log.d("AnswerCall","Call answered failed with error: "+errorMessage);
                    //toast error message
                }
            }
        });
Enter fullscreen mode Exit fullscreen mode

Decline the incoming call

Add the method below to decline the incoming call.

  CallManager.declineCall();
Enter fullscreen mode Exit fullscreen mode

Disconnect the ongoing call

Add the below method to disconnect the ongoing call.

  CallManager.disconnectCall();
Enter fullscreen mode Exit fullscreen mode

Step 9: Send/Receive Message

How to Send a One-to-One Message

Use the provided code to send a one-to-one text message.

TextMessage textMessage = new TextMessage();

textMessage.setToId(TO_JID);

textMessage.setMessageText(TEXT);

FlyMessenger.sendTextMessage(textMessage, (isSuccess, error, chatMessage) -> {

   if (isSuccess) {

       // you will get the message sent success response
   }
});
Enter fullscreen mode Exit fullscreen mode

How to Receive A One-to-One Message

Set up MessageEventsListener to receive and observe incoming messages.

ChatEventsManager.setupMessageEventListener(new MessageEventsListener() {

           @Override

           public void onMessageReceived(@NotNull ChatMessage message) {

             //called when a new message is received
           }
 });
Enter fullscreen mode Exit fullscreen mode

That's it, your chat app can now send and receive messages. From here, you can add more chat features as needed.

Final Verdict

No longer do enterprises have to choose between convenience and control. With the right chat SDK, enterprises can build their own Zoom app that is secure, branded and tailored to your workflow, all without recurring subscription fees or compliance headaches

Top comments (0)