Powered by Chatlivo Flutter VoIP Incoming Call Screen — iOS CallKit & Android
Primocys Logo

How to Show the Native Incoming Call Screen for VoIP Calls in Flutter Apps (iOS CallKit + Android ConnectionService)

Date 10 Jul, 2026
Share:
flutter voip app development company

When a Flutter VoIP incoming call arrives, your users expect the same full-screen native ring UI as a regular phone call — even when the app is killed. This is the complete implementation guide covering iOS CallKit with PushKit and Android ConnectionService with FCM, exactly how Primocys built it in WasaaChat and ChatWave.

What this guide covers The native incoming call screen — the one that looks exactly like a regular phone call — requires iOS CallKit + PushKit on Apple and ConnectionService / Telecom API + FCM data message on Android. A normal push notification is not enough on either platform: on iOS, VoIP push via PushKit wakes a killed app; on Android, an FCM data message (not notification message) fires the background service. The recommended Flutter package is flutter_callkit_incoming — it handles both platforms behind one Dart API. This guide covers the full stack: server-side push setup, native platform config, Dart event handling, custom ringtone, and the iOS 13 rule that crashes your app if you miss it. Built by Primocys — Flutter Top Developer 2024 & 2026 →

Most chat or VoIP apps handle calls inside the app perfectly — a custom flutter voip incoming call screen, nice animations, proper WebRTC media. The problem comes when the app is in the background or completely killed. The user’s phone rings silently (or not at all), they miss the call, and they blame the app. Solving this correctly on both iOS and Android requires integrating directly with each platform’s native telephony framework.

Primocys has implemented the flutter voip incoming call screen in production for WasaaChat and ChatWave — both live on the App Store and Google Play, both with full VoIP calling using self-hosted WebRTC. This guide covers exactly what we built, the mistakes we initially made, and the code that ended up in production.

iOS 10+
CallKit minimum supported version
Android 6+
ConnectionService (API 23+)
iOS 13
Report Before Completion
FCM data
Wake Android When Killed
.caf
iOS custom ringtone format

iOS CallKit vs Android ConnectionService — VoIP Architecture Overview

The ios callkit flutter implementation and Android ConnectionService are fundamentally different architectures — they need to be understood separately before you can implement them together in a Flutter VoIP app.

iOS — CallKit + PushKit iOS 10+

    • Push type — VoIP push via PushKit (PKPushType.voIP)
    • UI framework — CallKit — CXProvider shows native lock screen
    • When killed — PushKit wakes app, must call reportNewIncomingCall immediately
    • iOS 13 rule — MUST report call before completion() or OS kills app
    • Ringtone — config.ringtoneSound = “ring.caf”
    • China — CallKit banned — need fallback for CN App Store
Android — ConnectionService + FCM API 23+

  • Push type — FCM data message (NOT notification message)
  • UI framework — Telecom ConnectionService or full-screen intent
  • When killed — FCM data message fires background service isolate
  • Android 14+ — USE_FULL_SCREEN_INTENT requires runtime permission
  • Ringtone — File in android/app/src/main/res/raw/
  • OEMs — Xiaomi/OnePlus may kill background — guide users to whitelist

VoIP Push Notification Flutter — Full Signal Flow to Native Ring Screen

Most Flutter VoIP implementations break at the same step. This is the complete signal flow — server to APNs/FCM to PushKit/background isolate to native ring screen.

IOS VOIP CALL FLOW

Your Server

Sends VoIP push

APNs (VoIP cert)

PushKit push type

PushKit wakes app

Even if killed

reportNewIncomingCall

BEFORE completion()

Native CallKit UI

Lock screen ring

Dart event

onAccept / onDecline

ANDROID VOIP CALL FLOW

Your Server

FCM data message

FCM data payload

“data” key only

Background isolate

Fires even if killed

Foreground service

+ ConnectionService

Native call UI

Full-screen ring

Dart event

onAccept / onDecline

Why a regular push notification will not work: A standard APNs push on iOS shows a banner notification — it does not wake a killed app or display the native call UI. Only a PushKit VoIP push (voip push type with a separate VoIP certificate) wakes the app and lets CallKit display the lock screen. On Android, a standard FCM notification message also doesn’t reliably wake a killed app on modern Android versions with battery optimization. Only an FCM
data message
fires the background handler. This distinction — VoIP push on iOS, data message on Android — is the single most common reason VoIP calls fail to ring when the app is killed.

Flutter Callkit Incoming Package — Choosing the Right One

The wrong VoIP package choice breaks incoming calls on killed apps. Here’s how flutter_callkit_incoming, flutter_callkeep, and webtrit_callkeep actually differ in production.

RECOMMENDED

flutter_callkit_incoming

pub.dev · Most popular · Actively maintained

Full-featured: iOS CallKit, Android full-screen UI and ConnectionService, PushKit support in AppDelegate, custom ringtones, avatars, missed call notifications. Works with any VoIP backend (WebRTC, Agora, Twilio).

UNIFIED API

flutter_callkeep

pub.dev · Unified Dart API

Wraps iOS CallKit and Android ConnectionService behind one Dart interface. Simpler API than flutter_callkit_incoming, good for apps that need both incoming and outgoing system call integration.

PRODUCTION GRADE

webtrit_callkeep

pub.dev · Production VoIP phone apps

Production-grade federated plugin used in real VoIP phone apps. Kotlin/Swift native, dedicated background process on Android, PushKit on iOS. Higher complexity, deeper OS integration.

For this guide we use flutter_callkit_incoming — it covers 95% of real-world flutter voip app development use cases with the least native code you need to write yourself.

Step 1 — Add the Package

pubspec.yaml YAML
# pubspec.yaml — add to dependencies
dependencies:
  flutter:
    sdk: flutter

  flutter_callkit_incoming: ^2.0.1    # latest stable

  firebase_core: ^3.0.0               # for FCM on Android

  firebase_messaging: ^15.0.0          # FCM data messages

  uuid: ^4.0.0                         # for generating call UUIDs

Step 2 — Build the ZPL label string

2a — Add Background Modes in Xcode In Xcode: select Runner → Signing & Capabilities → + Capability → Background Modes. Enable: Voice over IP, Remote notifications, and Background fetch. Or add directly to Info.plist:

ios/Runner/Info.plist XML
<!— Add inside the root <dict> —>

<key>UIBackgroundModes</key>
<array>
  <string>voip</string>
  <string>remote-notification</string>
  <string>processing</string>
</array>

2b — PushKit VoIP Flutter iOS — AppDelegate.swift

ios/Runner/AppDelegate.swift Swift
import UIKit
import Flutter
import PushKit
import CallKit
import flutter_callkit_incoming

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, PKPushRegistryDelegate,
                            CallkitIncomingAppDelegate {

  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) → Bool {
    GeneratedPluginRegistrant.register(with: self)

    // Register for VoIP push notifications via PushKit
    let mainQueue = DispatchQueue.main
    let voipRegistry = PKPushRegistry(queue: mainQueue)
    voipRegistry.delegate = self
    voipRegistry.desiredPushTypes = [PKPushType.voIP]

    return super.application(application,
                didFinishLaunchingWithOptions: launchOptions)
  }

  // Called when PushKit delivers a new VoIP token
  func pushRegistry(_ registry: PKPushRegistry,
                  didUpdate credentials: PKPushCredentials,
                  for type: PKPushType) {
    let deviceToken = credentials.token
                      .map { String(format: "%02x", $0) }
                      .joined()
    // Send this token to your server — it's what you push to
    SwiftFlutterCallkitIncomingPlugin.sharedInstance?
      .setDevicePushTokenVoIP(deviceToken)
  }

  // ⚠️ iOS 13+ CRITICAL: Called when VoIP push arrives — app may be killed
  func pushRegistry(_ registry: PKPushRegistry,
                  didReceiveIncomingPushWith payload: PKPushPayload,
                  for type: PKPushType,
                  withCompletionHandler completion: @escaping () → Void) {
    let dict = payload.dictionaryPayload

    // Extract call data from push payload
    var data = flutter_callkit_incoming.Data(
      id: dict["uuid"] as? String ?? UUID().uuidString,
      nameCaller: dict["caller_name"] as? String ?? "Unknown",
      handle: dict["caller_number"] as? String ?? "",
      type: 0  // 0 = audio, 1 = video
    )
    data.appName = "WasaaChat"
    data.avatar = dict["caller_avatar"] as? String

    // MUST call this BEFORE completion() — iOS 13+ requirement
    SwiftFlutterCallkitIncomingPlugin.sharedInstance?
      .showCallkitIncoming(data, fromPushKit: true)

    // Completion can be called after (small delay is acceptable)
    DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
      completion()
    }
  }
}

⚠️ The iOS 13 Rule — This Will Crash Your App if Missed Since iOS 13, if your app receives a PushKit VoIP push and does not immediately report a new incoming call to CallKit (via reportNewIncomingCall() or the equivalent plugin method), iOS will terminate your app and invalidate your VoIP push token. You will then stop receiving VoIP pushes entirely until the token is refreshed. Always call showCallkitIncoming(data, fromPushKit: true) synchronously inside didReceiveIncomingPushWithPayload, before the completion() handler.

2c — Custom Ringtone on iOS

Add your ringtone file (must be .caf format) to the Xcode project under ios/Runner/. Convert from MP3 or WAV using: afconvert -f caff -d LEI16 ringtone.mp3 ringtone.caf. Then reference it in the call data:

AppDelegate.swift — ringtone Swift
// After creating the Data object, set the ringtone name (without .caf)
data.ringtoneSound = "custom_ring"  // looks for custom_ring.caf in bundle

// If ringtoneSound is nil or not found, iOS uses the system default ring

Step 3 — Android ConnectionService Flutter VoIP (Manifest + Permissions)

android/app/src/main/AndroidManifest.xml XML
<!— Permissions required for VoIP call screen —>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL"/>
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

<!— Inside <application> tag — register the plugin service —>
<service
  android:name="com.hiennv.flutter_callkit_incoming.CallkitIncomingService"
  android:exported="false"
  android:foregroundServiceType="phoneCall"/>

Android 14+ Runtime Permission

main.dart — request permission Dart
import 'package:permission_handler/permission_handler.dart';

// Android 14+ requires explicit permission for full-screen intents
Future<void> requestCallPermissions() async {
  if (Platform.isAndroid) {
    await [
      Permission.phone,
      Permission.microphone,
      Permission.notification,
    ].request();
  }
}

Custom Ringtone on Android

Place your ringtone audio file in android/app/src/main/res/raw/custom_ring.mp3 (or .ogg). Reference it by filename without extension in the Dart code below.

Step 4 — Dart Implementation (The Core Logic)

lib/services/voip_service.dart Dart
import 'dart:io';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:uuid/uuid.dart';

class VoIPService {
  static final Uuid _uuid = const Uuid();

  /// Call this from main() or your FCM background message handler
  static Future<void> showIncomingCall({
    required String callerName,
    required String callerNumber,
    String? callerAvatar,
    String? callUuid,
    bool isVideo = false,
  }) async {
    final uuid = callUuid ?? _uuid.v4();

    final params = CallKitParams(
      id: uuid,
      nameCaller: callerName,
      handle: callerNumber,
      avatar: callerAvatar,
      type: isVideo ? 1 : 0,    // 0 = audio, 1 = video
      textAccept: 'Accept',
      textDecline: 'Decline',
      duration: 30000,           // 30 seconds ring timeout

      // Missed call notification (shown if user doesn't answer)
      missedCallNotification: const NotificationParams(
        showNotification: true,
        isShowCallback: true,
        subtitle: 'Missed call',
        callbackText: 'Call back',
      ),

      // Android-specific params
      android: const AndroidParams(
        isCustomNotification: true,
        isShowLogo: false,
        ringtonePath: 'system_ringtone_default', // or 'custom_ring' from res/raw/
        backgroundColor: '#0a0e1e',
        actionColor: '#6d28d9',
        textColor: '#ffffff',
        incomingCallNotificationChannelName: 'Incoming Call',
      ),

      // iOS-specific params
      ios: const IOSParams(
        iconTemplateImageAssetName: 'CallKitLogo',  // 40x40 asset catalog
        handleType: 'generic',
        supportsVideo: true,
        maximumCallGroups: 2,
        maximumCallsPerCallGroup: 1,
        ringtonePath: 'custom_ring',   // .caf file without extension
      ),
    );

    await FlutterCallkitIncoming.showCallkitIncoming(params);
  }

  /// Dismiss the call screen (e.g., when remote hangs up)
  static Future<void> endCall(String uuid) async {
    await FlutterCallkitIncoming.endCall(uuid);
  }

  static void listenForEvents({
    required Function(String uuid) onAccept,
    required Function(String uuid) onDecline,
    required Function(String uuid) onEnded,
  }) {
    FlutterCallkitIncoming.onEvent.listen((event) {
      final uuid = event?.body['id'] as String? ?? '';
      switch (event!.event) {
        case Event.actionCallAccept:
          onAccept(uuid);         // User tapped green button
          break;
        case Event.actionCallDecline:
          onDecline(uuid);        // User tapped red button
          break;
        case Event.actionCallEnded:
          onEnded(uuid);          // Call ended or timed out
          break;
        default:
          break;
      }
    });
  }
}

Building a Flutter VoIP App Like WhatsApp?

We’ve built this in production — WasaaChat and ChatWave both run this exact CallKit + ConnectionService stack with self-hosted WebRTC. If you’d rather hire Flutter VoIP developers than implement it yourself, talk to us.

Step 5 — FCM VoIP Incoming Call Android Flutter When App Is Killed

On Android, when the app is completely terminated, the FCM push must be received by a background isolate. This is where many implementations break — the regular onMessage handler only fires when the app is in the foreground.

lib/main.dart Dart
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';

// ⚠️ Must be a TOP-LEVEL function (not inside a class)
// This runs in a SEPARATE ISOLATE when the app is killed
@pragma('vm:entry-point')
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // data message from server triggers this even when app is killed
  if (message.data['type'] == 'incoming_call') {
    await VoIPService.showIncomingCall(
      callerName: message.data['caller_name'] ?? 'Unknown',
      callerNumber: message.data['caller_number'] ?? '',
      callerAvatar: message.data['caller_avatar'],
      callUuid: message.data['uuid'],
      isVideo: message.data['is_video'] == 'true',
    );
  }
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  // Register background handler BEFORE runApp
  FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);

  // Also listen for foreground messages
  FirebaseMessaging.onMessage.listen((message) {
    if (message.data['type'] == 'incoming_call') {
      VoIPService.showIncomingCall(
        callerName: message.data['caller_name'] ?? 'Unknown',
        callerNumber: message.data['caller_number'] ?? '',
        callUuid: message.data['uuid'],
      );
    }
  });

  runApp(const MyApp());
}

Step 6 — Server-Side Push Format

The push payload format matters. Send a data-only message on Android (no notification key at root), and a VoIP push on iOS (sent to voip topic with your VoIP certificate, not your regular APNs cert).

server — FCM payload (Android) JSON
{
  "to": "<FCM_DEVICE_TOKEN>",
  // ⚠️ No "notification" key — data-only wakes killed app
  "data": {
    "type": "incoming_call",
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "caller_name": "Alex Morgan",
    "caller_number": "+1234567890",
    "caller_avatar": "https://example.com/avatar.jpg",
    "is_video": "false"
  },
  "priority": "high",           // CRITICAL — must be high for background
  "android": {
    "priority": "high"
  }
}
server — APNs VoIP push (iOS, Node.js example) JavaScript
// Using @parse/node-apn or similar library
const notification = new apn.Notification();
notification.topic = `com.yourapp.voip`;   // .voip suffix for PushKit
notification.pushType = "voip";              // PushKit push type
notification.priority = 10;                 // Immediate delivery
notification.expiry = Math.floor(Date.now() / 1000) + 30;
notification.payload = {
  uuid: "550e8400-e29b-41d4-a716-446655440000",
  caller_name: "Alex Morgan",
  caller_number: "+1234567890",
  caller_avatar: "https://example.com/avatar.jpg",
};
// Must use VoIP certificate, NOT standard APNs push cert

Step 7 — Wire Into Your App and Connect WebRTC

lib/screens/home_screen.dart Dart
class HomeScreen extends StatefulWidget {
  @override
  void initState() {
    super.initState();

    // Listen for call events from both platforms
    VoIPService.listenForEvents(
      onAccept: (uuid) {
        // User tapped Accept — connect your WebRTC session
        context.read<CallBloc>().add(AcceptCall(uuid: uuid));
        Navigator.pushNamed(context, '/call-screen',
          arguments: {'uuid': uuid});
      },
      onDecline: (uuid) {
        // User tapped Decline — send reject signal to server
        context.read<CallBloc>().add(RejectCall(uuid: uuid));
      },
      onEnded: (uuid) {
        // Call timed out or was dismissed — clean up
        context.read<CallBloc>().add(EndCall(uuid: uuid));
      },
    );

    // Check if app was launched from a call notification (killed state)
    _checkForActiveCallOnLaunch();
  }
}

Future<void> _checkForActiveCallOnLaunch() async {
  // Get any call that was waiting when app was killed
  final calls = await FlutterCallkitIncoming.activeCalls();
  if (calls.isNotEmpty) {
    final activeCall = calls.first;
    // Navigate to in-call screen or re-show incoming screen
  }
}

What It Looks Like — iOS & Android VoIP Demo

One video showing both platforms — iOS CallKit lock screen and Android native incoming call UI, exactly as users see it in WasaaChat.

IOS vs Android

iOS CallKit + Android — Live Demo

Play iOS Demo

CallKit Flutter Killed App — Common Issues & Fixes

Symptom Platform Cause Fix
No ring when app killed iOS Using APNs instead of PushKit Send to .voip topic with VoIP cert
App crash on VoIP push iOS 13+ completion() called before reportNewIncomingCall Call showCallkitIncoming FIRST, then call completion()
No ring when app killed Android Sending notification message instead of data message Remove “notification” key — only send “data”
Call screen not full screen Android Missing USE_FULL_SCREEN_INTENT permission Add permission + request runtime on Android 14+
Calls not ringing on Xiaomi Android OEM kills background services Guide users to grant Autostart permission for app
Custom ringtone not playing iOS File is not .caf format Convert with afconvert to CAF format
VoIP token not refreshing iOS App crashed on previous push (iOS 13 rule) Fix the crash → new token auto-generates on next launch
CallKit banned in China iOS CN Apple blocks CallKit in Chinese App Store Detect locale + fallback to FCM notification for CN users

“The native call screen is not just a UI preference — it’s the difference between users answering your VoIP calls and missing them. PushKit on iOS and FCM data messages on Android are the only mechanisms that wake a killed app reliably. Everything else is a workaround that breaks under real-world battery conditions.”

Primocys · Flutter VoIP App Development

We’ve Built This in Production — WasaaChat & ChatWave, Live on Both Stores

This guide describes exactly what Primocys implemented in WasaaChat and ChatWave — two live Flutter messaging apps on both the App Store and Google Play with self-hosted WebRTC and native VoIP call screens. If you need a Flutter developer who has shipped this code to real users, that’s us.

Live apps, not mockups

WasaaChat + ChatWave on App Store + Google Play. Download and test before hiring.

Self-hosted WebRTC

Zero per-minute API fees. Your own servers. Our production architecture.

Full VoIP stack

CallKit, PushKit, ConnectionService, FCM — all implemented and tested on real devices.

Flutter Top Developer

Clutch Top Flutter Developer 2024 & 2026. One codebase, both stores.

Fixed-price contracts

Full scope agreed before development starts. No hourly surprises.

E2E encryption

Signal Protocol built into WasaaChat. Same stack available for your app.

Conclusion: Flutter VoIP App Development Company India — Built in Production

Getting the flutter voip incoming call screen right on both iOS and Android is genuinely one of the harder cross-platform implementations in mobile development — not because the logic is complex, but because the platform requirements are strict, underdocumented, and punishing when you get them wrong. The iOS 13 rule alone (report the call to CallKit before calling completion, every single time) has broken production apps that shipped without it. The FCM data-vs-notification distinction on Android has caused more “why doesn’t it ring when the app is killed” support tickets than any other single mistake.

This is the implementation Primocys runs in production on WasaaChat and ChatWave — real apps, real users, real devices. If you’re building a flutter voip app like WhatsApp or a real-time calling platform and you’d rather hire Flutter VoIP developers who’ve already solved these problems in production than solve them yourself, that’s exactly what we do. India-based Flutter VoIP development delivers the same CallKit, ConnectionService, and self-hosted WebRTC architecture at 60–70% lower cost than US agencies.

The single most common reason VoIP calls don’t ring when the app is killed: On iOS: you’re using a regular APNs push instead of a PushKit VoIP push. On Android: you’re using an FCM notification message instead of an FCM data message. Fix both of those and 80% of “it doesn’t ring when killed” bugs resolve immediately. The remaining 20% are OEM-specific battery optimization issues on Xiaomi, OnePlus, and Samsung that require user-side whitelisting. Need help? Talk to our Flutter VoIP team →

FAQs: Flutter VoIP Incoming Call Screen — iOS CallKit & Android

How do I show the native incoming call screen in a Flutter VoIP app on iOS?
On iOS, showing the native flutter voip incoming call screen requires the CallKit framework combined with PushKit for VoIP push notifications. When your server sends a VoIP push to the device via APNs with the voip push type certificate, PushKit wakes your app even if it is terminated, and your AppDelegate receives the push in didReceiveIncomingPushWithPayload. Inside that delegate method, you must immediately call provider.reportNewIncomingCall() before calling the completion handler — iOS 13+ requires this or the OS will kill your app for not handling the push promptly. The CXProvider then displays the native iOS incoming call UI identical to a regular phone call.
How do I show the native Android call screen for VoIP in Flutter?
On Android, VoIP calling uses the Telecom ConnectionService API (Android 6.0+). When your server sends an FCM data message, a background service wakes the app—even if it’s terminated—and calls TelecomManager.addNewIncomingCall() to display the native incoming call screen. FCM notification messages are not reliable for waking terminated apps, so data messages are required.
What is the best Flutter package for VoIP incoming call screens in 2026?
The best Flutter CallKit package in 2026 is flutter_callkit_incoming. It supports iOS CallKit and PushKit, Android full-screen incoming calls, custom ringtones, caller avatars, missed call notifications, and a unified Dart event API. For advanced Telecom API integration with outgoing calls, webtrit_callkeep is a strong production-grade alternative, while flutter_callkeep offers a simpler setup.
Why does my Flutter VoIP call not ring when the app is killed on iOS?
If your Flutter VoIP app doesn’t show the incoming call screen when killed on iOS, you’re likely using regular APNs instead of PushKit VoIP notifications. Register for PKPushType.voIP, send VoIP pushes, and report the call to CallKit immediately using reportNewIncomingCall(). Delays can cause iOS to terminate the app and invalidate the VoIP push token.
Can I hire Flutter VoIP developers from India to build a WhatsApp-like calling app?
Yes. An India-based Flutter VoIP app development company can deliver iOS CallKit, Android ConnectionService, and self-hosted WebRTC solutions at 60–70% lower cost than many US agencies. Primocys is a Clutch Top Flutter Developer (2024 & 2026) with live VoIP apps in production, offering fixed-price development, full source code ownership, and no ongoing licensing fees. Get a free VoIP app development estimate →

Need a Flutter Developer Who’s Done This in Production?

ownload WasaaChat from the App Store. That’s our VoIP implementation running on a real device, with real users. Then let’s talk about building yours.

Arpan Sagar
Arpan Sagar
Arpan leads product and engineering at Primocys, a Top-Rated Clutch app development company based in Ahmedabad, India. With over 10+ years of experience, he has successfully delivered real-time communication platforms for 1,200+ clients worldwide. He is directly involved in overseeing the development of chat and messaging applications, ensuring high performance, scalability, and seamless user experience in every project. 📧 Email: [email protected] 📱 WhatsApp: Chat on WhatsApp

Build your scalable apps today.

Contact Us
Talk to an Expert