Developer Guide / WebRTC Integration

Browser Calls with WebRTC

Let your users talk to your AI voice agent directly from a web page — no phone call needed. This guide walks through the required scripts, HTML elements, connection lifecycle, and events.

Overview

Voice Elements provides a lightweight JavaScript library — InventiveWebRTC.js — that handles the entire WebRTC handshake, ICE negotiation, and media pipeline for you. Your page only needs to call a single function to connect and listen for a handful of DOM events to track call state.

The connection flow is simple: the library opens the user's microphone, establishes a WebSocket to the Voice Elements signaling server, negotiates an SDP offer/answer, and streams two-way audio between the browser and your AI voice agent.

HTTPS required: Browsers only allow microphone access on secure origins. Your page must be served over https:// (or localhost during development).

Prerequisites

  • A Voice Nexus Service account with at least one configured voice agent.
  • The WebSocket URL (WSS) for your Voice Elements WebRTC server. This is provided by Voice Elements when your account is provisioned.
  • Your page served over HTTPS so the browser will grant microphone permission.
  • A modern browser — Chrome, Edge, Firefox, or Safari.

Required Scripts

Two JavaScript files must be included on every page that uses browser calling. Load them in this order, after the required HTML elements (see next section).

Script Purpose
adapter.js A WebRTC compatibility shim (from the webrtc-adapter project). Normalizes browser differences in the getUserMedia and RTCPeerConnection APIs. Must be loaded before InventiveWebRTC.js.
InventiveWebRTC.js The Voice Elements WebRTC client library. Manages the WebSocket signaling channel, SDP negotiation, ICE candidate exchange, microphone access, and media streaming. Exposes the public API described in this guide.
<!-- Load after the required HTML elements -->
<script src="adapter.js"></script>
<script src="InventiveWebRTC.js"></script>
Load order matters. adapter.js must come first. InventiveWebRTC.js references DOM elements by ID at parse time, so the HTML elements it depends on must already exist in the document.

Required HTML Elements

InventiveWebRTC.js looks up several elements by id when it first loads. Place these elements in your page before the script tags.

<!-- Local mic preview (muted so the user doesn't hear themselves) -->
<audio id="sourceAudio" autoplay muted></audio>

<!-- Remote audio from the AI agent -->
<audio id="remoteAudio" autoplay></audio>

<!-- Optional status label the library updates -->
<span id="lblStatus">Disconnected</span>
Element ID Type Purpose
sourceAudio <audio> Receives the local microphone stream. Should be muted to prevent echo.
remoteAudio <audio> Plays back audio from the remote AI agent. Should have autoplay.
lblStatus any element Optional. The library may update its textContent with status messages during SDP negotiation.

Connecting a Call

To start a browser call, invoke one of two functions. Both will prompt the user for microphone access (if not already granted), open a WebSocket to the signaling server, and negotiate the WebRTC peer connection automatically.

Option A — Connect with a WebSocket URL

Use this when you already know the WSS endpoint for your Voice Elements server.

IVLConnect("wss://your-server.voiceelements.com:61053/");

Option B — Connect with an Application ID

If your account uses Application ID-based routing, call IVLConnectApplicationID instead. The library will look up the correct WebSocket URL automatically via the Voice Elements REST API.

IVLConnectApplicationID("your-application-id");

Passing context to your agent

When the WebSocket opens, the library sends a handshake that includes the current page URL. You can append custom data (such as a phone number or session token) by setting the global variable ivlAppendToUrlOnOpen before calling IVLConnect.

// The handshake URL will be sent as:
// "https://yoursite.com/call" + "/" + "7205551234"
ivlAppendToUrlOnOpen = "7205551234";
IVLConnect("wss://your-server.voiceelements.com:61053/");

Your VNS CallStart webhook receives this URL, so you can parse the appended value to determine which agent configuration to return.

Disconnecting

To hang up, call:

IVLDisconnect();

This closes the WebSocket, removes the local media stream from the peer connection, and tears down the RTCPeerConnection. A socketStatusEvent with status IVLSocketState.Disconnected fires once the socket closes.

Events

The library dispatches CustomEvents on document so your page can react to state changes without polling. Register listeners before calling IVLConnect.

Event Name e.detail Properties Description
socketStatusEvent status, time Fired whenever the connection state changes. status is one of the IVLSocketState enum values (see table below).
mediaStatusEvent status, time Fired when remote audio begins or ends. status is IVLMediaState.Connected or IVLMediaState.Disconnected.
messageEvent message, time Diagnostic log messages from the library. Useful for debugging. Only fires when ivlLogs = true.
applicationMessageEvent message Fired when the server sends a custom application message. The message property is a JSON string you can parse to handle app-specific commands.
authenticationEvent modulus, publicExponent Fired if the server requests authentication. Respond by calling IVLAuthenticate(username, password).

IVLSocketState Values

Constant Value Meaning
IVLSocketState.Disconnected 0 No active connection.
IVLSocketState.Permissions 1 Requesting microphone permission from the user.
IVLSocketState.Connecting 2 WebSocket opened; SDP/ICE negotiation in progress.
IVLSocketState.Connected 3 Call is live — two-way audio is flowing.

Example: Listening for connection state

document.addEventListener("socketStatusEvent", function (e) {
    switch (e.detail.status) {
        case IVLSocketState.Disconnected:
            console.log("Call ended");
            break;
        case IVLSocketState.Permissions:
            console.log("Requesting microphone...");
            break;
        case IVLSocketState.Connecting:
            console.log("Connecting...");
            break;
        case IVLSocketState.Connected:
            console.log("Connected — call is live!");
            break;
    }
});

Sending & Receiving Application Messages

You can exchange custom JSON payloads between your page and the Voice Elements server while a call is in progress. This is useful for sending UI commands (e.g. a "Goodbye" button) or receiving data from the agent.

Sending a message to the server

// Send an arbitrary JSON object to the server-side application
IVLSocketSendApplicationMessage({
    __type: "MyApp.EndCall",
    version: 1,
    reason: "user-clicked-hangup"
});

Receiving a message from the server

document.addEventListener("applicationMessageEvent", function (e) {
    var msg = JSON.parse(e.detail.message);
    console.log("Received from server:", msg);
    // Handle application-specific message types here
});

Sending DTMF Tones

If your agent expects DTMF input (e.g. "press 1 for billing"), you can send tones programmatically from JavaScript. DTMF sending is set up automatically during the WebRTC negotiation.

// Send a single digit
sendTone("1");

// Send multiple digits
sendTone("1234#");

Each tone is sent with a 250 ms duration and 50 ms gap by default.

Full Example

Below is a minimal, self-contained HTML page that places a "Call Agent" button on screen. Clicking it connects to your AI voice agent via WebRTC. Clicking it again hangs up.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Browser Call Demo</title>
</head>
<body>

    <h1>Talk to Our AI Agent</h1>
    <p>Status: <span id="lblStatus">Disconnected</span></p>
    <button id="callBtn">Call Agent</button>

    <!-- Required audio elements -->
    <audio id="sourceAudio" autoplay muted></audio>
    <audio id="remoteAudio" autoplay></audio>

    <!-- Scripts (order matters) -->
    <script src="adapter.js"></script>
    <script src="InventiveWebRTC.js"></script>

    <script>
        var WSS_URL  = "wss://your-server.voiceelements.com:61053/";
        var callBtn  = document.getElementById("callBtn");
        var isActive = false;

        // Listen for state changes
        document.addEventListener("socketStatusEvent", function (e) {
            var lbl = document.getElementById("lblStatus");
            switch (e.detail.status) {
                case IVLSocketState.Permissions:
                    lbl.textContent = "Requesting mic…";
                    break;
                case IVLSocketState.Connecting:
                    lbl.textContent = "Connecting…";
                    break;
                case IVLSocketState.Connected:
                    lbl.textContent = "Connected";
                    callBtn.textContent = "Hang Up";
                    isActive = true;
                    break;
                case IVLSocketState.Disconnected:
                    lbl.textContent = "Disconnected";
                    callBtn.textContent = "Call Agent";
                    isActive = false;
                    break;
            }
        });

        callBtn.addEventListener("click", function () {
            if (!isActive) {
                IVLConnect(WSS_URL);
            } else {
                IVLDisconnect();
            }
        });
    </script>

</body>
</html>
Replace WSS_URL with the actual WSS endpoint provided by Voice Elements for your account.

Troubleshooting

Microphone permission denied

The browser blocked microphone access. Ensure the page is served over HTTPS and the user clicks "Allow" on the permission prompt. Check that no browser extension is blocking media access.

Call connects but no audio

Verify that both <audio> elements exist with the correct IDs. Ensure remoteAudio has the autoplay attribute. Some browsers require a user gesture before audio can play — make sure the call is initiated by a button click.

WebSocket connection fails

Confirm the WSS URL is correct and that port 61053 (or your configured port) is not blocked by a firewall. Mixed-content rules will block ws:// connections from an HTTPS page — always use wss:// in production.

Enabling debug logs

Set ivlLogs = true; before calling IVLConnect. This activates the messageEvent custom event. Listen for it to capture detailed log output from the library.

API Quick Reference

Function / Variable Description
IVLConnect(wssUrl) Open mic, connect WebSocket, start WebRTC call.
IVLConnectApplicationID(appId) Look up WSS URL by Application ID, then connect.
IVLDisconnect() Hang up — close socket & peer connection.
IVLAuthenticate(user, pass) Respond to an authentication challenge.
IVLSocketSendApplicationMessage(obj) Send a custom JSON message to the server.
sendTone(digits) Send DTMF tones over the active call.
ivlAppendToUrlOnOpen Set before IVLConnect to append data to the handshake URL.
ivlLogs Set to true to enable messageEvent diagnostic logging.