Build In-Browser Calling with Twilio Client

Twilio Client allows your users to make and receive phone calls in their browsers. This tutorial will show you the front-end and backend code necessary to make browser-to-phone and browser-to-browser calls with Twilio Client.

Companies like Zendesk and Home Depot use Twilio Client to power their customer support centers. This tutorial and accompanying  application power the support site for the Birchwood Bicycle Polo Co., which sells equipment to those who play "the sport of kings." It has three main features:

  • Unsatisfied customers can submit support tickets with their phone number and their problem.
  • Support agents can call customers' phones from their browser to follow up on support tickets.
  • Customers can also use their browser to speak with support agents live when available.
Loading Code Samples...
Language
from flask import render_template, flash, jsonify, request
from . import app, db
from .forms import SupportTicketForm
from .models import SupportTicket

from twilio.jwt.client import ClientCapabilityToken
from twilio.twiml.voice_response import VoiceResponse, Dial


@app.route('/')
def root():
    form = SupportTicketForm()
    return render_template('home.html', form=form)


@app.route('/tickets', methods=['GET', 'POST'])
def new_ticket():
    success_message = "Your ticket was submitted! An agent will call you soon."
    form = SupportTicketForm()

    if form.validate_on_submit():
        ticket = SupportTicket(**form.data)
        db.session.add(ticket)
        db.session.commit()
        flash(success_message)
    return render_template('home.html', form=form)


@app.route('/dashboard', methods=['GET'])
def dashboard():
    support_tickets = SupportTicket.query.all()
    return render_template('support_dashboard.html', support_tickets=support_tickets)


@app.route('/support/token', methods=['GET'])
def get_token():
    """Returns a Twilio Client token"""
    # Create a TwilioCapability object with our Twilio API credentials
    capability = ClientCapabilityToken(
        app.config['TWILIO_ACCOUNT_SID'],
        app.config['TWILIO_AUTH_TOKEN'])

    # Allow our users to make outgoing calls with Twilio Client
    capability.allow_client_outgoing(app.config['TWIML_APPLICATION_SID'])

    # If the user is on the support dashboard page, we allow them to accept
    # incoming calls to "support_agent"
    # (in a real app we would also require the user to be authenticated)
    if request.args.get('forPage') == '/dashboard':
        capability.allow_client_incoming('support_agent')
    else:
        # Otherwise we give them a name of "customer"
        capability.allow_client_incoming('customer')

    # Generate the capability token
    token = capability.generate()

    return jsonify({'token': token})


@app.route('/support/call', methods=['POST'])
def call():
    """Returns TwiML instructions to Twilio's POST requests"""
    response = VoiceResponse()

    dial = Dial(callerId=app.config['TWILIO_NUMBER'])
    # If the browser sent a phoneNumber param, we know this request
    # is a support agent trying to call a customer's phone
    if 'phoneNumber' in request.form:
        dial.number(request.form['phoneNumber'])
    else:
        # Otherwise we assume this request is a customer trying
        # to contact support from the home page
        dial.client('support_agent')

    return str(response.append(dial))
browser_calls_flask/views.py
Generate a capability token

browser_calls_flask/views.py

Find your language and framework of choice below to get to the source code in your language and follow step-by-step instructions to learn how to build in-browser calling yourself:

Kat King

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

Loading Code Samples...
from flask import render_template, flash, jsonify, request
from . import app, db
from .forms import SupportTicketForm
from .models import SupportTicket

from twilio.jwt.client import ClientCapabilityToken
from twilio.twiml.voice_response import VoiceResponse, Dial


@app.route('/')
def root():
    form = SupportTicketForm()
    return render_template('home.html', form=form)


@app.route('/tickets', methods=['GET', 'POST'])
def new_ticket():
    success_message = "Your ticket was submitted! An agent will call you soon."
    form = SupportTicketForm()

    if form.validate_on_submit():
        ticket = SupportTicket(**form.data)
        db.session.add(ticket)
        db.session.commit()
        flash(success_message)
    return render_template('home.html', form=form)


@app.route('/dashboard', methods=['GET'])
def dashboard():
    support_tickets = SupportTicket.query.all()
    return render_template('support_dashboard.html', support_tickets=support_tickets)


@app.route('/support/token', methods=['GET'])
def get_token():
    """Returns a Twilio Client token"""
    # Create a TwilioCapability object with our Twilio API credentials
    capability = ClientCapabilityToken(
        app.config['TWILIO_ACCOUNT_SID'],
        app.config['TWILIO_AUTH_TOKEN'])

    # Allow our users to make outgoing calls with Twilio Client
    capability.allow_client_outgoing(app.config['TWIML_APPLICATION_SID'])

    # If the user is on the support dashboard page, we allow them to accept
    # incoming calls to "support_agent"
    # (in a real app we would also require the user to be authenticated)
    if request.args.get('forPage') == '/dashboard':
        capability.allow_client_incoming('support_agent')
    else:
        # Otherwise we give them a name of "customer"
        capability.allow_client_incoming('customer')

    # Generate the capability token
    token = capability.generate()

    return jsonify({'token': token})


@app.route('/support/call', methods=['POST'])
def call():
    """Returns TwiML instructions to Twilio's POST requests"""
    response = VoiceResponse()

    dial = Dial(callerId=app.config['TWILIO_NUMBER'])
    # If the browser sent a phoneNumber param, we know this request
    # is a support agent trying to call a customer's phone
    if 'phoneNumber' in request.form:
        dial.number(request.form['phoneNumber'])
    else:
        # Otherwise we assume this request is a customer trying
        # to contact support from the home page
        dial.client('support_agent')

    return str(response.append(dial))