Dashboard
WhatsApp OTP Gateway
Checking...
🔋
WA State
📤
0
OTPs Sent
0
Verified
0
Failed
System Info
PHP8.1.33
Node.jssh: node: command not found
Node binnode
exec()✘ disabled
shell_exec()✘ disabled
proc_open()✔ enabled
popen()✘ disabled
Bridge
WA State
OTP TTL5 min / 3 tries
Sessiondata/wa_auth/
Activity Log
Scan QR to Login
Loading...
📵
Bridge Not Running
Click Start to launch the WhatsApp bridge
WhatsApp QR
WhatsApp Connected!
Session is active & saved
⚠️
Bridge Error
An error occurred.
Session Persistence

After you scan the QR code once, the session is saved to data/wa_auth/.

  • Opening the page in a new browser — session still works ✅
  • Server restart — click Start, session auto-resumes ✅
  • No QR re-scan needed unless you Logout
Bridge Status
Process
WA State
Last update
Send OTP
Include country code without +. E.g: 8801712345678
Message Preview
🔐 Your OTP Code

Code: • • • • • •
⏱ Expires in 5 minutes.

Do not share this with anyone.
Verify OTP
Enter the 6-digit code the user received on WhatsApp
Setup Guide — cPanel Installation
This system uses PHP to control a Node.js bridge. Node.js must be installed on your server — it is on almost all cPanel hosts. You never need to configure a separate app or port.
Step 1 — Upload Files
1
Upload the entire project folder to your cPanel public_html (or any subfolder)
2
Make data/ writable:
chmod 755 data/ via SSH or File Manager → Right Click → Change Permissions
3
Make sure data/ is outside public_html or protected by .htaccess (see below)
Step 2 — Install Node dependencies
4
Open cPanel → Terminal (or SSH) and run:
cd ~/public_html/wa-server
npm install
5
This installs whatsapp-web.js and qrcode into wa-server/node_modules/
Step 3 — Use the dashboard
6
Open https://yourdomain.com/index.php
7
Go to WhatsApp Login tab → click Start
8
PHP starts bridge.js as a background process using exec()
9
QR code appears → Scan with WhatsApp → Session saved ✅
10
Open page from any browser / device — session still works ✅
Protect data/ folder
## Add to data/.htaccess
Deny from all

This prevents anyone from accessing your OTP hashes or session files via browser.

Use in Your PHP Project
<?php
require_once 'includes/config.php';
require_once 'includes/Bridge.php';
require_once 'includes/Otp.php';

$bridge = new Bridge();
$otp    = new Otp();

// 1. Make sure bridge is running
if (!$bridge->isRunning()) {
    $bridge->start();   // starts bridge.js in background
    sleep(8);           // wait for WhatsApp to reconnect from saved session
}

// 2. Make sure WhatsApp is ready
$status = $bridge->getStatus();
if ($status['state'] !== 'READY') {
    die('WhatsApp not connected. Visit /index.php to scan QR.');
}

// 3. Generate OTP and send
$phone = '8801712345678';  // digits only, with country code
$code  = $otp->create($phone);
$msg   = "Your OTP: *{$code}* — expires in 5 minutes.";

$result = $bridge->send($phone, $msg);
echo $result['success'] ? 'OTP sent!' : $result['error'];
<?php
require_once 'includes/config.php';
require_once 'includes/Otp.php';

$otp = new Otp();

$phone = $_POST['phone'];     // digits only
$input = $_POST['otp_code']; // what user entered

$result = $otp->verify($phone, $input);

if ($result['ok']) {
    // ✅ Correct and not expired
    session_start();
    $_SESSION['verified_phone'] = $phone;
    header('Location: /dashboard.php');
    exit;
} else {
    // ❌ Wrong, expired, or too many tries
    $error = $result['msg']; // "Wrong OTP. 2 attempt(s) left."
}
<!-- Login form — 2 steps: phone → OTP -->

<!-- Step 1 -->
<div id="step1">
  <input type="tel" id="phone" placeholder="8801712345678"/>
  <button onclick="sendStep()">Send OTP</button>
</div>

<!-- Step 2 -->
<div id="step2" style="display:none">
  <input type="text" id="otp" maxlength="6" placeholder="Enter OTP"/>
  <button onclick="verifyStep()">Verify</button>
</div>

<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
function sendStep() {
  $.post('ajax.php', { action: 'send_otp', phone: $('#phone').val() }, function(r) {
    if (r.success) { $('#step1').hide(); $('#step2').show(); }
    else alert(r.error);
  });
}
function verifyStep() {
  $.post('ajax.php', { action: 'verify_otp', phone: $('#phone').val(), code: $('#otp').val() }, function(r) {
    if (r.ok) { alert('Verified! Redirecting...'); location.href='/dashboard.php'; }
    else alert(r.msg);
  });
}
</script>
Bridge Log (bridge.log)
(click Refresh)