Blind vs attended transfer in WebRTC: how Browser Phone handles both

Blind vs attended transfer in WebRTC: how Browser Phone handles both

browser-phone.org · 3 April 2026

Call transfer is one of those features that sounds straightforward until you are the one implementing it. There are two distinct models — blind and attended — and they behave differently at the SIP signalling level, at the WebRTC layer, and in terms of what the user sees. Getting both right in a browser-based phone means solving problems that desk phone manufacturers have had decades to work through quietly in firmware.

Here is how Browser Phone handles both, what is happening underneath, and what to watch for if you are building or extending a WebRTC softphone.

Blind transfer

A blind transfer — sometimes called an unattended transfer — is the simpler of the two. You are on a call, you decide to send it to another extension, you do not speak to the destination first, and the call leaves your hands. The caller rings the new extension and you are done.

At the SIP level, this is a REFER message. Browser Phone sends REFER to the PBX with a Refer-To header pointing at the transfer target. The PBX re-invites the caller to the new destination. In principle, that is all there is to it. (For background on how WebRTC signalling sits on top of SIP in an Asterisk environment, the Asterisk WebRTC configuration guide covers the underlying setup.)

Where it gets complicated

The tricky part is closing the call leg on the browser side cleanly. The correct behaviour is for the PBX to send a NOTIFY back once the transfer completes — specifically a NOTIFY containing SIP/2.0 200 OK in the body, confirming the handoff. Some PBXes never send it. Some send it malformed. A browser phone that waits on this message will appear frozen — the call panel stays open, nothing happens, and the user cannot tell whether the transfer worked.

Browser Phone handles this with a timeout: if no clean NOTIFY arrives within a few seconds of the initial 202 Accepted, the local call leg closes regardless. It matches how most physical desk phones behave, and keeps the UI honest even when the PBX is not following the spec precisely.

Attended transfer

An attended transfer means speaking to the destination before completing the handoff:

  • Put the original caller on hold
  • Dial the transfer target and have a brief conversation
  • Connect the two parties and drop off

From a SIP perspective, you now have two simultaneous call legs from the browser: one to the original caller on hold, and one to the transfer target. The transfer completes when Browser Phone sends a REFER on the held leg with a Refer-To header that references the dialog of the active leg.

The Refer-To header for an attended transfer contains a Replaces parameter — URL-encoded — that tells the PBX exactly which call leg to substitute:

Refer-To: <sip:caller@pbx?Replaces=callid-of-second-leg
  %3Bto-tag%3Dsecond-leg-to-tag
  %3Bfrom-tag%3Dsecond-leg-from-tag>

The percent-encoding is mandatory and a frequent source of bugs. A single mis-encoded character and the PBX either ignores the Replaces header or rejects the REFER. It tends to work in testing and then fail against a specific PBX in production — the kind of thing that is annoying to diagnose.

Managing two simultaneous calls

Browser Phone tracks each call as a separate object. During an attended transfer, both are visible in the UI — one held, one active — and you can switch between them before completing the handoff. The Complete Transfer button constructs the REFER with the correct Replaces header, sends it on the held leg, and once the PBX acknowledges with a 202, both local call legs close.

Hold

Putting a WebRTC call on hold requires a bit more than just pausing audio. You have two options.

The first is to stop sending audio from the browser without signalling anything. The PBX does not know the call is on hold, the caller gets silence, no hold music. Acceptable for testing; not acceptable for real callers waiting on the line.

The second — the correct option — is to send a re-INVITE with the SDP media direction set to sendonly. This tells the PBX the browser will still receive audio, so the PBX can play hold music through the existing RTP stream, but will not be transmitting. The caller hears music. The browser pauses sending. Both sides understand the state of the call.

On the WebRTC side, this means renegotiating the peer connection: the SDP offer in the re-INVITE carries a=sendonly on the audio track. In most cases the existing DTLS connection is reused rather than restarted, keeping the hold and unhold transitions quick. (Where the PBX and browser disagree on codecs — for example, an Asterisk endpoint expecting G.711 while the browser offers Opus — media transcoding becomes part of this picture.)

When both sides are WebRTC endpoints

If both the original caller and the transfer target are using browser-based softphones — two people on the same Browser Phone or Siperb deployment, for instance — the attended transfer works identically at the SIP level. The PBX bridges the two WebRTC sessions; the softphone just needs to get the REFER signalling right.

It becomes more involved when the two endpoints are behind different TURN servers or cannot reach each other directly. In that case the PBX needs to act as a media bridge for the two WebRTC sessions, or a WebRTC-to-SIP proxy needs to handle the bridging on its behalf. Asterisk with res_srtp handles this correctly natively; FreeSWITCH does too.

Edge cases worth testing

Transfer bugs tend to appear in the less obvious scenarios rather than the straightforward happy path. A few worth testing deliberately:

  • Blind transfer to a busy extension — does the caller hear a busy tone or just silence?
  • Attended transfer where the target never answers — can you cancel the outbound call and return to the original caller cleanly?
  • Attended transfer where the original caller hangs up before you complete the handoff — does the second call leg tear down cleanly?
  • Transfer on a mobile or unreliable connection — does the REFER retry or fail silently?

Browser Phone’s transfer implementation has been tested against these scenarios on both Asterisk and FreeSWITCH. Behaviour with other PBXes varies — if you run into something unexpected, the GitHub issues page and the Asterisk community forums are both good starting points.


If you would rather not manage the infrastructure and just need transfer — blind, attended, and all the edge cases — working reliably out of the box, Siperb offers the same functionality as a hosted WebRTC softphone with support for both Asterisk and FreeSWITCH backends, including provisioned credentials, push notifications for inbound calls, and built-in media transcoding for legacy PBXes.


browser-phone.org · Open-source WebRTC SIP phone for Asterisk, FreeSWITCH and any SIP-based PBX. Project home of the codebase that became Siperb.

Leave a Reply

Your email address will not be published. Required fields are marked *