I created this piece of code to use Google Analytics Measurement Protocol instead of the google provided javascript, analytics.js in one of my page.
Recently I was playing with analytics javascript code, and I found that many times it will not collect data if something is blocking tracking codes (eg.: analytics.js) like when PrivDog is installed (amongs others).
The original idea is coming from here, but this is for wordpress. http://www.stumiller.me/implementing-google-analytics-measurement-protocol-in-php-and-wordpress/ I modified the code to send data with sockets. (and without the wordpress functions library)
$gclid = $_GET['gclid'];
if (!empty($gclid)) {
setcookie("gclid", $gclid, time() + (10 * 365 * 24 * 60 * 60));
}
// Handle the parsing of the _ga cookie or setting it to a unique identifier
function gaParseCookie()
{
if (isset($_COOKIE['_ga'])) {
list($version, $domainDepth, $cid1, $cid2) = split('[\.]', $_COOKIE["_ga"], 4);
$contents = array('version' => $version, 'domainDepth' => $domainDepth, 'cid' => $cid1 . '.' . $cid2);
$cid = $contents['cid'];
} else {
$cid = gaGenUUID();
}
return $cid;
}
// Generate UUID v4 function - needed to generate a CID when one isn't available
function gaGenUUID()
{
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
// 32 bits for "time_low"
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
// 16 bits for "time_mid"
mt_rand(0, 0xffff),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
mt_rand(0, 0x0fff) | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
mt_rand(0, 0x3fff) | 0x8000,
// 48 bits for "node"
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
function gaBuildHit($method = null, $info = null)
{
global $gclid;
if ($method && $info) {
// Standard params
$v = 1;
$tid = "UA-XXXXXXX-XX"; // Put your own Analytics ID in here
$cid = gaParseCookie();
if (empty($gclid)) {
$gclid = $_COOKIE['gclid'];
}
// Register a PAGEVIEW
if ($method === 'pageview') {
// Send PageView hit
$data = array(
'v' => $v,
'tid' => $tid,
'cid' => $cid,
'gclid' => $gclid,
't' => 'pageview',
'dt' => $info['title'],
'dp' => $info['slug']
);
gaFireHit($data);
} // end pageview method
//
// Register an ECOMMERCE TRANSACTION (and an associated ITEM)
else if ($method === 'ecommerce') {
// Send Transaction hit
$data = array(
'v' => $v,
'tid' => $tid,
'cid' => $cid,
'gclid' => $gclid,
't' => 'transaction',
'ti' => $info['tid'], // Transaction ID
'ta' => 'SI',
'tr' => $info['price'], // transaction value (native currency)
'ts' => $info['shipping'], // transaction shipping (native currency)
'cu' => $info['cc'] // currency code
);
gaFireHit($data);
// Set up Item params
if ($info['info']->product_name) {
$in = urlencode($info['info']->product_name); // item name;
$ip = $tr;
$iq = 1;
$ic = urlencode($info['info']->product_id); // item SKU
$iv = urlencode('SI'); // Product Category - we use 'SI' in all cases, you may not want to
// Send Item hit
$data = array(
'v' => $v,
'tid' => $tid,
'cid' => $cid,
'gclid' => $gclid,
't' => 'item',
'ti' => $ti,
'in' => $in,
'ip' => $ip,
'iq' => $iq,
'ic' => $ic,
'iv' => $iv,
'cu' => $cu
);
gaFireHit($data);
}
} else if ($method === 'event') {
$data = array(
'v' => $v,
'tid' => $tid,
'cid' => $cid,
'gclid' => $gclid,
'ec' => $info['category'],
'ea' => $info['event'],
'el' => $info['label'],
'ev' => $info['value']
);
gaFireHit($data);
}
}
}
// See ttps://developers.google.com/analytics/devguides/collection/protocol/v1/devguide
function gaFireHit($data = null)
{
if ($data) {
$url = 'https://ssl.google-analytics.com/collect';
$getString .= '?payload_data&';
$getString .= http_build_query($data);
$result = socketPost($url, $getString, $_SERVER['HTTP_USER_AGENT']);
return $result;
}
return false;
}
function socketPost($url, $post_string, $ua = null)
{
$parts = parse_url($url);
// workout port and open socket
$port = isset($parts['port']) ? $parts['port'] : 80;
$success = $fp = fsockopen($parts['host'], $port, $errno, $errstr, 30);
if ($fp) {
// create output string
$output = "POST " . $parts['path'] . " HTTP/1.1
";
if (is_string($ua)) {
$output .= "User-Agent: " . $ua . "
";
}
$output .= "Host: " . $parts['host'] . "
";
$output .= "Content-Type: application/x-www-form-urlencoded
";
$output .= "Content-Length: " . strlen($post_string) . "
";
$output .= "Connection: Close
";
$output .= isset($post_string) ? $post_string : '';
// send output to $url handle
$success = fwrite($fp, $output);
fclose($fp);
}
return $success ? true : false;
}
//examples:
//page hit
$data = array(
'title' => 'Page title',
'slug' => $_SERVER["REQUEST_URI"]
);
gaBuildHit('pageview', $data);
//ecommerce
$data = array(
'tid' => $order_id_in_merchant_system,
'cc' => 'AUD', // the currency code
'price' => $order_total, // the price
'shipping' => $order_shipping, // the shipping cost
'country' => 'AU' // the country ISO code
);
gaBuildHit('ecommerce', $data);
The code itself is working just fine. I put here for you to get the idea.
Question is, I dont really see the flow, how could an Adwords Click get tracked here. Like, if there is no _ga cookie set before (then gaParseCookie creates one), how could analytics connect the tracked event into eg.: an Analytics keyword the click coming from? Is that possible with Measurement Protocol?