Phone SDKWebRTC Phone Integration

WebRTC Phone Integration

Admin·5/5/2026

Guide to Integrating AlohubPhone SDK v3

Documentation for developers who want to integrate Alohub's WebRTC phone into their website/web application.

Table of Contents

  1. Overview

  2. Prerequisites Before Getting Started

  3. SDK Installation

  4. Basic Integration (5 minutes)

  5. Widget Interface

  6. Advanced Integration — Headless Mode

  7. CRM Integration — Click-to-Call

  8. Error Handling

  9. Microphone & Access Permissions

  10. Features During Calls

  11. Multilingual Support

  12. Build & Deployment

  13. Frequently Asked Questions

1. Overview

What is AlohubPhone SDK v3?

AlohubPhone SDK v3 is a JavaScript library that allows embedding a WebRTC phone directly into a website. Employees can make and receive calls right in the browser without needing to install software.

Key Features

Feature

Description

1 JS file

Combines everything into a single file (~375KB, ~95KB gzip)

2 parameters

Just need apiKey+ userName

Security

SIP credentials are never exposed

Shadow DOM

Completely isolated CSS, does not affect the website

Cross-platform

WordPress, React, Vue, Angular, plain HTML, ...

6 languages

Vietnamese, English, 日本語, 한국어, 中文, ภาษาไทย

2. Prerequisites Before Getting Started

Alohub Account

You need to have:

  • API Key Contact Alohub to obtain an API Key

  • userName — Alohub account username (e.g.: admin.alohub)

Technical Requirements

Requirement

Details

Browser

Chrome 60+, Firefox 55+, Edge 79+, Safari 11+, CocCoc

HTTPS

Required in production (localhost is exempt)

Microphone

Requires microphone access

Note: The SDK only works with Alohub's PBX. Cannot be used with other PBXs. Contact Alohub to register for a PBX.

3. SDK Installation

Add a script line to the HTML page:

<!-- Production -->
<script src="https://cdn.alohub.vn/sdk/v3/alohub-phone.prod.min.js"></script>
<!-- Development (server test) -->
<script src="https://cdn.alohub.vn/sdk/v3/alohub-phone.dev.min.js"></script>

Method 2: Self-host

Download the file alohub-phone.prod.min.js, place it in the static folder, add a script tag:

<script src="/assets/js/alohub-phone.prod.min.js"></script>

Difference Between Dev and Prod

File

Server

Purpose

.dev.js

{{protocol}}://{{host}}:{{port}}(dev)

Test, development

.prod.js

{{protocol}}://{{host}}(prod)

Production

4. Basic Integration (5 minutes)

Step 1: Add SDK to the page

Place the following code before the tag </body>:

<script src="https://cdn.alohub.vn/sdk/v3/alohub-phone.prod.min.js"></script>
<script>
  AlohubPhone.init({
    apiKey: 'YOUR_API_KEY',      // Thay bằng API key thật
    userName: 'your.username',    // Thay bằng username thật
  });
</script>

Step 2: Widget Automatically Appears

After adding the code, the phone widget appears in the bottom right corner of the webpage. The widget displays:

  • Header : Connection status (green dot = online) + extension number

  • Number input box : Enter the phone number to call + call button

  • Keypad : Press "Show Keypad" to display the full numpad

Step 3: Customize Interface + Error Handling

AlohubPhone.init({
  apiKey: 'YOUR_API_KEY',
  userName: 'your.username',

  // Giao diện
  theme: 'dark',               // 'light' (mặc định) hoặc 'dark'
  position: 'bottom-left',     // Vị trí widget (xem bảng bên dưới)
  language: 'vi',              // vi, en, ja, ko, zh, th

  // Hành vi
  autoAnswer: false,           // false = hiện popup khi có cuộc gọi đến
  debug: true,                 // true = hiện log trong console

  // Callbacks
  onReady: function(phone) {
    console.log('Sẵn sàng! Mic:', phone.getMicPermission());
  },
  onError: function(e) {
    console.error('[' + e.code + ']', e.message);
  },
  onAuthFailed: function(e) {
    console.error('Xác thực thất bại:', e.code, e.message);
  }
});

Widget Position

Value

Position

bottom-right

Bottom right corner (default)

bottom-left

Bottom left corner

top-right

Top right corner

top-left

Top left corner

5. Widget Interface

The SDK provides 5 screens that automatically switch according to the call status:

Screen

When

Displays

1. Dial

Default

Number input box + call button + "Show Keypad"

2. Dial + Keypad

Press "Show Keypad"

Numpad 0-9, *, # with letters ABC/DEF + delete button ⌫ + large Call button

3. Ringing

Outgoing call

Number being called + red "End" button

4. Incoming

Incoming call

Incoming number + red "Decline" / green "Accept" button

5. Answering

Answering

Number + timer + "End" + "Show Keypad" + "Transfer Call"

Header status bar

Dot

Status

When

🟢 Green

Online

SIP registered, ready to call

🟡 Yellow (blinking)

Connecting

Connecting WebSocket/SIP

🔴 Red

Offline

Disconnected / registration failed

🔵 Blue (blinking)

Calling

In a call

6. Advanced Integration — Headless Mode

When you want to design your own interface , use headless: true. The SDK will not create any UI, only provide APIs and events.

AlohubPhone.init({
  apiKey: 'YOUR_API_KEY',
  userName: 'your.username',
  headless: true,              // ← Không tạo UI widget

  onReady: function(phone) {
    // phone là instance SDK — điều khiển hoàn toàn bằng code
    console.log('Sẵn sàng!');

    phone.on('incoming', function(data) {
      showMyPopup('Cuộc gọi từ: ' + data.remoteNumber);
    });

    phone.on('answered', function(data) {
      showMyCallScreen(data.remoteNumber);
    });

    phone.on('ended', function(data) {
      hideMyCallScreen();
      saveCallLog(data);
    });

    phone.on('error', function(e) {
      showMyError(e.code, e.message);
    });
  }
});

Comparison of 2 Modes

With Widget (default)

Headless

Interface

Widget automatically

You code it yourself

DTMF / Mute / Hold

Available on widget

phone.sendDTMF(), phone.mute(), ...

Events

Complete

Complete (same)

phone.ui

Available

null

7. CRM Integration — Click-to-Call

<!-- Nút gọi trong CRM -->
<button class="btn-call" data-phone="0901234567">📞 Gọi</button>

<script>
  var phone = null;

  AlohubPhone.init({
    apiKey: 'YOUR_API_KEY',
    userName: 'your.username',
    headless: true,
    onReady: function(p) {
      phone = p;

      // Ghi log cuộc gọi khi kết thúc
      phone.on('ended', function(data) {
        fetch('/api/call-logs', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            phone: data.remoteNumber,
            duration: data.duration,
            direction: data.direction
          })
        });
      });
    }
  });

  // Click-to-Call với extra SIP headers
  document.querySelectorAll('.btn-call').forEach(function(btn) {
    btn.addEventListener('click', function() {
      if (phone) phone.call(this.dataset.phone, {
        extraHeaders: ['X-CRM-INFO: lead|123']
      });
    });
  });
</script>

8. Error Handling

Error handling flow

The SDK provides 3 layers of error catching:

  1. onAuthFailed(e) — Authentication failed (before SDK is ready): MISSING_API_KEY, MISSING_USERNAME, INVALID_API_KEY, DOMAIN_NOT_WHITELISTED

  2. .catch(err) — SIP registration failed: REGISTRATION_FAILED, REGISTRATION_TIMEOUT

  3. phone.on('error', fn) — All runtime errors: MIC_NOT_FOUND, MIC_DENIED, CALL_MEDIA_FAILED, CALL_NO_NUMBER, CALL_NOT_READY, ...

Error handling code

phone.on('error', function(e) {
  // e.code    — Mã lỗi chuẩn (AlohubPhone.ERROR.*)
  // e.type    — Nhóm: 'mic', 'call', 'dtmf', 'transfer'
  // e.message — Mô tả chi tiết

  switch (e.code) {
    case AlohubPhone.ERROR.MIC_NOT_FOUND:
      alert('Không tìm thấy microphone!');
      break;
    case AlohubPhone.ERROR.MIC_DENIED:
      alert('Microphone bị từ chối.');
      phone.requestMicPermission(); // Yêu cầu lại
      break;
    case AlohubPhone.ERROR.CALL_MEDIA_FAILED:
      alert('Lỗi microphone khi gọi.');
      break;
    case AlohubPhone.ERROR.CALL_NOT_READY:
      alert('Điện thoại chưa sẵn sàng.');
      break;
  }
});

// Cuộc gọi thất bại — có SIP code chi tiết
phone.on('failed', function(e) {
  console.log(e.sipCode, e.sipReason);
  // 480 "Temporarily Unavailable"
  // 486 "Busy Here"
});

Error code table

Error code

Group

Description

MIC_NOT_FOUND

mic

No microphone

MIC_DENIED

mic

Mic access denied

CALL_MEDIA_FAILED

mic

Mic error during call (JsSIP getusermediafailed)

CALL_NO_NUMBER

call

Missing phone number

CALL_NOT_READY

call

SIP not registered

DTMF_INVALID

dtmf

Invalid DTMF character

TRANSFER_NO_CALL

transfer

Transfer when no call

API_CALL_FAILED

api

Call via API failed

Common SIP Error Codes

SIP Code

Meaning

480

Temporarily Unavailable — Recipient not online

486

Busy Here — Busy

487

Request Terminated — Call canceled

603

Decline — Recipient declined

404

Not Found — Number does not exist

9. Microphone & Access Permissions

The SDK automatically requests mic permission after SIP registration. If denied, it can request again:

// Kiểm tra trạng thái (đồng bộ)
phone.getMicPermission();  // 'granted' | 'denied' | 'unknown'

// Yêu cầu lại (hiện popup browser)
phone.requestMicPermission().then(function(status) {
  console.log('Mic:', status); // 'granted' hoặc 'denied'
});

// Lắng nghe thay đổi
phone.on('micPermission', function(e) {
  if (e.status === 'denied') {
    alert('Vui lòng cho phép microphone!');
  }
});

Note: If the user has clicked "Block" on the browser, requestMicPermission()it will be denied immediately without showing a popup. The user must go to Settings > Site Settings > Microphone to unblock.

10. Features During Calls

Group

Method

Description

Call

phone.call(num, opts?)

Outgoing call (opts: {extraHeaders: [...]})

phone.answer()

Answer

phone.hangup()

End / decline

DTMF

phone.sendDTMF(tone)

Send key presses (0-9, *, #, A-D)

Mic

phone.mute() / unmute()

Mute/unmute mic

phone.toggleMute()

Toggle status

Hold

phone.hold() / unhold()

Hold / resume

phone.toggleHold()

Toggle status

Transfer

phone.transfer(target)

Transfer call (blind transfer)

Status

phone.isOnCall()

On call?

phone.isMuted()

Mic is off?

phone.isHeld()

On hold?

phone.getCallInfo()

Call details

Disconnect

phone.unregister()

Logout SIP (keep WebSocket)

phone.disconnect()

Completely disconnect

phone.destroy()

Cancel instance + remove UI + clear credentials

11. Multilingual Support

Code

Language

Interface Example

vi

Vietnamese (default)

Phone number, End, Answer

en

English

Phone Number, Hang Up, Answer

ja

日本語

電話番号, 終了, 応答

ko

한국어

전화번호, 종료, 받기

zh

中文

电话号码, 挂断, 接听

th

ภาษาไทย

หมายเลขโทรศัพท์, วางสาย, รับสาย

// Cài đặt khi khởi tạo
AlohubPhone.init({ apiKey: '...', userName: '...', language: 'en' });

// Đổi ngôn ngữ runtime
phone.ui.setLanguage('ja');

// Custom ngôn ngữ riêng (ví dụ tiếng Đức)
phone.ui.setLanguage({
  call: 'Anrufen',
  hangup: 'Auflegen',
  answer: 'Annehmen',
  reject: 'Ablehnen'
  // Các key thiếu sẽ fallback về tiếng Việt
});

12. Build & Deployment

Build from source

cd v3/
node build.js --dev       # → dist/alohub-phone.dev.js
node build.js --prod      # → dist/alohub-phone.prod.js
node build.js             # → cả hai

# Minify (cần cài terser)
npm install terser
node build.js             # → thêm dist/*.min.js

CSP (Content Security Policy)

If the website uses CSP, add:

Content-Security-Policy:
  connect-src wss://*.alohub.vn https://*.alohub.vn;
  media-src blob:;
  script-src 'self' https://cdn.alohub.vn;

13. Frequently Asked Questions

Q: Does the SDK work with other PBXs?

No. SDK v3 only works with Alohub IPCC.

Q: What if the microphone is denied?

Call phone.requestMicPermission()to request again. If blocked, the user must go to browser Settings > Site Settings > Microphone > unblock.

Q: Is there support for React / Vue / Angular?

Yes. The SDK is vanilla JS, works on any framework. Use headless: trueand then integrate into the component.

Q: Why did the call fail?

Listen to the failedevent — returns sipCodeand sipReason(e.g.: 480 "Temporarily Unavailable").

Q: How to logout?

phone.unregister()(only SIP) | phone.disconnect()(completely) | phone.destroy()(cancel + remove UI).

Q: Can it be used in an iframe?

Yes, add allow="microphone"to the <iframe>tag.

Q: Is there a limit on the number of simultaneous calls?

Each SDK instance supports 1 call. An incoming call while on a call will emit the callWaitingevent and automatically decline.

AlohubPhone SDK v3 Contact Alohub — support@alohub.vn

Was this article helpful?
Updated: 5/5/2026