Skip to main content
Vobiz Calling for HubSpot adds a Vobiz softphone to HubSpot’s calling panel. You run a small Node.js backend, register it with HubSpot as a calling provider, and your agents sign in with their Vobiz account. They place and take calls in the browser over WebRTC, and HubSpot logs each call on the contact’s timeline. Source code: vobiz-ai/Vobiz-HubSpot-Calling

Features

  • Click-to-call. Click any phone number in HubSpot, or type one into the panel.
  • Inbound calls with a screen pop. A call to your Vobiz number rings every signed-in agent with an Answer / Decline overlay. The first agent to answer takes it.
  • Call logging. HubSpot creates a call engagement on the contact’s timeline for every call, inbound and outbound.
  • Recordings. Every call is recorded. Agents play recent recordings in the panel.
  • Caller ID choice. Agents pick which of your Vobiz numbers their calls go out from.
  • Multi-agent. Each HubSpot user gets their own Vobiz SIP endpoint, created automatically on first sign-in.
  • Two sign-in modes. Your Vobiz account (Auth ID + Auth Token), or one existing SIP endpoint’s username and password.
  • Any Vobiz account. One backend serves any number of Vobiz accounts. Nothing account-specific is configured on the server.

How it works

  • HubSpot loads the widget in its calling panel. Your backend serves it at /widget/.
  • An agent signs in from the widget. The backend checks the credentials with Vobiz and sets up what the account needs: an application and one SIP endpoint per agent.
  • The browser registers as that agent’s SIP endpoint and places outbound calls itself.
  • Vobiz asks your backend’s answer URL (/answer) what to do with each call. Outbound, the backend dials the customer. Inbound, it rings the browsers of the signed-in agents.
  • Every call is recorded, and Vobiz tells the backend when the recording is ready.
  • The widget tells HubSpot when a call starts and ends. HubSpot writes the call to the contact’s timeline using the agent’s own HubSpot session.

Prerequisites

Setup

1

Clone, install and configure

Set at least these in backend/.env. There are no Vobiz credentials in it.
2

Run the backend and expose it

Put it behind your public HTTPS URL, then check it from outside your network:
The second command must print <Response></Response>. If Vobiz cannot fetch the answer URL, calls fail.
3

Get HubSpot developer access

Turn on Developer tools access for your user (Settings → Users & Teams → your user → Permissions). On seat-based accounts, assign a Developer seat instead.
4

Create the HubSpot app

The HubSpot CLI is installed with the project’s dev dependencies.
Copy the app’s Client ID and Client secret (Development → Projects → your app → Auth) into backend/.env as HUBSPOT_CLIENT_ID and HUBSPOT_CLIENT_SECRET, and restart the backend.
npm run sync-urls edits src/app/app-hsmeta.json in place with your hostname. Do not commit that change. Run it and upload again whenever your hostname changes.
5

Register the calling widget

Add HUBSPOT_APP_ID and HUBSPOT_DEVELOPER_API_KEY to backend/.env (or export them; the shell wins). The widget URL defaults to <PUBLIC_BASE>/widget/; set WIDGET_URL only to use a different one.
This registers Vobiz Calling as a provider, turns on inbound calling, and makes it available to your users. npm run calling:show prints the current settings.
6

Install the app

Open https://calling.example.com/hubspot/install and choose your HubSpot account. You land on Connected to HubSpot.
Installing a calling app needs a user with CRM permissions. In a portal where you are the only user, the install fails with “There was a problem fetching approvers”. Install into a developer test account instead (npm run test-account "Vobiz Calling Test", which uses the key npx hs account auth saved in ~/.hscli/config.yml, or create one in HubSpot).
7

Choose Vobiz as the calling provider

Open a contact with a phone number and click Call. At the bottom of the call popover, click Change provider and pick Vobiz Calling.

Sign in

The panel opens on a Connecting badge with two sign-in tabs.
Vobiz Calling for HubSpot panel showing a Connecting badge and step 1 Sign in to Vobiz with Vobiz account and SIP direct tabs plus Auth ID and Auth Token fields

The panel on load, with the two sign-in tabs.

Enter your Auth ID (MA_XXXXXXXX) and Auth Token from the Console → API credentials. The Auth Token is not your Console login password. When you sign in, the backend checks the credentials with Vobiz and sets up your account:
  • An application named vobiz-hubspot-calling-integration, with its answer URL and hangup URL set to https://calling.example.com/answer (POST). If it exists, it is reused and pointed at your backend. No other application is changed.
  • One SIP endpoint per agent, with the alias hubspot-<agent>, linked to that application. Each HubSpot user gets their own endpoint. A fresh random SIP password is set on every sign-in and sent only to that agent’s browser.
Signing in does not move any of your numbers. Once the browser registers, the badge turns to Ready.
Panel showing a green READY badge, the signed-in Vobiz account marked ACTIVE with its caller ID, and the Choose a caller ID and Place a call steps beneath

Signed in and ready to call.

Choose a caller ID. Calling from lists your account’s active, voice-enabled numbers. Outbound calls show the number you pick. The backend refuses any number that is not on your account.
The Calling from field expanded into a dropdown listing Vobiz numbers available as outbound caller IDs

Pick the number your calls go out from.

SIP direct

Use this for agents who should not hold your account’s Auth Token. Enter an existing endpoint’s SIP username, its SIP password, and the Calling from number in E.164 format (+91XXXXXXXXXX). The password stays in the browser and never reaches the backend. First, point the endpoint and the number at an application whose answer URL is your backend:
  1. In the Console, create an application with Answer URL and Hangup URL set to https://calling.example.com/answer, method POST.
  2. Under Voice → Endpoints, set the endpoint’s application to it.
  3. Under Numbers, attach the caller-ID number to the same application.
The API equivalent is Create an application, then Update an endpoint with {"app_id": "<app_id>"}, then Attach a number.
Use the endpoint’s stored username exactly as Console → Voice → Endpoints shows it, and a separate endpoint for each integration: an endpoint belongs to one application at a time.
SIP direct has no number dropdown, no Enable inbound calls and no recordings list; those need the account API. Inbound calls to the caller-ID number ring a SIP direct agent.

Enable inbound calls

Signed in with your Vobiz account, open Enable inbound calls, pick the number customers should call, and click Enable inbound calls. This attaches the number to the vobiz-hubspot-calling-integration application, so calls to it ring your signed-in agents.
A number belongs to one application at a time, so this moves the number off the application it is on now. The dropdown shows each number’s current application (now on app …), and the confirmation names the application it moved from, with its ID.
You only need to do this once per number.

Using it

Outbound. Click a phone number anywhere in HubSpot, or type a number with its country code into Number to call and click Call. The button is enabled once the badge shows Ready. During the call the panel shows a timer and Hang up.
Panel during a live call showing the Hang up button and a status line with an elapsed timer

An outbound call in progress.

Inbound. Keep HubSpot open and the panel signed in. A call to an enabled number raises the Incoming Vobiz Call overlay for every agent signed in to that Vobiz account. Answer (or Enter) picks up; Decline (or Escape) dismisses. If no agent is signed in, the caller hears “Sorry, no one is available to take your call right now” and the call ends.
Incoming Vobiz call overlay showing the calling number with green Answer and red Decline buttons and a hint that Enter accepts and Escape declines

The inbound overlay.

Call logging. For every call, the widget tells HubSpot the call has started and, when it ends, that it is complete. HubSpot creates the call engagement itself and shows it on the contact’s activity timeline, where you can add notes and an outcome. The backend does not write to HubSpot, and the app asks only for the oauth scope. Recordings. Every call, inbound and outbound, is recorded, up to one hour per call. Call recordings in the panel lists the account’s 15 most recent recordings. Play streams the audio through a signed link that expires after 15 minutes by default.
Call recordings list showing recording entries with timestamps and Play buttons

Recent recordings with the inline player.

Calls ring for up to 30 seconds and are limited to 4 hours.

Configuration

The backend reads backend/.env. npm run calling:configure reads HUBSPOT_APP_ID, HUBSPOT_DEVELOPER_API_KEY and WIDGET_URL (plus optional CALLING_APP_NAME, default Vobiz Calling) from backend/.env and your shell (the shell wins). WIDGET_URL defaults to <PUBLIC_BASE>/widget/.

Deploying to production

  • Use a stable HTTPS hostname. If it changes, update PUBLIC_BASE, run npm run sync-urls and npx hs project upload, re-run npm run calling:configure, and have each account sign in again.
  • Run exactly one backend instance. Sign-ins and calls are held in memory.
  • Keep DATA_DIR on persistent storage (default backend/data). The agent → endpoint map and the HubSpot OAuth tokens are saved there.
  • Set SIGNING_SECRET to a fixed value so recording links survive restarts.

Security

  • Your Auth Token never leaves the server and is never stored on disk. It is kept in the backend’s memory, never logged and never returned to the browser.
  • The browser gets a session token for that tab and its own endpoint’s SIP credentials. An agent can only read their own.
  • SIP direct passwords never reach the backend.
  • Recording links carry no credentials. Each is signed for one recording in one account and expires.
  • The backend only answers browsers from HubSpot, localhost, its own origin, and origins you add in ALLOWED_ORIGINS.
  • An inbound call rings only agents of the Vobiz account that owns the number.
  • Anyone who signs in with the Auth ID and Auth Token holds your account’s API credentials. Use SIP direct for agents who should not.

Troubleshooting

The widget did not load: the bundle was not built, or the backend is unreachable. Run npm run build, restart, and check that https://calling.example.com/widget/ opens in a browser.
Your host is not in the app’s permitted URLs. Run npm run sync-urls, then npx hs project upload.
The app is not installed in this portal, the widget is not registered, or it was registered with --not-ready. Check with npm run calling:show, re-run npm run calling:configure, and install from /hubspot/install into this portal.
Grant your HubSpot user Developer tools access, or assign a Developer seat.
You are installing into a portal where you are the only user, so there is nobody to approve. Install into a developer test account.
HUBSPOT_SCOPES is set to more than oauth. Remove it (the default is oauth), restart, and install again.
Copy both again from Console → API credentials. The Auth Token is not your Console password.
The browser could not register its SIP endpoint. With a Vobiz account, sign in again. With SIP direct, use the endpoint’s stored username from Console → Voice → Endpoints. If the agent is signed in on another browser, that sign-in replaced the password: use one browser per agent.
Vobiz cannot reach your answer URL, or the application points at an old hostname. curl -X POST https://calling.example.com/answer -d "Event=Hangup" must return XML. Sign in again to point the application at the current PUBLIC_BASE.
The agent has no valid caller ID. Choose a number under Calling from, and check in the Console that it is active and voice-enabled.
No agent of that Vobiz account is signed in to the panel, for example right after the backend restarted. Sign in.
The number is not attached to the integration’s application. Click Enable inbound calls for it.
Inbound calling is off in HubSpot’s calling settings. Re-run npm run calling:configure without --no-inbound.
“Sign in to the calling panel again” means the backend restarted: sign in and refresh the list. “Invalid or has expired” means the link is older than RECORDING_URL_TTL_SECONDS or SIGNING_SECRET changed: refresh the list.

Operating notes

  • Sign in again after the backend restarts. Sessions and Auth Tokens live in memory. Inbound callers to an account hear the “no one is available” message until one of its agents signs in.
  • Run one backend instance. Each instance keeps its own state.
  • Use one browser per agent. Signing in from a second browser disconnects the first.
  • Inbound calls ring every signed-in agent of the account.
  • Every call is recorded, up to one hour per call.
  • Recordings are in the panel.
  • A Vobiz account sign-in gives you the number list, Enable inbound calls and recordings. With SIP direct, type the password again after a page reload.
  • Install the app privately in your HubSpot account.

Next steps

Source code

Clone the backend and widget, and read the full README.

Other CRMs

The same softphone for Zendesk, Pipedrive and Freshdesk.
Reference: <Dial>, <Record>, SIP endpoints, Applications.