Using the Hangouts Telephone API
Have you ever wanted to create a Hangout app that connects its users to a phone line? You could do all sorts of interesting things like bridge users to a help line or could make an app that would let users manage participants who are added over the phone…
The Google+ Hangouts Telephone API lets you do just this: place and manage outbound calls from Google+ Hangout apps. The API is great for performing various activities where a phone number is automatically added to a call.
In a basic example, you could have the Hangout dial a number when the Hangout begins, or could trigger a phone call through user interaction in the Hangout. In more complicated use cases, you might even want to also then send a series of phone tones over the line to the call at certain timings. This could open up a number of new possibilities ranging from letting users create DTMF music (e.g. “Funky town” on touch tones) to managing an automated calling system. The following video shows the demo:
You can get going easily by following the Quickstart instructions bellow and a full example with Twilio / Google+ hangout integration is provided, the Google+ Telephone Hangout Demo.
I have also added a start hangout button to let you launch the app on your own.
Quickstart: A basic app using the Telephone API
The following HTML represents a very basic Hangout app using the Telephone API (telephoneHangout.html):
<script src="//hangoutsapi.talkgadget.google.com/talkgadget/apps/gadgets/js/rpc.js"></script> <!-- set to developer channel --> <script src="//plus.google.com/hangouts/_/api/dev/hangout.js"></script> <body> <script> function init() { // When API is ready... gapi.hangout.onApiReady.add(function() { try { console.log("started"); var phoneNumber = gapi.hangout.getStartData(); // You should perform validation of gd, but for now, ignore. console.log(phoneNumber); document.getElementById("outputArea").innerHTML = "Dialing: " + phoneNumber + " based on initial data..."; gapi.hangout.telephone.beginCall(phoneNumber); } catch (e) { console.log('Error:'); console.log(e.stack); } }); } // Add startup listener immediately. If you need an // OAuth 2.0 access token, your startup will be different. init(); </script> <div id="outputArea"></div> </body>
To configure and run the app:
- Configure the hangout app in the developer console
- Start at: https://code.google.com/apis/
console - Click the red Create Project button
- Click APIs
- Turn on the Google+ Hangouts API
- Click the gear icon next to the Google+ API, this will open the hangouts settings
- Start at: https://code.google.com/apis/
- Upload the HTML file to the hangoutshoster / iframer tool
- Navigate to https://hostbot2000.appspot.
com - Drag and drop the HTML file onto the drop file here area
- The app will generate a URL (e.g. https://hangoutiframer.
appspot.com/forward/v0.4?u= ) that you will use in the next stephttps://www.googledrive.com/ host/ 0B0trNWWAuy5SLUQya3duOVdfQzQ/ telephoneHangout.html
- Navigate to https://hostbot2000.appspot.
- Configure the hangout app from the hangouts settings
- In the application URL field, add the url from the previous step
- Click the checkbox indicating “this application requires additional scopes”
- In the additional scopes field, add https://www.googleapis.
com/auth/hangout.telephone - Save the project ID for later, this is the section that comes after “https://code.google.com/apis/
console/b/0/?pli=1#project ” in the URL for the hangout setup screen, for example, if your URL is https://code.google.com/apis/console/b/0/?pli=1# , the project ID is 521280096254project:521280096254:hangout
- Create a client for the project from the developer console
- Return to your project from the first step
- Click “Registered apps”
- Click the red “Register app” button
- Select Web application
- Click register
- Launch the hangout passing in the phone number you want to dial
- To launch the hangout, you will need to form the URL to launch the hangout. The format is: https://hangoutsapi.
talkgadget.google.com/ APP_ID&gd=data where APP_ID is your app id from the second step and gd is the phone number to dial when the hangout beginshangouts/_?gid= - As an example, the following URL would launch the app and dial 206.555.1212: https://
hangoutsapi.talkgadget.google. com/hangouts/_?gid= 521280096254&gd=2065551212
- To launch the hangout, you will need to form the URL to launch the hangout. The format is: https://hangoutsapi.
So this is great, you can now place calls outbound from your hangout. How about we make it trickier! Let’s now pass tones to the number we’re dialing to perform various actions after the number is dialed.
Setting up a Twilio project for your fake call tree
Let’s create a call tree using the Twilio API. The tree will first prompt for a conference number then later will prompt for a participant code. The goal here is to pass extra values passed to the app in time for the tree to correctly handle them. I will not go into much detail for the Twilio API, their documentation is fantastic if you haven’t used it before. First, create the handler to receive the call [tapi.php]:
<?php header("content-type: text/xml"); echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ?> <Response> <Say>Let's do something using the Hangout Telephone API</Say> <Gather numDigits="5" action="magic.php" method="POST"> <Say>What's the magic tone?</Say> </Gather> </Response>
Next, another handler to accept a code [magic.php]:
<?php // if the caller pressed anything but 1 send them back if($_REQUEST['Digits'] != '12345') { header("Location: fail.php"); die; } header("content-type: text/xml"); echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ?> <Response> <Say>Very good.</Say> <Say>Now for the PIN.</Say> <Gather numDigits="4" action="magic2.php" method="POST"> </Gather> </Response>
A final handler for accepting a pin [magic2.php]:
<?php // if the caller pressed anything but 1 send them back if($_REQUEST['Digits'] != '7890') { header("Location: fail.php"); die; } header("content-type: text/xml"); echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ?> <Response> <Say>You just sunk my battleship</Say> <Play>http://wheresgus.com/tapi/tada.mp3</Play> </Response>
I also created a handler that will send a failure message, that is included in the project zip archive. If you have configured the project correctly and the Twilio API can see your PHP pages, you will now be able to dial your number, then punch in the first set of example tones (12345), punch in the second set of correct example tones (7890), and will then get the success sound.
Bringing it all together in the Hangout app
You’re now ready to automate using the Hangout app. You will have to first have a good way to pass data to your application and next will need to send the data programatically to the call.
Passing JSON data to the Hangout
Because we’ll be performing additional operations, it’s convenient to pass data as JSON to the Hangout app. The following URL shows you how to pass in a phone number and various additional values to the app: https://hangoutsapi.talkgadget.google.com/hangouts/_?gid=521280096254&gd={“number”: “2065551212”, “confCode”: “12345”, “leadPin”: “7890”} Now, when the app sees the JSON, it must parse it into an object:
// Global to store the start data and phone call var gPhone; var gCall; gapi.hangout.onApiReady.add(function() { try { console.log("started"); var startData = gapi.hangout.getStartData(); var phoneNumber = JSON.parse(startData); gPhone = phoneNumber; // You should perform validation of gd, but for now, ignore. gCall = gapi.hangout.telephone.beginCall(phoneNumber.number); } catch (e) { console.log('Error:'); console.log(e.stack); } });
At this point, you can pass additional commands to the call by making an API call to gCall.sendTone and have a record of various codes to pass to the phone.
Sending tones to the call
When you send tones to the call, you must pass them digit by digit as opposed to just passing a long string of values. This is done to give the developer full control of when the tones are sent. The following example function will send the global codes passed in the hangout start data to the call:
function sendCodeTones(){ console.log("Sending: " + gPhone.confCode); // Send numbers in sequence for (var i=0; i < gPhone.confCode.length; i++){ setTimeout("gCall.sendTone(gPhone.confCode[" + i + "])", i*250); } }
In my case, I’m using 250 ms delays between sending the tones, you could use longer or shorter values based on your PSTN.
The final implementation
Let’s look at a complete hangout app that will call, send tones when the call is ready to receive them, and then sends a second set of tones after that.
<script src="//hangoutsapi.talkgadget.google.com/talkgadget/apps/gadgets/js/rpc.js"></script> <!-- set to developer channel --> <script src="//plus.google.com/hangouts/_/api/dev/hangout.js"></script> <body> <script> var gPhone; var gCall; function init() { // When API is ready... gapi.hangout.onApiReady.add(function() { placeCall(); }); } function placeCall(){ console.log("started"); var startData = gapi.hangout.getStartData(); console.log(startData); var phoneNumber = JSON.parse(startData); console.log(phoneNumber); gPhone = phoneNumber; // You should perform validation of gd, but for now, ignore. document.getElementById("outputArea").innerHTML = "Dialing: " + phoneNumber.number + " based on initial data..."; gapi.hangout.telephone.onCallInitiated.add(callInitiatedEventHandler); gCall = gapi.hangout.telephone.beginCall(phoneNumber.number); } function sendCodeTones(){ console.log("Sending: " + gPhone.confCode); // Send numbers in sequence for (var i=0; i < gPhone.confCode.length; i++){ setTimeout("gCall.sendTone(gPhone.confCode[" + i + "])", i*250); } setTimeout("sendPinTones()", 5000); } function sendPinTones(){ console.log("Sending: " + gPhone.leadPin); // Send numbers in sequence for (var i=0; i < gPhone.leadPin.length; i++){ setTimeout("gCall.sendTone(gPhone.leadPin[" + i + "])", i*250); } } function callInitiatedEventHandler(call){ call.callInformation.onCallStateChanged.add(callStateChangedEventHandler); } function callStateChangedEventHandler(callState){ console.log("call state changed to:"); console.log(callState.newState); if (callState.newState == gapi.hangout.telephone.CallState.CONNECTED){ setTimeout("sendCodeTones()", 12000); } } // Add startup listener immediately. If you need an // OAuth 2.0 access token, your startup will be different. init(); </script> <div id="outputArea"></div> </body>
Now, when you run the app, you can pass in your Twilio phone number, start the call, pass in two sets of configurable codes, and will have everything automated within the hangout. As an example, the following code will initiate the call with my Twilio number and the appropriate codes: https://hangoutsapi.talkgadget.google.com/hangouts/_?gid=521280096254&gd={“number”: “(253) 214-3890”, “confCode”: “12345”, “leadPin”: “7890”} All of the project files used in the demo are available in the Hangout demo app zip. Have fun!
Additional Considerations
Passing the data as raw JSON in a GET request could cause issues if the user had a bad copy/paste and also could reveal information within the request. You could make the application more secure by passing an identifier rather than the raw JSON data to the application for the conference. The application would communicate with your server to retrieve the dial-in information securely based on an alternative value passed as start data to the Hangout app.
Does this actually work? I have been unable to get this working with the instructions above. Seems like there are some pieces/steps missing. Please help as this is EXACTLY what I’m wanting to accomplish.
Yes, it actually works! Sometimes the timing gets off because the window for responses in Twilio is short as I have it configured. I’ll try and put together a start a hangout button to demo the app for you.
As far as issues you are seeing, I’d be happy to help you get going. Is your hangout app getting successfully created? Are you having trouble with the Twilio end? There’s a couple moving parts in the demo.
I get internal server error while trying to upload the file to my google apps drive account
alternate-protocol:443:quic
content-length:323
content-type:text/html; charset=UTF-8
date:Thu, 20 Mar 2014 21:55:17 GMT
server:Google Frontend
status:500 Internal Server Error
version:HTTP/1.1
Just added a start hangout button for the demo: http://wheresgus.com/hophone/
Hi, I’m very interested in this… I had an idea to create a “hangout” button on my website that when pressed (by a visitor). It would open a hangout with them and keep them on had until I accepted the call.
Do you think this modification would be possible? I’m an absolute novice with all this api talk but very happy to learn.
It’s technically possible to do what you’re trying to do – you would have to figure out the right way to implement “caller on hold”.
This is very helpful. I’m having an issue when I try to make this app public. I checked the box on the Hangouts API page ‘Make your application available to all users’, and clicked Save. But when I try to execute the app, I’m getting an error; “There was an error loading your app!
This app did not load because there appears to be something wrong with it”. Any idea what might be happening?
Make sure that you are not getting a CORS / security related issue by visiting the hosted page that has your hangout xml/html. This way you can approve the certificate so that it is trusted in the hangout iframe. An alternative approach is to use something like hostbot2000.appspot.com / https://hangoutiframer.appspot.com/static/help.html to help you host your scripts on a secure host for testing.
As a non developer this is intriguing. We use Google Hangouts internally and Twilio/OpenVBX as our PBX. Does this provide a way to essentially replace Google Voice to dial out from Hangouts and use Twilio instead so we can combine inbound/outbound calling? If so is there a commercial or simply open source client/extension (Chrome extension even) we can acquire? Thanks.
You could probably build something out that would allow you to bridge via Twilio. The idea of an extension is a good idea. You should see what the Uber Conference folks are doing: https://www.uberconference.com/hangouts
Non-developer here as well 🙂 I’ve never used Hangouts, not even once, because I’ve read a lot of bad raps about the app – that it’s massively slow, bad voice quality, etc. Any truth to that?
Hi:
Is there a commercial / purchasable product/app here? We really like Twilio / OpenVBX and Google Hangouts. Google Voice (despite rumors of integrating in to Hangout) is just not good enough except for stand alone phone numbers.
We’re extremely interested in a Chrome/Hangouts app and, ideally, one for Android as well. M
Can anyone help?
Thanks
Mark
There are people using these features in real-world applications. If you end up doing any cool work with this, mention me on Google+ or chat about it in the Google+ developer discussion – https://plus.google.com/communities/113527920160449995981
Great article, thank you for putting it all together! What is the song that is playing in the background at the begging?
It’s Ja Rule ft. Ashanti – Always on time [video content slightly NSFW]
Gus, this looks pretty awesome, thanks! I can’t seem to find anything about using the google api to take incoming calls – do you know if it supports that?
I’m not sure and I don’t have an app to test this on-hand… but… check to see if you are able to get a callable number through the gapi.hangout.telephone.getPhoneNumber() method https://developers.google.com/+/hangouts/api/gapi.hangout.telephone#gapi.hangout.telephone.Call
Does Hangout API support incoming calls? If yes, how to handle them?
Not that I’m aware of, you can just add people to the call. The product team is aware of interest around the feature.
Hi Gguuss,
I’m using the most basic code to make a clickable phone call:
Is there anyway to change the default img or even better, is there a way to make it a clickable phone number instead of the img?
why i get ex message is “User may not make calls. This is either because the app doesn’t have the telephone OAuth scope or because the user is in a location from which calls are disabled.”, and gapi.hangout.isApiReady(); always is false
Hi,i try use code for call a phone number,thanks you for your guide.
but when i use code try a call ,my api ready is false .where i do wrong?can you help me?
https://hangoutsapi.talkgadget.google.com/hangouts/_?gid=521280096254&gd={“number”:”(253) 214-3890″,”confCode”:”12345″,”leadPin”:”7890″}
user this function var startData = gapi.hangout.getStartData();
startData is null ,what wrong?