<!DOCTYPE html><html><head><title>Twilio Click to Call for Heroku and Flask</title><!-- We use Twitter Bootstrap as the default styling for our page--><linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"><linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"><!-- Include CSS for our third-party telephone input jQuery plugin--><linkrel="stylesheet"href="/static/styles/intlTelInput.css"></head><body><divclass="container"><h1>Click To Call</h1><p> Click To Call converts your website's users into engaged customers by
creating an easy way for your customers to contact your sales and
support teams right on your website.
</p><p>Here's an example of how it's done!</p><hr><!-- C2C contact form--><divclass="row"><divclass="col-md-12"><formid="contactForm"role="form"><divclass="form-group"><h3>Call Sales</h3><pclass="help-block"> Are you interested in impressing your friends and
confounding your enemies? Enter your phone number
below, and our team will contact you right away.
</p></div><divclass="form-group"><inputtype="text"id="phoneNumber"placeholder="(651) 555-7889"class="form-control"></div><buttontype="submit"class="btn btn-default"> Contact Sales
</button></form></div></div></div><!-- Include page dependencies --><scriptsrc="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script><scriptsrc="/static/js/intlTelInput.min.js"></script><scriptsrc="/static/js/app.js"></script></body></html>

clicktocall/templates/index.html

A user facing web form

clicktocall/templates/index.html

Since the page doesn't need to render new content after clicking on submit, we decided to implement the POST action via Ajax using jQuery. Let's look at that next.

// Execute JavaScript on page load$(function(){// Initialize phone number text input plugin$('#phoneNumber').intlTelInput({responsiveDropdown:true,autoFormat:true,utilsScript:'/static/js/libphonenumber/src/utils.js'});// Intercept form submission and submit the form with ajax$('#contactForm').on('submit',function(e){// Prevent submit event from bubbling and automatically// submitting the forme.preventDefault();// Call our ajax endpoint on the server to initialize the// phone call$.ajax({url:'/call',method:'POST',dataType:'json',data:{phoneNumber:$('#phoneNumber').val()}}).done(function(data){// The JSON sent back from the server will contain// a success messagealert(data.message);}).fail(function(error){alert(JSON.stringify(error));});});});

clicktocall/static/js/app.js

'Submit' the web form with jQuery

clicktocall/static/js/app.js

Now that we have the front end done let's build the backend. We'll explore in the next step.

First, we instantiate a TwilioRestClient object with our Account SID and Auth Token.

This is essentially our Python REST API handler, which we could use to send SMSes (or a myriad of other things). But for now, we just need it to get access to the object that we're going to use to create phone calls.

fromflaskimportFlaskfromflaskimportjsonifyfromflaskimportrender_templatefromflaskimportrequestfromflaskimporturl_forfromtwilio.twiml.voice_responseimportVoiceResponsefromtwilio.restimportClient# Declare and configure applicationapp=Flask(__name__,static_url_path='/static')app.config.from_pyfile('local_settings.py')# Route for Click to Call demo page.@app.route('/')defindex():returnrender_template('index.html',configuration_error=None)# Voice Request URL@app.route('/call',methods=['POST'])defcall():# Get phone number we need to callphone_number=request.form.get('phoneNumber',None)try:twilio_client=Client(app.config['TWILIO_ACCOUNT_SID'],app.config['TWILIO_AUTH_TOKEN'])exceptExceptionase:msg='Missing configuration variable: {0}'.format(e)returnjsonify({'error':msg})try:twilio_client.calls.create(from_=app.config['TWILIO_CALLER_ID'],to=phone_number,url=url_for('.outbound',_external=True))exceptExceptionase:app.logger.error(e)returnjsonify({'error':str(e)})returnjsonify({'message':'Call incoming!'})@app.route('/outbound',methods=['POST'])defoutbound():response=VoiceResponse()response.say("Thank you for contacting our sales department. If this ""click to call application was in production, we would ""dial out to your sales team with the Dial verb.",voice='alice')''' # Uncomment this code and replace the number with the number you want # your customers to call. response.number("+16518675309") '''returnstr(response)# Route for Landing Page after Heroku deploy.@app.route('/landing.html')deflanding():returnrender_template('landing.html',configuration_error=None)

clicktocall/app.py

Application Core Controller

Next we'll use the create method from the calls object to make an outgoing phone call. This requires us to pass a From number, a To number and a URL parameter that tells Twilio what to do after it connects the call to our user.

In this case Twilio needs to dial in the Agent once the call has been placed. We'll discuss this more in the next step.

fromflaskimportFlaskfromflaskimportjsonifyfromflaskimportrender_templatefromflaskimportrequestfromflaskimporturl_forfromtwilio.twiml.voice_responseimportVoiceResponsefromtwilio.restimportClient# Declare and configure applicationapp=Flask(__name__,static_url_path='/static')app.config.from_pyfile('local_settings.py')# Route for Click to Call demo page.@app.route('/')defindex():returnrender_template('index.html',configuration_error=None)# Voice Request URL@app.route('/call',methods=['POST'])defcall():# Get phone number we need to callphone_number=request.form.get('phoneNumber',None)try:twilio_client=Client(app.config['TWILIO_ACCOUNT_SID'],app.config['TWILIO_AUTH_TOKEN'])exceptExceptionase:msg='Missing configuration variable: {0}'.format(e)returnjsonify({'error':msg})try:twilio_client.calls.create(from_=app.config['TWILIO_CALLER_ID'],to=phone_number,url=url_for('.outbound',_external=True))exceptExceptionase:app.logger.error(e)returnjsonify({'error':str(e)})returnjsonify({'message':'Call incoming!'})@app.route('/outbound',methods=['POST'])defoutbound():response=VoiceResponse()response.say("Thank you for contacting our sales department. If this ""click to call application was in production, we would ""dial out to your sales team with the Dial verb.",voice='alice')''' # Uncomment this code and replace the number with the number you want # your customers to call. response.number("+16518675309") '''returnstr(response)# Route for Landing Page after Heroku deploy.@app.route('/landing.html')deflanding():returnrender_template('landing.html',configuration_error=None)

fromflaskimportFlaskfromflaskimportjsonifyfromflaskimportrender_templatefromflaskimportrequestfromflaskimporturl_forfromtwilio.twiml.voice_responseimportVoiceResponsefromtwilio.restimportClient# Declare and configure applicationapp=Flask(__name__,static_url_path='/static')app.config.from_pyfile('local_settings.py')# Route for Click to Call demo page.@app.route('/')defindex():returnrender_template('index.html',configuration_error=None)# Voice Request URL@app.route('/call',methods=['POST'])defcall():# Get phone number we need to callphone_number=request.form.get('phoneNumber',None)try:twilio_client=Client(app.config['TWILIO_ACCOUNT_SID'],app.config['TWILIO_AUTH_TOKEN'])exceptExceptionase:msg='Missing configuration variable: {0}'.format(e)returnjsonify({'error':msg})try:twilio_client.calls.create(from_=app.config['TWILIO_CALLER_ID'],to=phone_number,url=url_for('.outbound',_external=True))exceptExceptionase:app.logger.error(e)returnjsonify({'error':str(e)})returnjsonify({'message':'Call incoming!'})@app.route('/outbound',methods=['POST'])defoutbound():response=VoiceResponse()response.say("Thank you for contacting our sales department. If this ""click to call application was in production, we would ""dial out to your sales team with the Dial verb.",voice='alice')''' # Uncomment this code and replace the number with the number you want # your customers to call. response.number("+16518675309") '''returnstr(response)# Route for Landing Page after Heroku deploy.@app.route('/landing.html')deflanding():returnrender_template('landing.html',configuration_error=None)

clicktocall/app.py

Application Core Controller

clicktocall/app.py

Next we will see how to generate the TwiML required for Twilio to take actions on behalf of our application.

TwiML is a set of simple verbs and nouns written in XML that Twilio reads as instructions.

In this case our instructions inform Twilio to simply SAY something to the user. If we wanted to connect the user to a real support agent, we would have to add a Dial verb that specifies the support agent number so the customer can talk to him or her.

In order to make writing TwiML easy, many of the helper libraries have methods that generate TwiML for you. In this case we use the twilio Python library to create a TwiML response that will instruct Twilio to say something.

fromflaskimportFlaskfromflaskimportjsonifyfromflaskimportrender_templatefromflaskimportrequestfromflaskimporturl_forfromtwilio.twiml.voice_responseimportVoiceResponsefromtwilio.restimportClient# Declare and configure applicationapp=Flask(__name__,static_url_path='/static')app.config.from_pyfile('local_settings.py')# Route for Click to Call demo page.@app.route('/')defindex():returnrender_template('index.html',configuration_error=None)# Voice Request URL@app.route('/call',methods=['POST'])defcall():# Get phone number we need to callphone_number=request.form.get('phoneNumber',None)try:twilio_client=Client(app.config['TWILIO_ACCOUNT_SID'],app.config['TWILIO_AUTH_TOKEN'])exceptExceptionase:msg='Missing configuration variable: {0}'.format(e)returnjsonify({'error':msg})try:twilio_client.calls.create(from_=app.config['TWILIO_CALLER_ID'],to=phone_number,url=url_for('.outbound',_external=True))exceptExceptionase:app.logger.error(e)returnjsonify({'error':str(e)})returnjsonify({'message':'Call incoming!'})@app.route('/outbound',methods=['POST'])defoutbound():response=VoiceResponse()response.say("Thank you for contacting our sales department. If this ""click to call application was in production, we would ""dial out to your sales team with the Dial verb.",voice='alice')''' # Uncomment this code and replace the number with the number you want # your customers to call. response.number("+16518675309") '''returnstr(response)# Route for Landing Page after Heroku deploy.@app.route('/landing.html')deflanding():returnrender_template('landing.html',configuration_error=None)

clicktocall/app.py

Connect an 'agent' to the user

clicktocall/app.py

And that's it!

We've just implemented click to call on our web page that will allow customers to connect with a support agent. You're ready to add it to your application!

<!DOCTYPE html><html><head><title>Twilio Click to Call for Heroku and Flask</title><!-- We use Twitter Bootstrap as the default styling for our page--><linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"><linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"><!-- Include CSS for our third-party telephone input jQuery plugin--><linkrel="stylesheet"href="/static/styles/intlTelInput.css"></head><body><divclass="container"><h1>Click To Call</h1><p> Click To Call converts your website's users into engaged customers by
creating an easy way for your customers to contact your sales and
support teams right on your website.
</p><p>Here's an example of how it's done!</p><hr><!-- C2C contact form--><divclass="row"><divclass="col-md-12"><formid="contactForm"role="form"><divclass="form-group"><h3>Call Sales</h3><pclass="help-block"> Are you interested in impressing your friends and
confounding your enemies? Enter your phone number
below, and our team will contact you right away.
</p></div><divclass="form-group"><inputtype="text"id="phoneNumber"placeholder="(651) 555-7889"class="form-control"></div><buttontype="submit"class="btn btn-default"> Contact Sales
</button></form></div></div></div><!-- Include page dependencies --><scriptsrc="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script><scriptsrc="/static/js/intlTelInput.min.js"></script><scriptsrc="/static/js/app.js"></script></body></html>

// Execute JavaScript on page load$(function(){// Initialize phone number text input plugin$('#phoneNumber').intlTelInput({responsiveDropdown:true,autoFormat:true,utilsScript:'/static/js/libphonenumber/src/utils.js'});// Intercept form submission and submit the form with ajax$('#contactForm').on('submit',function(e){// Prevent submit event from bubbling and automatically// submitting the forme.preventDefault();// Call our ajax endpoint on the server to initialize the// phone call$.ajax({url:'/call',method:'POST',dataType:'json',data:{phoneNumber:$('#phoneNumber').val()}}).done(function(data){// The JSON sent back from the server will contain// a success messagealert(data.message);}).fail(function(error){alert(JSON.stringify(error));});});});

fromflaskimportFlaskfromflaskimportjsonifyfromflaskimportrender_templatefromflaskimportrequestfromflaskimporturl_forfromtwilio.twiml.voice_responseimportVoiceResponsefromtwilio.restimportClient# Declare and configure applicationapp=Flask(__name__,static_url_path='/static')app.config.from_pyfile('local_settings.py')# Route for Click to Call demo page.@app.route('/')defindex():returnrender_template('index.html',configuration_error=None)# Voice Request URL@app.route('/call',methods=['POST'])defcall():# Get phone number we need to callphone_number=request.form.get('phoneNumber',None)try:twilio_client=Client(app.config['TWILIO_ACCOUNT_SID'],app.config['TWILIO_AUTH_TOKEN'])exceptExceptionase:msg='Missing configuration variable: {0}'.format(e)returnjsonify({'error':msg})try:twilio_client.calls.create(from_=app.config['TWILIO_CALLER_ID'],to=phone_number,url=url_for('.outbound',_external=True))exceptExceptionase:app.logger.error(e)returnjsonify({'error':str(e)})returnjsonify({'message':'Call incoming!'})@app.route('/outbound',methods=['POST'])defoutbound():response=VoiceResponse()response.say("Thank you for contacting our sales department. If this ""click to call application was in production, we would ""dial out to your sales team with the Dial verb.",voice='alice')''' # Uncomment this code and replace the number with the number you want # your customers to call. response.number("+16518675309") '''returnstr(response)# Route for Landing Page after Heroku deploy.@app.route('/landing.html')deflanding():returnrender_template('landing.html',configuration_error=None)

fromflaskimportFlaskfromflaskimportjsonifyfromflaskimportrender_templatefromflaskimportrequestfromflaskimporturl_forfromtwilio.twiml.voice_responseimportVoiceResponsefromtwilio.restimportClient# Declare and configure applicationapp=Flask(__name__,static_url_path='/static')app.config.from_pyfile('local_settings.py')# Route for Click to Call demo page.@app.route('/')defindex():returnrender_template('index.html',configuration_error=None)# Voice Request URL@app.route('/call',methods=['POST'])defcall():# Get phone number we need to callphone_number=request.form.get('phoneNumber',None)try:twilio_client=Client(app.config['TWILIO_ACCOUNT_SID'],app.config['TWILIO_AUTH_TOKEN'])exceptExceptionase:msg='Missing configuration variable: {0}'.format(e)returnjsonify({'error':msg})try:twilio_client.calls.create(from_=app.config['TWILIO_CALLER_ID'],to=phone_number,url=url_for('.outbound',_external=True))exceptExceptionase:app.logger.error(e)returnjsonify({'error':str(e)})returnjsonify({'message':'Call incoming!'})@app.route('/outbound',methods=['POST'])defoutbound():response=VoiceResponse()response.say("Thank you for contacting our sales department. If this ""click to call application was in production, we would ""dial out to your sales team with the Dial verb.",voice='alice')''' # Uncomment this code and replace the number with the number you want # your customers to call. response.number("+16518675309") '''returnstr(response)# Route for Landing Page after Heroku deploy.@app.route('/landing.html')deflanding():returnrender_template('landing.html',configuration_error=None)

fromflaskimportFlaskfromflaskimportjsonifyfromflaskimportrender_templatefromflaskimportrequestfromflaskimporturl_forfromtwilio.twiml.voice_responseimportVoiceResponsefromtwilio.restimportClient# Declare and configure applicationapp=Flask(__name__,static_url_path='/static')app.config.from_pyfile('local_settings.py')# Route for Click to Call demo page.@app.route('/')defindex():returnrender_template('index.html',configuration_error=None)# Voice Request URL@app.route('/call',methods=['POST'])defcall():# Get phone number we need to callphone_number=request.form.get('phoneNumber',None)try:twilio_client=Client(app.config['TWILIO_ACCOUNT_SID'],app.config['TWILIO_AUTH_TOKEN'])exceptExceptionase:msg='Missing configuration variable: {0}'.format(e)returnjsonify({'error':msg})try:twilio_client.calls.create(from_=app.config['TWILIO_CALLER_ID'],to=phone_number,url=url_for('.outbound',_external=True))exceptExceptionase:app.logger.error(e)returnjsonify({'error':str(e)})returnjsonify({'message':'Call incoming!'})@app.route('/outbound',methods=['POST'])defoutbound():response=VoiceResponse()response.say("Thank you for contacting our sales department. If this ""click to call application was in production, we would ""dial out to your sales team with the Dial verb.",voice='alice')''' # Uncomment this code and replace the number with the number you want # your customers to call. response.number("+16518675309") '''returnstr(response)# Route for Landing Page after Heroku deploy.@app.route('/landing.html')deflanding():returnrender_template('landing.html',configuration_error=None)

fromflaskimportFlaskfromflaskimportjsonifyfromflaskimportrender_templatefromflaskimportrequestfromflaskimporturl_forfromtwilio.twiml.voice_responseimportVoiceResponsefromtwilio.restimportClient# Declare and configure applicationapp=Flask(__name__,static_url_path='/static')app.config.from_pyfile('local_settings.py')# Route for Click to Call demo page.@app.route('/')defindex():returnrender_template('index.html',configuration_error=None)# Voice Request URL@app.route('/call',methods=['POST'])defcall():# Get phone number we need to callphone_number=request.form.get('phoneNumber',None)try:twilio_client=Client(app.config['TWILIO_ACCOUNT_SID'],app.config['TWILIO_AUTH_TOKEN'])exceptExceptionase:msg='Missing configuration variable: {0}'.format(e)returnjsonify({'error':msg})try:twilio_client.calls.create(from_=app.config['TWILIO_CALLER_ID'],to=phone_number,url=url_for('.outbound',_external=True))exceptExceptionase:app.logger.error(e)returnjsonify({'error':str(e)})returnjsonify({'message':'Call incoming!'})@app.route('/outbound',methods=['POST'])defoutbound():response=VoiceResponse()response.say("Thank you for contacting our sales department. If this ""click to call application was in production, we would ""dial out to your sales team with the Dial verb.",voice='alice')''' # Uncomment this code and replace the number with the number you want # your customers to call. response.number("+16518675309") '''returnstr(response)# Route for Landing Page after Heroku deploy.@app.route('/landing.html')deflanding():returnrender_template('landing.html',configuration_error=None)