WhatsApp Mirror — Full-Stack Real-Time Bridge

A production-grade, highly-responsive WhatsApp Mirror application. This system allows you to remotely view and manage a WhatsApp account on a dark-themed Flutter mobile app (iOS + Android) by bridging commands and real-time events over a standalone WebSockets Node.js bridge server.


🏗️ Architecture

📱 Mobile Client (Flutter) ⚡ [WebSockets Protocol] ⚡ 🖥️ standalone Backend Server (Node.js) ⚙️ [Puppeteer] ⚙️ 🟩 WhatsApp Web (LocalAuth Session)

📂 Project Structure

whatsapp-app/
├── README.md               ← Full system configuration & documentation
├── whatsapp_bridge/        ← standalone Node.js server
│   ├── package.json        ← Package dependencies (whatsapp-web.js, ws, qrcode, express)
│   ├── server.js           ← Bridge server entrypoint (Port 3025)
│   └── .wwebjs_auth/       ← Session persistence auth cache (git-ignored)
└── whatsapp_app/           ← Dark-themed Flutter Client
    ├── pubspec.yaml        ← Flutter configuration and plugins
    └── lib/
        ├── main.dart       ← Flutter app entry point (GetX service initializer)
        ├── config/
        │   └── app_config.dart     ← Server host & port variables
        ├── theme/
        │   └── app_theme.dart      ← WhatsApp-style immersive Dark Theme
        ├── services/
        │   └── whatsapp_service.dart ← Websocket request/response manager
        ├── models/
        │   ├── conversation_model.dart
        │   └── message_model.dart
        ├── controllers/
        │   ├── conversations_controller.dart
        │   └── chat_controller.dart
        ├── screens/
        │   ├── conversations_screen.dart
        │   ├── chat_screen.dart
        │   └── qr_screen.dart
        └── widgets/
            ├── conversation_tile.dart
            └── message_bubble.dart

WebSockets Protocol Specification

To handle asynchronous requests and map them back to specific UI components or triggers, a strict Request-Response ID matching mechanism is implemented.

1. Client-to-Server Requests

Every request from the Flutter client MUST contain a unique requestId. The server replies with the exact same requestId.

A. Ping Check (ping)

  • Request:
    { "type": "ping", "requestId": "1" }
    
  • Response:
    { "type": "pong", "ready": true, "requestId": "1" }
    

B. Get Conversation List (get_conversations)

  • Request:
    { "type": "get_conversations", "limit": 50, "offset": 0, "requestId": "2" }
    
  • Response:
    {
      "type": "conversations",
      "data": [
        {
          "id": "1234567890@c.us",
          "name": "Jane Doe",
          "isGroup": false,
          "unreadCount": 2,
          "avatar": "https://pps.whatsapp.net/v/...",
          "lastMessage": {
            "body": "Hello there!",
            "timestamp": 1716035000,
            "fromMe": false,
            "hasMedia": false
          },
          "timestamp": 1716035000,
          "pinned": false,
          "isMuted": false
        }
      ],
      "total": 1,
      "requestId": "2"
    }
    

C. Get Message History (get_messages)

  • Request:
    { "type": "get_messages", "chatId": "1234567890@c.us", "limit": 50, "requestId": "3" }
    
  • Response:
    {
      "type": "messages",
      "chatId": "1234567890@c.us",
      "data": [
        {
          "id": "true_1234567890@c.us_ABC123",
          "body": "Hello there!",
          "fromMe": false,
          "timestamp": 1716035000,
          "type": "chat",
          "hasMedia": false,
          "isForwarded": false,
          "author": null,
          "ack": 4
        }
      ],
      "requestId": "3"
    }
    

D. Send Message (send_message)

  • Request:
    { "type": "send_message", "chatId": "1234567890@c.us", "text": "Hello!", "requestId": "4" }
    
  • Response:
    {
      "type": "message_sent",
      "chatId": "1234567890@c.us",
      "data": {
        "id": "true_1234567890@c.us_XYZ987",
        "body": "Hello!",
        "fromMe": true,
        "timestamp": 1716035005,
        "type": "chat",
        "hasMedia": false,
        "isForwarded": false,
        "author": null,
        "ack": 1
      },
      "requestId": "4"
    }
    

E. Mark Chat as Read (mark_read)

  • Request:
    { "type": "mark_read", "chatId": "1234567890@c.us", "requestId": "5" }
    
  • Response:
    { "type": "marked_read", "chatId": "1234567890@c.us", "requestId": "5" }
    

F. Search Conversations (search_conversations)

  • Request:
    { "type": "search_conversations", "query": "Jane", "requestId": "6" }
    
  • Response:
    {
      "type": "conversations",
      "data": [...],
      "search": true,
      "requestId": "6"
    }
    

2. Server-to-Client Push Events

The server broadcasts live events to all connected clients immediately.

  • QR Code Broadcast:
    { "type": "qr", "qr": "data:image/png;base64,iVBORw0KGgo..." }
    
  • Authenticated:
    { "type": "authenticated" }
    
  • Client Ready:
    { "type": "ready" }
    
  • Status Updates:
    { "type": "status", "ready": true }
    
  • Client Disconnected:
    { "type": "disconnected", "reason": "Session expired or logged out" }
    
  • New Incoming Message:
    {
      "type": "new_message",
      "chatId": "1234567890@c.us",
      "data": {
        "id": "false_1234567890@c.us_DEF456",
        "body": "Live incoming text!",
        "fromMe": false,
        "timestamp": 1716035100,
        "type": "chat",
        "hasMedia": false,
        "isForwarded": false,
        "author": null,
        "ack": 2
      }
    }
    
  • Message Delivery / Read Receipt (message_ack):
    {
      "type": "message_ack",
      "messageId": "true_1234567890@c.us_XYZ987",
      "chatId": "1234567890@c.us",
      "ack": 4
    }
    
    (Ack codes: 0 = Error/None, 1 = Pending, 2 = Sent, 3 = Delivered, 4 = Read)

🚀 Quick Setup & Installation

1. Server Setup (whatsapp_bridge/)

Navigate into the backend project, install dependencies, and start the standalone service:

cd whatsapp_bridge
npm install
node server.js

The server will boot up and bind to Port 3025. It will automatically print: [SERVER] Standalone WhatsApp Bridge running on port 3025

2. Flutter App Setup (whatsapp_app/)

First, ensure that you have created the Flutter project structure using standard platform templates:

# Run this inside the workspace directory
flutter create whatsapp_app

Then, copy all files in whatsapp_app/ into the newly created project folder. Open the folder and install Dart packages:

cd whatsapp_app
flutter pub get

Run on Simulator / Device

flutter run

🌐 Production Deployment (CloudPanel Server)

Since this backend server acts as a standalone daemon and does not conflict with existing apps, it operates exclusively on Port 3025.

1. Create Node.js Site in CloudPanel

  1. Navigate to CloudPanel Admin Portal -> Sites -> Add Site -> Create a Node.js Application.
  2. Set Domain Name: mywhatsappapp.interlap.com (or your subdomain).
  3. Set Port: 3025.
  4. Set Entry Point: server.js.
  5. Select Node.js Version: 18+ LTS (or Node 20 LTS).

2. Bypass Nginx Reverse Proxy

By default, CloudPanel routes external traffic from Port 80/443 through an Nginx reverse proxy. For our standalone WebSockets configuration, we want direct access. Make sure to open Port 3025 on your firewall (e.g. AWS Security Group or UFW):

sudo ufw allow 3025/tcp

This isolates Node.js directly on port 3025.

3. Keep Server Alive with PM2

We highly recommend running your Node.js application inside PM2 to ensure it auto-reconnects, logs diagnostic crashes, and recovers seamlessly:

# Install PM2 globally
npm install -g pm2

# Start the bridge server
pm2 start server.js --name "whatsapp-bridge"

# Persist server launch on reboot
pm2 save
pm2 startup

🔒 Security & Performance Features

  • Session Persistence: Configured using whatsapp-web.js's built-in LocalAuth session strategies, meaning that once you scan the QR code once, you will not have to scan it again unless explicitly logged out.
  • Resilience & Crash Prevention: The server wraps critical events in structured try/catch clauses and binds events to process.on('uncaughtException'), protecting the server from unexpected Puppeteer execution crashes.
  • Auto-Reconnection: If WhatsApp Web loses connection or the user logs out, the server attempts re-initialization automatically after a 5-second backoff delay.
  • Dark Mode Design: Beautiful custom-tailored dark theme matching official WhatsApp guidelines (#111B21, #1F2C34, #00A884) with full custom ripple alerts, status badges, and tick indicators.
Description
No description provided
Readme 2.7 MiB
Languages
Dart 54.4%
JavaScript 18.4%
C++ 12.7%
CMake 9.6%
Swift 1.5%
Other 3.3%