How to Capture Call Tracking Metrics in Google Analytics with Twilio Programmable Voice

September 21, 2018
Written by
Paul Mathews
Contributor
Opinions expressed by Twilio contributors are their own

ltOUdTd-dYkNZuIaeLWSAPxIOuyhQ2SNallORRW2pGsk583eMbqp9Cf8awXkSIxr9P7uR12XqdKs9njGkI853Y2yqiQHaAEgxaS-JkwcVGfZUC65Te85RjkMgBKxte86QJihu3m5

Call tracking involves saving a phone number and recording related the information about the calls made by that number. The metrics can then be used to measure the impact of marketing efforts on lead generation and sales.

Say that you are an entrepreneur or the marketing head of an organization and your main source of leads are phone calls. To spend your marketing dollars wisely, you will have to know which of your campaigns generate the maximum number of calls. This can be done using a call tracking system.

Call tracking systems used to be very expensive and cumbersome. However, in this blog post we will create an easy call tracking system that combines the powers of Twilio and Google Analytics to give you a very detailed picture of the calls and locations of these calls.

Configuring Google Analytics

Start by logging into your Google Analytics account or signing up for a new one.

Go to Admin->create account-> give the specification for website tracking. In the required column enter any website name and url (for example, www.example.com), also select the category as industry. To get the Tracking Id Go to Admin -> property ->Property Settings->you can now see the Tracking ID. Take a note of the tracking ID because it is needed to connect a Twilio Function to your Google Analytics property.

Log in to your Twilio account or sign up for a new account.

Go to Runtime, Select “Function”, and then click “+” symbol and select the “Call Forward" Function template. Press "Create".

Open the Function and give the function name and the path as your choice. This Function path is needed later so, copy this path and save the Function.

We can now associate our Twilio number with the Google Analytics tracking ID.

Associating Phone Numbers with Tracking IDs

Go to Phone Numbers (# icon in menu) in your Twilio account and select a Twilio number from the list of active numbers. If you don't yet have a number, buy a number and then go to Phone Numbers and select the number from the list of active numbers. After selecting the number, go to Voice & Fax option and select Voice calls. In the “A CALL COMES IN” box, set it as webhook and provide the details in the empty box beside it, in the following format:

Paste your function path followed by a question mark then "PhoneNumber=(here set the actual phone number which you need to be forward all the calls". Remove the spaces and hyphens in the number) then "&campaign=(here set campaign name of the number you have currently selected))&trackingId=(here set the tracking Id you got from google analytics)".

It's much easier to see in an example:


https://glorious-front-7473.twil.io/callforward?PhoneNumber=+19876543210&campaign=abc_business&trackingId=UA-123456789-1

Save the changes. You can also change the phone numbers for different campaign for the same tracking ID.

Go back to Runtime ->Go to Twilio function and Create Another blank function similar to the one that you created for call forward function. Give the function name as Call Action and path as /call_action and save the function.

Coding Call Forwarding

Go back to the call forward function. This function is used to forward calls that are received by your twilio campaign numbers to the actual phone number of your business through Webhook(HTTP post). The call forward function accepts three parameters i.e., campaign, actual phone number and tracking Id of your google analytics account. Paste the following code in the box provided and save the function.  

Here is the code for Call Forward function:

exports.handler = function(context, event, callback) {
    let phoneNumber = event.PhoneNumber; 
    let campaign = event.campaign;
    let trackingId = event.trackingId;
    let domain = context.DOMAIN_NAME;
    let twiml = new Twilio.twiml.VoiceResponse();
    let allowedThrough = true;
//Checking campaign is given or not. If there is no campaign_name the call is not forwarding to another number
    if (campaign === null) {
        allowedThrough = false;
    }
    let dialParams = {};
    if (campaign) {
        dialParams.campaign = campaign;
    }

var actionUrl ='https://'+domain+'/call_action?PhoneNumber='+phoneNumber+'&campaign='+campaign+'&trackingId='+trackingId;

    if (allowedThrough) {
        twiml.dial(
           {
           action :encodeURI(actionUrl),
           method:'GET'
           },phoneNumber
        );
    }
    else {
        twiml.say('Sorry, you are calling from a restricted number. Goodbye.');
    }
// return the TwiML
    callback(null, twiml);
};

The above function is used to forward calls to actual phone number. When the call ends, call action function is called by passing parameters such as phonenumber, campaign and tracking ID through action URL.

Linking the system with Google Analytics

Go back to the call action function and paste the following code in the box provided and save the function. This function is used to get a call details and callers geo location and report to google analytics (by your tracking ID of your analytics account) through the Events API.

Here is the code for updating events API:

exports.handler = function(context, event, callback) {
var http = require('http'); 
const analyticsID  = event.trackingId; 
const gaUrl = "http://www.google-analytics.com/collect?v=1&t=event&tid="+analyticsID+"&";
function sendAnalyticsEvent(eventParams,callback) {
   var url = gaUrl+eventParams;
   http.get(url, function(res) {
       if(res.statusCode === 200){
            console.log("Sent event: status="+res.statusCode+", params", eventParams);
            let twiml = new Twilio.twiml.VoiceResponse();
            twiml.hangup();
            callback(null, twiml);
       }
   }).on('error', function(e) {
       console.log("Sent event: error="+e.message+", params", eventParams);
       let twiml = new Twilio.twiml.VoiceResponse();
       twiml.say('Sorry, there is an error in reporting analyitics. Good bye.');
       callback(null, twiml);
   });
}
    var callerGeoDetail = GeoCode(event.From);
    var callerGeoCode   = callerGeoDetail["code"];
    var contact = event.From;
    var Duration = event.DialCallDuration;
    var CallStatus = event.DialCallStatus;
    if(Duration === undefined){ Duration=0;}
    var eventParams = "ec=Call&ea="+CallStatus+"&ev="+Duration+"&el="+event.campaign+"&t=event&v=1&cid="+contact;
    eventParams += "&geoid="+callerGeoCode;
    sendAnalyticsEvent(eventParams,callback);
};
function GeoCode(number) {
    var _4DigitgeoCodeMapping = get4DigitGeoCodeMapping();
    var _3DigitgeoCodeMapping = get3DigitGeoCodeMapping();
    var _2DigitgeoCodeMapping = get2DigitGeoCodeMapping();
    var _1DigitgeoCodeMapping = get1DigitGeoCodeMapping();
    var get4DigitCallingCode  = number.substring(1, 5);
    var get3DigitCallingCode  = number.substring(1, 4);
    var get2DigitCallingCode  = number.substring(1, 3);
    var get1DigitCallingCode  = number.substring(1, 2);
    var geoCode = _4DigitgeoCodeMapping[get4DigitCallingCode] || _3DigitgeoCodeMapping[get3DigitCallingCode] || _2DigitgeoCodeMapping[get2DigitCallingCode] || _1DigitgeoCodeMapping[get1DigitCallingCode] || "2270";
    console.log("geoCode",geoCode);
    if(geoCode == "20117") // mapping of area code for US or Canadian number.
    {
        var areaCodeToGeoCodeMapping = getAreaCodeToGeoCodeMapping();
        var areaCode    = number.substring(2, 5);
        var geoAreaCode     = areaCodeToGeoCodeMapping[areaCode] || "20117";
        var geoAreaDetails  = {"code": geoAreaCode};
        console.log("geoDetails",geoAreaDetails);
        return geoAreaDetails;
    }
    else{
        var geoDetails = {"code": geoCode};
        console.log("geoDetails",geoDetails);
        return geoDetails;
    }
}

function get4DigitGeoCodeMapping(){
    return{
        "1473": "21137", "1671": "2316", "1876": "2388", "1664": "2500", "1670": "2580", "1787": "2630", "1939": "2630", "1869": "2659", "1758": "2662", "1784": "2670", "1868": "2780", "1649": "2796", "1284": "2850", "1340": "2850", "1684": "2882", "1264": "2660", "1268": "2028", "1242": "2044", "1246": "2052", "1441": "2060", "1345": "2136", "1767": "2212", "1809": "2212", "1828": "2212", "1849": "2212"
    };
}
function get3DigitGeoCodeMapping(){
    return{      
"355": "2008", "213": "2012", "376": "2020", "244": "2024", "374": "21519", "297": "2533", "994": "2031", "973": "2048", "880": "2050", "375": "2112", "501": "2084", "229": "2204", "975": "2064", "591": "2068", "387": "2070", "267": "2072", "673": "2096", "359": "2100", "226": "2854", "257": "2108", "855": "2116", "237": "2120", "238": "2132", "236": "2140", "235": "2148", "618": "2162", "269": "2174", "242": "2178", "243": "2180", "682": "2184", "506": "2188", "225": "2430", "385": "2191", "357": "2196", "420": "2203", "253": "2262", "593": "20264", "503": "2222", "240": "2226", "291": "2232", "372": "2233", "251": "2231", "500": "2238", "298": "2234", "679": "2242", "358": "2246", "594": "2254", "689": "2258", "241": "2266", "220": "2270", "995": "2268", "233": "2288", "350": "2292", "299": "2304", "590": "2312", "502": "2320", "224":"2324", "245":"2324", "592": "2328", "509": "2332", "379":"2336", "504":"2340", "852":"2344", "354":"2352", "964": "2368", "353": "2372", "972":"2376", "962":"2400", "254":"2404", "686":"2296", "850": "21331", "965": "2414", "996":"2417", "856":"2418", "371":"2428", "961":"2422", "266": "2426", "231": "2430", "218": "2434", "423": "2438", "370": "2440", "352": "2442", "853": "2446", "389": "2807", "261": "2450", "265": "2454", "960": "2462", "223": "2466", "356": "2470", "692": "2584", "596": "2474", "222": "2478", "230": "2480", "262": "2175", "691": "2583", "373": "2498", "377": "2492", "976": "20167", "382": "2499", "212": "2504", "258": "2508", "264": "2516", "674":"2520", "977": "2524", "599": "2530", "687": "2540", "505": "2558", "227": "2562", "234": "2566", "683": "2570", "672": "2574", "968": "2512", "680": "2585", "970": "2376", "507": "21142", "675": "2598", "595": "2600", "870": "2612", "351": "2620", "974": "2634", "250": "2646", "290": "2682", "508": "2666", "685": "2882", "378": "21137", "239": "2678", "966": "2682", "221": "2686", "381": "2688", "248": "2690", "232": "2694", "421": "2703", "386": "2705", "677": "2090", "252": "2706", "249": "21176", "597": "2740", "268": "2748", "963": "2368", "886": "2158", "992": "2762", "255": "2834", "670": "2626", "228": "2768", "690": "2772", "676": "2776", "216":"2788", "993": "2795", "688": "2798", "256": "2800", "380": "2804", "971": "2784", "598": "2858", "998": "2860", "678": "2548", "681": "2876", "967": "2887", "260": "2894", "263": "2716"
    };
}

function get2DigitGeoCodeMapping(){
    return{                                     
"93": "2004", "54": "20008", "61": "20035", "43": "20048", "32": "2056", "55": "20088", "57": "20114", "53": "21147", "45": "21154", "20": "21164", "33": "20332", "49": "20235", "30": "2300", "36": "2348", "91": "2356", "62": "2360", "98": "2368", "81": "20624", "76": "2398", "77": "2398", "82": "21331", "60": "20737", "52": "21142", "31": "2528", "64": "2554", "92": "2586", "51": "2604", "63": "2608", "48": "20862", "40": "21244", "65": "2702", "27": "21222", "34": "20282", "94": "2144", "47": "2744", "46": "21014", "41": "20133", "66": "21044", "90": "21354", "44": "20339", "58": "21204", "84": "21044"    
    };
}
function get1DigitGeoCodeMapping(){
    return{
        "1":"20117","7":"20931"
    };
}

function getAreaCodeToGeoCodeMapping() {
    return {
        "907": "21132", "205": "21133", "251": "21133", "256": "21133", "334": "21133", "479": "21135", "501": "21135", "870": "21135", "480": "21136", "520": "21136", "602": "21136", "623": "21136", "928": "21136", "209": "21137", "213": "21137", "310": "21137", "323": "21137", "408": "21137", "415": "21137", "424": "21137", "510": "21137", "530": "21137", "559": "21137", "562": "21137", "619": "21137", "626": "21137", "650": "21137", "661": "21137", "707": "21137", "714": "21137", "760": "21137", "805": "21137", "818": "21137", "831": "21137", "858": "21137", "909": "21137", "916": "21137", "925": "21137", "949": "21137", "303": "21138", "719": "21138", "720": "21138", "970": "21138", "203": "21139", "475": "21139", "860": "21139", "959": "21139", "202": "21140", "302": "21141", "239": "21142", "305": "21142", "321": "21142", "352": "21142", "386": "21142", "407": "21142", "561": "21142", "727": "21142", "754": "21142", "772": "21142", "786": "21142", "813": "21142", "850": "21142", "863": "21142", "904": "21142", "941": "21142", "954": "21142", "229": "21143", "404": "21143", "470": "21143", "478": "21143", "678": "21143", "706": "21143", "770": "21143", "912": "21143", "808": "21144", "319": "21145", "515": "21145", "563": "21145", "641": "21145", "712": "21145", "208": "21146", "217": "21147", "224": "21147", "309": "21147", "312": "21147", "331": "21147", "464": "21147", "618": "21147", "630": "21147", "708": "21147", "773": "21147", "815": "21147", "847": "21147", "872": "21147", "219": "21148", "260": "21148", "317": "21148", "574": "21148", "765": "21148", "812": "21148", "316": "21149", "620": "21149", "785": "21149", "913": "21149", "270": "21150", "502": "21150", "606": "21150", "859": "21150", "225": "21151", "318": "21151", "337": "21151", "504": "21151", "985": "21151", "339": "21152", "351": "21152", "413": "21152", "508": "21152", "617": "21152", "774": "21152","781": "21152", "857": "21152", "978": "21152", "227": "21153", "240": "21153", "301": "21153", "410": "21153", "443": "21153", "667": "21153", "207": "21154", "231": "21155", "248": "21155", "269": "21155", "313": "21155", "517": "21155", "586": "21155", "616": "21155", "734": "21155", "810": "21155", "906": "21155", "947": "21155","989": "21155", "218": "21156", "320": "21156", "507": "21156", "612": "21156", "651": "21156", "763": "21156", "952": "21156", "314": "21157", "417": "21157", "557": "21157", "573": "21157", "636": "21157", "660": "21157", "816": "21157", "975": "21157", "228": "21158", "601": "21158", "662": "21158", "406": "21159", "252": "21160", "336": "21160", "704": "21160", "828": "21160", "910": "21160", "919": "21160", "980": "21160", "984": "21160", "701": "21161", "308": "21162", "402": "21162", "603": "21163", "201": "21164", "551": "21164", "609": "21164", "732": "21164", "848": "21164", "856": "21164", "862": "21164", "908": "21164", "973": "21164", "505": "21165", "702": "21166", "775": "21166", "212": "21167", "315": "21167", "347": "21167", "516": "21167", "518": "21167", "585": "21167", "607": "21167", "631": "21167", "646": "21167", "716": "21167", "718": "21167", "845": "21167", "914": "21167", "917": "21167", "216": "21168", "234": "21168", "283": "21168", "330": "21168", "419": "21168", "440": "21168", "513": "21168", "567": "21168", "614": "21168", "740": "21168", "937": "21168", "405": "21169", "580": "21169", "918": "21169", "503": "21170", "541": "21170", "971": "21170", "215": "21171", "267": "21171", "412": "21171", "445": "21171", "484": "21171", "570": "21171", "610": "21171", "717": "21171", "724": "21171", "814": "21171", "835": "21171", "878": "21171", "401": "21172", "803": "21173", "843": "21173", "864": "21173", "605": "21174", "423": "21175", "615": "21175", "731": "21175", "865": "21175", "901": "21175", "931": "21175", "210": "21176", "214": "21176", "254": "21176", "281": "21176", "361": "21176", "409": "21176", "469": "21176", "512": "21176", "682": "21176", "713": "21176", "737": "21176", "806": "21176", "817": "21176", "830": "21176", "832": "21176", "903": "21176", "915": "21176", "936": "21176", "940": "21176", "956": "21176", "972": "21176", "979": "21176", "435": "21177", "801": "21177", "276": "21178", "434": "21178", "540": "21178", "571": "21178", "703": "21178", "757": "21178", "804": "21178", "802": "21179", "206": "21180", "253": "21180", "360": "21180", "425": "21180", "509": "21180", "564": "21180", "262": "21182", "414": "21182", "608": "21182", "715": "21182", "920": "21182", "304": "21183", "307": "21184"
    };
}

In the above code you can see,

  1. sendAnalyticsEvent function, which is used to report events(call duration, call status and callers location)  to analytics through events api.
  2. GeoCode function, which is used to find callers location. It takes country code from the callers number. The country code varies from one to four digits. The country code is mapped to a Google Map’s geocode for placement in the map. There are four separate mapping tables, each corresponding to the number of digits in area code. First, the country code is assumed to be 4 digits and the mapping is obtained from the get4DigitGeoCodeMapping function. If no map is obtained, it is assumed to be 3 digits and the mapping is obtained from get3DigitGeoCodeMapping function. This process is continued until the get1DigitGeoCodeMapping. If no map is found, it maps to Gambia country by default.
  3. getDigitGeoCodeMapping functions are used to map country code to google geocode.
  4. getAreaCodetoGeoCodeMapping function is used to map area code of US and Canada to geo-caller Id.

Note that calls are tagged at the country level. However, calls from US and Canada are further resolved to the state or province in Google Analytics. Calls from any unknown country are marked as Gambia.

After completing these steps, you can test it by calling to the Twilio number you have setup. The call will be forwarded to the actual number.

Viewing Results in Google Analytics

The results can be viewed in the Google Analytics account you created in step 1. Login to Google Analytics, go to real-time, select events there you can see the live results of call tracking as given in the below figure:

To see the location of the caller. Go to Audience -> geo ->  location.

To see the accumulated results of the call tracking, Go to Behaviour ->Events->Overview.

This Overview represents the call tracking data over a month. The present day details are noted in real-time->events. You can select the range of the days at the right top of your window.

In the above events graph,

1. Total events : Total number of calls.

2. Unique events : Total number of unique calls.

3. Event value : total call duration for all calls.

4. Average value : Average call duration.

To see the results for different campaign. Click “Event Label” to choose campaign. To know Calls Status. Click “Event action”.

Keeping Track

Call tracking function allows you to tie a phone number by a campaign. Here, a phone number is programmed to forward calls to the actual phone number. The country code of the caller is mapped to a geo-location, which is used in Google Analytics. Calls from the US and Canada are further resolved to the state or province respectively. Finally, this function reports to the Google Analytics by tracking ID of your account created. In analytics you get a clear picture of the impact of your marketing efforts on lead generation and sales. You can also make your campaigns more effective and cost efficient based on the results.

There are several possibilities to expand this further. In this example, only US and Canadian numbers are mapped to State. It is possible to expand this for any other countries by area code mapping. Currently calls are not recorded. It is possible to record calls as well. It is also possible to implement IVR, and track the selected IVR option.

Happy call tracking!

This article a guest post from Nethram.