Creating a simple call tracking service, part 1

The article will consider one of the possible options for implementing call tracking on the site. This material is written purely for educational purposes and does not carry the goal of replacing existing specialized services that provide the calltracking service.



Functional Requirements



  1. The service should provide the ability to substitute numbers (numbers) by the source of the transition to the site - the transition from search engines, the transition to advertising, the links using utm tags.
  2. The service should fix the displayed number to the site visitor and display this number on a further visit.
  3. When initiating a call to the displayed number, the service must initiate the creation of an event in Google Analytics.


General mechanics



When you go to the site, we determine the source of the transition, and then check whether the number is assigned to this visitor. If the visitor first visited the site, then we assign him a unique identifier, after which we assign him a number from the pool of numbers related to this referral source. In the future, when the visitor returns to the site again, we display the number assigned to him earlier.



I would like to focus on the call log. Replacing the number, assigning it to the user is a technical issue, the main thing is to be able to compare a specific call and the number that is currently assigned to the user. If the telephony used allows you to receive detailed information on ongoing calls on an ongoing basis, then knowing the moment of a call to a specific number and having information about which number was displayed at that moment on the website of which user, it is possible to initiate the creation of an event in Google Analytics and associate it with the ROK.



Structure



  1. ct-server.ru - an executable web service script will be placed here, a database for storing room settings and logging visitors;
  2. refer-to-site-with-ct-code.ru - on this site we will emulate the transition from the search network;
  3. site-with-ct-code.ru - the site on which the number substitution script will be placed.


Let's get started



The example below will be implemented on a local server.



Create a virtual host site-with-ct-code.ru , in which we put the index.html file of the following contents.



<!DOCTYPE HTML> <html> <head> <meta charset='utf-8'> <title>CT</title> <script src="http://ct-server.ru/script.js"></script> <script> //  google id document.cookie = '_ga=GA1.2.1212121212.1212121212; expires=Thu, 18 Dec 2077 12:00:00 UTC; path=/'; </script> </head> <body> <p id='calltracking'>79000000000</p> </body> </html>
      
      





As you can see from the example, we connect an external script ct-server.ru/script.js , which will "communicate" between site-with-ct-code.ru and ct-server.ru , as well as interact with the site's DOM tree site-with-ct-code.ru . The number will be substituted by the id of the element - 'calltracking'.



Now create a refer-to-site-with-ct-code.ru , which will contain a link to site-with-ct-code.ru for the ability to check the pin number on the transition from the referrer.



 <!DOCTYPE HTML> <html> <head> <meta charset='utf-8'> <title>CT</title> </head> <body> <a href="http://site-with-ct-code.ru"></a> </body> </html>
      
      





After that, we will raise the ct-server.ru host, which will have the following structure:



index.php - an executable script file that will receive Post requests from site-with-ct-code.ru and interact with the database;



script.js - a script file that will be connected on sites where the number will be substituted.



Database



We will need to create two plates. In the ct table we will store numbers and settings for their display, in the numbers table we will log the display of numbers.



 CREATE TABLE `ct` ( `id` int(11) NOT NULL, `phone` varchar(200) NOT NULL, `refer` varchar(200) NOT NULL, `utm` varchar(200) NOT NULL, `host` varchar(200) NOT NULL, `ga` varchar(200) NOT NULL, `login` varchar(200) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `ct` ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `id` (`id`); ALTER TABLE `ct` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;
      
      





A small explanation of the added fields:



phone - substituted phone number;

refer - the source of the transition;

utm - link to the page on which the number substitution should take place;

host - the site where the number substitution script is located;

ga - id of the Google Analytics counter;

login - login number owner.



Fill the plate with data.



 INSERT INTO `ct` (`id`, `phone`, `refer`, `utm`, `host`, `ga`, `login`) VALUES (2, '78000000001', '', 'http://site-with-ct-code.ru/?utm_medium=cpc', 'http://site-with-ct-code.ru', 'UA-12345678-1', ''), (3, '78000000002', 'http://refer-to-site-with-ct-code.ru/', 'http://site-with-ct-code.ru/', 'http://site-with-ct-code.ru', 'UA-12345678-1', ''), (4, '78000000003', 'http://refer-to-site-with-ct-code.ru/', 'http://site-with-ct-code.ru/', 'http://site-with-ct-code.ru', 'UA-12345678-1', ''), (5, '78000000004', 'http://refer-to-site-with-ct-code.ru/', 'http://site-with-ct-code.ru/', 'http://site-with-ct-code.ru', 'UA-12345678-1', ''), (6, '78000000005', '', 'http://site-with-ct-code.ru/', 'http://site-with-ct-code.ru', 'UA-12345678-1', '');
      
      





image



Now create the numbers plate.



 CREATE TABLE `numbers` ( `id` int(11) NOT NULL, `phone` varchar(200) DEFAULT NULL, `ct_user` varchar(200) DEFAULT NULL, `refer` varchar(200) DEFAULT NULL, `gid` varchar(200) DEFAULT NULL, `page` varchar(200) DEFAULT NULL, `time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `numbers` ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `id` (`id`), ALTER TABLE `numbers` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;COMMIT;
      
      





In this plate we will record which visitor, which number and at what point in time is displayed on the site. In the future, this data can be compared with the call log to initiate the target action - sending an event to Google Analytics, creating a lead in CRM, sending an email, etc.



phone - phone number;

ct_user - visitor id;

refer - the source of the transition;

gid - Google Analytics cookie

page - the page on which the number is displayed;

time - number display time.



Create a request handler



The interaction between the ct-server.ru web service and the site hosting the script will be done through cross-domain XHR (XMLHttpRequest) POST requests.



Let's open the file ct-server.ru/index.php created earlier and add a check for receiving data from allowed hosts, in our case it is site-with-ct-code.ru , site-with-ct-code2.ru and site-with -ct-code3.ru .



 <?php if (isset($_SERVER["HTTP_ORIGIN"]) === true) { $host = $_SERVER["HTTP_ORIGIN"]; //   $allowHosts = array("http://site-with-ct-code.ru", "http://site-with-ct-code2.ru", "http://site-with-ct-code3.ru"); if (in_array($host, $allowHosts, true) === true) { header('Access-Control-Allow-Origin: ' . $host); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Methods: POST'); header('Access-Control-Allow-Headers: Content-Type'); //    post-      } if ($_SERVER["REQUEST_METHOD"] === "OPTIONS") { exit; } } ?>
      
      





We write in the variable values ​​of the POST requests that came from site-with-ct-code.ru



 $phone = $_POST["phone"]; $ct_user = $_POST["ct_user"]; $gid = $_POST["gid"]; $refer = $_POST["ref"]; $page = $_POST["page"];
      
      





Cook _ga has the form _ga = GA1.2.1212121212.121212121212, we will bring it to the form "1212121212.121212121212".



 if ($gid) { $pos = strpos($gid, '.', strpos($gid, '.') + 1); $gid = substr($gid, $pos + 1); }
      
      





We will establish a connection to the database where we previously created our tables.



 $conn = new mysqli("localhost", "root", "", "calltracking"); if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); }
      
      





Interaction with the web service will be through two methods - get_num_first and get_num .



The get_num_first method is called when the visitor first interacts with the site to get a number by selecting from the database according to the criteria - mail, referrer, utm, host. If the selection result returns a value, then we display the phone number.



In addition, we send the event to Google Analytics through the Google Measurement Protocol . The same method is applicable for tracking offline actions, in the future it can be used when comparing the call log and the number log in the numbers table.



 if ($_POST['method'] == 'get_num_first') { $sql = "SELECT * FROM `ct` where `host` = '" . $host . "' and `refer` = '" . $refer . "' and `utm` = '" . $page . "' ORDER BY RAND() LIMIT 1 "; $result = $conn->query($sql); if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { print_r($row["phone"]); $event = file_get_contents('https://www.google-analytics.com/collect?v=1&tid=UA-12345678-1&cid=' . $gid . '&t=event&ec=GetNumber&ea=number&z=' . $row["phone"] . ''); } } else { //echo "0"; $sql = "SELECT * FROM `ct` where `host` = '" . $host . "' and `refer` = '" . $refer . "' ORDER BY RAND() LIMIT 1 "; $result = $conn->query($sql); print_r($row["phone"]); $event = file_get_contents('https://www.google-analytics.com/collect?v=1&tid=UA-12345678-1&cid=' . $gid . '&t=event&ec=GetNumber&ea=number&z=' . $row["phone"] . ''); } }
      
      





The get_num method is required to log entries in the numbers table.



 else if ($_POST['method'] == 'get_num') { $sql = "INSERT INTO `numbers` (`phone`, `ct_user`, `gid`, `refer`,`page`) VALUES ( '" . $phone . "', '" . $ct_user . "', '" . $gid . "', '" . $refer . "', '" . $page . "');"; $result = $conn->query($sql); $sql = "SELECT * FROM `numbers` where `ct_user` = '" . $ct_user . "' ORDER BY `id` DESC LIMIT 1 "; $result = $conn->query($sql); if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { print_r($row["phone"]); $event = file_get_contents('https://www.google-analytics.com/collect?v=1&tid=UA-12345678-1&cid=' . $gid . '&t=event&ec=ShowNumber&ea=number&z=' . $row["phone"] . ''); } } else { //echo "0"; } } $conn->close();
      
      





Number substitution script



Next, we will move on to the ct-server.ru/script.js script, which we connect on site-with-ct-code.ru



To start, let's create two functions - setcookie for creating and getcookie for reading cookies. We will use them to record and get the cookie id of the user and phone number.



 //  function setcookie(phone, value, expires, path, domain, secure) { document.cookie = phone + "=" + escape(value) + (expires ? "; expires=" + new Date(expires) : "") + (path ? "; path=" + path : "") + (domain ? "; domain=" + domain : "") + (secure ? "; secure" : ""); } //  function getcookie(phone) { var cookie = " " + document.cookie; var search = " " + phone + "="; var setStr = null; var offset = 0; var end = 0; if (cookie.length > 0) { offset = cookie.indexOf(search); if (offset != -1) { offset += search.length; end = cookie.indexOf(";", offset); if (end == -1) { end = cookie.length; } setStr = unescape(cookie.substring(offset, end)); } } return setStr; }
      
      





After that, add the makeid function to generate the id for the user.



 // id  function makeid(length) { var result = ""; var user_id = "abcdefghijklmnopqrstuvwxyz0123456789"; var user_idLength = user_id.length; for (var i = 0; i < length; i++) { result += user_id.charAt(Math.floor(Math.random() * user_idLength)); } return result; }
      
      





Now let's create a function to generate cookies containing a 33-digit user id.



 // id  function generateuser_id() { var ct_user_id = makeid(33); setcookie("ct_user", ct_user_id, new Date().getTime() + 60 * 60 * 1000); //  }
      
      





The resulting ct_user cookie is stored for 1 hour.



We proceed to generate a request for a number through the get_num_first method. The resulting number from ct-server.ru is written in the cookie for 1 hour and we perform the first substitution of the number on the page by the id of the element.



 //    ,  ,       id  function getNumberFirstTime() { var method = "get_num_first"; var ct_user = getcookie("ct_user"); var gid = getcookie("_ga"); var ref = document.referrer; var host = window.location.origin; var page = document.location.href; var xhr = new XMLHttpRequest(); var body = "&method=" + encodeURIComponent(method) + "&page=" + encodeURIComponent(page) + "&ct_user=" + encodeURIComponent(ct_user) + "&ref=" + encodeURIComponent(ref) + "&host=" + encodeURIComponent(host) + "&gid=" + encodeURIComponent(gid); xhr.open("POST", "http://ct-server.ru", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.withCredentials = true; xhr.send(body); xhr.onreadystatechange = function() { //console.log(xhr.responseText); var t = xhr.responseText; document.getElementById("calltracking").innerHTML = t; setcookie("phone", t, new Date().getTime() + 60 * 60 * 1000); //  }; }
      
      





Let's create a function that will periodically send the displayed number, user id, page address, google analytics cookie value, referral source to ct-server.ru.



 function getNumberPeriodically() { var method = "get_num"; var ct_user = getcookie("ct_user"); var phone = getcookie("phone"); var gid = getcookie("_ga"); var ref = document.referrer; var page = document.location.href; var host = window.location.origin; var xhr = new XMLHttpRequest(); var body = "&method=" + encodeURIComponent(method) + "&page=" + encodeURIComponent(page) + "&ct_user=" + encodeURIComponent(ct_user) + "&ref=" + encodeURIComponent(ref) + "&host=" + encodeURIComponent(host) + "&phone=" + encodeURIComponent(phone) + "&gid=" + encodeURIComponent(gid); xhr.open("POST", "http://ct-server.ru", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.withCredentials = true; xhr.send(body); xhr.onreadystatechange = function() { //console.log(xhr.responseText); var t = xhr.responseText; //document.getElementById('calltracking').innerHTML = t; }; }
      
      





At the end, we add the sendToCalltracking function, which checks for the presence of cookies, phone number and user id.



 function sendToCalltracking() { var ggg = getcookie("ct_user"); var ccc = getcookie("phone"); var gac = getcookie("_ga"); if ( typeof ggg === "undefined" || ggg === null || ccc === "undefined" || ccc === null || ccc.length < 1 || ggg.length < 1 || ccc === "" || ggg === "" ) { //console.log('false'); generateuser_id(); getNumberFirstTime(); } else { //console.log('true'); document.getElementById("calltracking").innerHTML = ccc; getNumberPeriodically(); } }
      
      





At the very beginning of the script we put a timer function call.



 var myTimer = setTimeout(sendToCalltracking, 500); //        setInterval(sendToCalltracking, 1 * 60 * 1000);
      
      





image



If cookies are deleted during the next operation, the function will assign a new one to the visitor according to the received selection by host and source. In addition, it is possible to write the received values ​​to the localStorage browser.



image



Once a minute, the script will send the value of the cookie number and user id indicating the page on which it was applied without reloading it. It is understood that the script will be placed on all pages of the domain.



image



In the next article we will discuss the development of a simple interface for adding and configuring numbers.



All Articles