dotMobimobiThinkingmobiForgemobiReadyDeviceAtlasgoMobi

Posted by jonlindh 2 years 46 weeks ago

pic
 jonlindh
mobiForge Newbie
Posts: 5
Joined: 3 years ago
[offline]

Hi,

I have been working on a mobile e-commerce site and wanted to use Google Analytics to track visitors and e-commerce values. I have seen a few examples of Google Analytics without Javascript but most of them creates a new cookie for each request, and the visitor data won't be that reliable. Therefore i made this PHP class...

The code generates a HTML-code with one or more images thats tracks the visit and e-commerce values. I have also used DeviceAtlas API to track the screen resolution and color depth.

The traffic source is still an issue, i guess search egines and referals won't work that well yet....

Let me know what you think and how this works for you :)

See the latest code below

Posted by jonlindh 2 years ago

pic
 jonlindh
mobiForge Newbie
Posts: 5
Joined: 3 years ago
[offline]

Found a typo misstake in the function SetTransactionItem that I have corrected. See the correct code below:

See the latest code below

Posted by Kristine 2 years ago

pic
 Kristine
mobiForge Newbie
Posts: 1
Joined: 2 years ago
[offline]

Motally (www.motally.com) has a great mobile analytics solution with a free version. It's easy to use; just cut and paste a few lines of code in a common header or footer and Motally does the rest. You'll get accurate data on page views, sessions, and unique users. You can even track specific events or do funnel analysis. Reports are easy to read and you can receive them through automated emails or log on to export them directly to you computer. Check it out at www.motally.com/demo

Feel free to contact me if you have any questions (kristine@motally.com).

Kristine

Posted by jonlindh 2 years ago

pic
 jonlindh
mobiForge Newbie
Posts: 5
Joined: 3 years ago
[offline]

New version that handles referrals:

See the latest code below

Posted by xyz 2 years ago

pic
 xyz
Mobile Expert
Posts: 53
Joined: 5 years ago
[offline]

Hello,

it could be that this violates the Terms of Service of Google Analytics.

cf. http://www.google.com/analytics/tos.html

Posted by Noodles 2 years ago

pic
 Noodles
mobiForge Newbie
Posts: 2
Joined: 3 years ago
[offline]

I don't see how it would be a violation of Google's TOS.

Good work with the class Jon, but could you remove the hardcoding of the Analytics account number and website? Maybe pass them into the construct? This way I can use different account numbers if I need to.

Posted by Noodles 2 years ago

pic
 Noodles
mobiForge Newbie
Posts: 2
Joined: 3 years ago
[offline]

You might also want to consider replacing any &'s in the image URL with & to comply with xHTML standards.

Btw, I'm trying this on http://drugs.mobi. I will leave it for a couple of days and see if it improves our analytics numbers.

Posted by jonlindh 2 years ago

pic
 jonlindh
mobiForge Newbie
Posts: 5
Joined: 3 years ago
[offline]

New version:
- Better traffic source tracking, added organic search and adwords
- I have moved the account number and host to the constructor

<?php
class GoogleAnlayticsMobile {
	private $__utma; 						// Google Analytics __utma cookie
	private $__utma_c_time = 63072000; 		// 2 years (2 years is the default in Google Analytics)
	private $__utmb; 						// Google Analytics __utmb cookie
	private $__utmb_c_time = 1800; 			// 30 minutes (30 minutes is the default in Google Analytics)
	private $__utmc;						// Google Analytics __utmc cookie
	private $__utmz;						// Google Analytics __utmz cookie
	private $__utmz_c_time = 604800; 		// 7 days (6 months is the default in Google Analytics)
	private $ga_utmhn;						// Site host
	private $ga_utmac;						// Google Analytics account
	private $ga_utmwv = "4.3.1";			// Google Analytics tracking code version
	private $ga_hash;						// Google Analytics hash for domain
	private $ga_img = "http://www.google-analytics.com/__utm.gif";
	private $ga_search = array(array("google","q"),array("yahoo","p"),array("msn","q"),array("bing","q"),array("aol","query"),array("aol","encquery"),array("lycos","query"),array("ask","q"),array("altavista","q"),array("netscape","query"),array("cnn","query"),array("looksmart","qt"),array("about","terms"),array("mamma","query"),array("alltheweb","q"),array("gigablast","q"),array("voila","rdata"),array("virgilio","qs"),array("live","q"),array("baidu","wd"),array("alice","qs"),array("yandex","text"),array("najdi","q"),array("aol","q"),array("club-internet","query"),array("mama","query"),array("seznam","q"),array("search","q"),array("wp","szukaj"),array("onet","qt"),array("netsprint","q"),array("google.interia","q"),array("szukacz","q"),array("yam","k"),array("pchome","q"),array("kvasir","searchExpr"),array("sesam","q"),array("ozu","q"),array("terra","query"),array("nostrum","query"),array("mynet","q"),array("ekolay","q"),array("search.ilse","search_for"));
	private $ga_referer;
	private $time;
	private $html;
 
	function __construct($ga_utmac, $ga_utmhn, $URI = NULL, $ga_params = array()) {
		$this->ga_utmac = $ga_utmac;
		$this->ga_utmhn = $ga_utmhn;
		$this->ga_hash = $this->Hash($ga_utmhn);
 
		// Set the time for the request
		$this->time = time();
		// Set the page URI that is request
		if($URI==NULL) $URI = $_SERVER['REQUEST_URI'];
		// Set the referer page
		$this->ga_referer = $_SERVER['HTTP_REFERER'];
		// Set the visitor source
		$source = $this->GetTrafficSource();
		// Set the new traffic source
		if($source["utmgclid"]!="") $source_str = "utmgclid=".$source["utmgclid"];
		else $source_str = "utmcsr=".$source["utmcsr"];
		$source_str .= "|utmccn=".$source["utmccn"]."|utmcmd=".$source["utmcmd"];
		if($source["utmctr"]!="") $source_str .= "|utmctr=".$source["utmctr"];
		if($source["utmcct"]!="") $source_str .= "|utmcct=".$source["utmcct"];
 
		// Set all extra parameters like screen resolution, color depth
		if(is_array($ga_params)) foreach ($ga_params as $key => $value) $ga_set_params .= "&".$key."=".rawurlencode($value);
		else $ga_set_params = "";
 
		// Check if Google Analytics cookie "__utma" already exists
		if(isset($_COOKIE["__utma"])) {
			// Save cookies to local variable
			$this->__utma = $_COOKIE["__utma"];
			$this->__utmb = $_COOKIE["__utmb"];
			$this->__utmz = $_COOKIE["__utmz"];
 
			$__utmb = split("\.",$this->__utmb);
 
			if(strpos($this->__utmz,"utmgclid")>-1) $pos = strpos($this->__utmz,"utmgclid");
			else $pos = strpos($this->__utmz,"utmcsr");
			$__utmz = split("\.",substr($this->__utmz,0,$pos));
			$__utmz[4] = substr($this->__utmz,$pos);
			$__utma = split("\.",$this->__utma);
 
			// Check if Google Analytics "session" cookie "__utmc" exists, if not create one and update the number of visits in cookie: "__utma"
			if(!isset($_COOKIE["__utmc"])) {
				// Increase the number of visits
				$__utma[5] = $__utma[5]+1;
				// Update the time of the visit
				$__utma[3] = $__utma[4];
				$__utma[4] = $this->time;
				// Save cookies
				$this->__utma = join(".",$__utma);
				setcookie("__utma", $this->__utma, $this->time+$this->__utma_c_time, "/", ".".$this->ga_utmhn);
				setcookie("__utmc", $__utma[0], 0, "/", ".".$this->ga_utmhn);
				// Update "__utmb" cookie with the number of pageviews or create a new cookie
				if(isset($_COOKIE["__utmb"])) $__utmb[1] = 1;
				else $__utmb = array($__utma[0], 1, 10, $this->time);
			}
			else $__utmb[1] = $__utmb[1]+1; // Increase the number of pageviews in "__utmb" cookie
 
			// Update the traffic source
			if($__utmz[4]!=$source_str && $source["utmcsr"]!="(direct)") $__utmz = array($__utmz[0], $this->time, $__utma[5], $__utmz[3]+1, $source_str);
 
			// Save cookies "__utmb" and "__utmz"
			$this->__utmb = join(".",$__utmb);
			setcookie("__utmb", $this->__utmb, $this->time+$this->__utmb_c_time, "/", ".".$this->ga_utmhn);
			$this->__utmz = join(".",$__utmz);
			setcookie("__utmz", $this->__utmz, $this->time+$this->__utmz_c_time, "/", ".".$this->ga_utmhn);
		}
		else {
			// No Google Analytics cookies exists, create new ones and save them i local variables
			$c_id = sprintf("%f", (rand(1000000000,2147483647) ^ $this->ga_hash) * 2147483647);
			$c_id = split("\.",$c_id);
			$this->__utma = $this->ga_hash.".".$c_id[0].".".$this->time.".".$this->time.".".$this->time.".1";
			$this->__utmb = $this->ga_hash.".1.10.".$this->time;
			$this->__utmc = $this->ga_hash;
			$this->__utmz = $this->ga_hash.".".$this->time.".1.1.".$source_str;
			setcookie("__utma", $this->__utma, $this->time+$this->__utma_c_time, "/", ".".$this->ga_utmhn);
			setcookie("__utmb", $this->__utmb, $this->time+$this->__utmb_c_time, "/", ".".$this->ga_utmhn);
			setcookie("__utmc", $this->__utmc, 0, "/", ".".$this->ga_utmhn);
			setcookie("__utmz", $this->__utmz, $this->time+$this->__utmz_c_time, "/", ".".$this->ga_utmhn);
		}
		// Create the pageview request to Google Analytics image
		$this->html .= "<img src=\"".$this->ga_img."?utmwv=".$this->ga_utmwv."&utmn=".rand(1000000000,9999999999)."&utmhn=".$this->ga_utmhn."".$ga_set_params."&utmhid=".rand(1000000000,9999999999)."&utmr=".rawurlencode($this->ga_referer)."&utmp=".rawurlencode($URI)."&utmac=".$this->ga_utmac."&utmcc=__utma%3D".$this->__utma."%3B%2B__utmz%3D".rawurlencode($this->__utmz)."%3B\" width=\"1\" height=\"1\" />\n";
	}
 
	function Hash($d) {
		if(!$d || $d=="") return 1;
		$h=0; $g=0;
		for($i=strlen($d)-1;$i>=0;$i--) {
			$c = (int)(ord($d[$i]));
			$h = (($h << 6) & 0xfffffff) + $c + ($c << 14);
			$g = ($h & 0xfe00000);
			if($g!=0) $h = ($h ^ ($g >> 21));
		}
		return $h;
	}
 
	function GetTrafficSource() {
		if(isset($_GET["utm_source"]) && isset($_GET["utm_medium"])) { 
			// The traffic source i set in the URL
			$utmccn = isset($_GET["utm_campaign"]) ? $_GET["utm_campaign"] : "(not set)";
			$utmcct = isset($_GET["utm_content"]) ? $_GET["utm_content"] : "(not set)";
			return array("utmgclid"=>"", "utmcsr"=>$_GET["utm_source"], "utmccn"=>$utmccn, "utmcmd"=>$_GET["utm_medium"], "utmctr"=>$_GET["utm_term"], "utmcct"=>$utmcct);
		}
		else if($this->ga_referer!="") { 
			// The treffic source is from a referral site
			$search_engine = $this->GetSearchEngine();
			// Check if it's a search engine
			if($search_engine) return $search_engine; 
			else if(!isset($_COOKIE["__utmc"])) { 
				// It's not a search engine and it's a new visit. Set the referer.
				$ref = $this->GetReferer();
				if(substr($ref["host"],0,4)=="www.") $ref["host"] = substr($ref["host"],4); // Remove www from URL
				return array("utmgclid"=>"", "utmcsr"=>$ref["host"], "utmccn"=>"(referral)", "utmcmd"=>"referral", "utmctr"=>"", "utmcct"=>$ref["uri"]);
			}
		}
		return array("utmgclid"=>"", "utmcsr"=>"(direct)", "utmccn"=>"(direct)", "utmcmd"=>"(none)", "utmctr"=>"", "utmcct"=>"");
	}
 
	function GetSearchEngine() {
		$ref = $this->GetReferer();
		for($ii=0;$ii<count($this->ga_search);$ii++) {
			if(strpos(strtolower($ref["host"]), strtolower($this->ga_search[$ii][0]))>-1) {
				$test1 = strpos($ref["referer"], "?".$this->ga_search[$ii][1]."=");
				$test2 = strpos($ref["referer"], "&".$this->ga_search[$ii][1]."=");
				$i = ($test1 > -1) ? $test1 : $test2;
				if($i>-1) {
					$k = substr($ref["referer"], $i+strlen($this->ga_search[$ii][1])+2, strlen($ref["referer"]));
					$i = strpos($k,"&");
					if($i > -1) $k = substr($k,0,$i);
					if(isset($_GET["gclid"])) return array("utmgclid"=>$_GET["gclid"], "utmcsr"=>"", "utmccn"=>"(not set)", "utmcmd"=>"(not set)", "utmctr"=>$k, "utmcct"=>"");
					else return array("utmgclid"=>"", "utmcsr"=>$this->ga_search[$ii][0], "utmccn"=>"(organic)", "utmcmd"=>"organic", "utmctr"=>$k, "utmcct"=>"");
				}
			}
		}
		return false;
	}
 
	function GetReferer() {
		$referer_tmp = $this->ga_referer;
		$pos = strpos($referer_tmp, "://");
		if($pos>0) $referer_tmp = $referer_tmp = substr($referer_tmp,$pos+3);
		$pos = strpos($referer_tmp, "/");
		if($pos>0) return array("host"=>substr($referer_tmp, 0, $pos), "uri"=>substr($referer_tmp, $pos), "referer"=>$this->ga_referer);
		else return array("host"=>$referer_tmp, "uri"=>"", "referer"=>$this->ga_referer);
	}
 
	function SetTransaction($order_id, $amount, $shipping, $tax, $city, $region, $country) {
		// Generate code to set a new transaction in Google Analytics
		$this->html .= "<img src=\"".$this->ga_img."?utmwv=".$this->ga_utmwv."&utmn=".rand(1000000000,9999999999)."&utmhn=".$this->ga_utmhn."&utmt=tran&utmtid=".$order_id."&utmtto=".$amount."&utmttx=".$tax."&utmtsp=".$shipping."&utmtci=".rawurlencode($city)."&utmtrg=".rawurlencode($region)."&utmtco=".rawurlencode($country)."&utmac=".$this->ga_utmac."&utmcc=__utma%3D".$this->__utma."%3B%2B__utmz%3D".rawurlencode($this->__utmz)."%3B\" width=\"1\" height=\"1\" />\n";
	}
 
	function SetTransactionItem($order_id, $item_id, $category, $name, $price, $quantity) {
		// Generate code to set a new transaction item in Google Analytics, you must call the function SetTransaction before you call this one.
		$this->html .= "<img src=\"".$this->ga_img."?utmwv=".$this->ga_utmwv."&utmn=".rand(1000000000,9999999999)."&utmhn=".$this->ga_utmhn."&utmt=item&utmtid=".$order_id."&utmipc=".$item_id."&utmipn=".rawurlencode($name)."&utmiva=".rawurlencode($category)."&utmipr=".$price."&utmiqt=".$quantity."&utmac=".$this->ga_utmac."&utmcc=__utma%3D".$this->__utma."%3B%2B__utmz%3D".rawurlencode($this->__utmz)."%3B\" width=\"1\" height=\"1\" />\n";
	}
 
	function GetTrackingCode() {
		// Return the Google Analytics code for this request
		return $this->html;
	}
}
 
 
$ga_params = array();
//$ga_params["utmsr"] = $properties["displayWidth"]."x".$properties["displayHeight"];
//$ga_params["utmsc"] = $properties["displayColorDepth"]."-bit";
 
$ga = new GoogleAnlayticsMobile("UA-0000000-00", "mywebsite.com", NULL, $ga_params);
//$ga->SetTransaction("1234", 219, 29, 0, "Stockholm", "", "Sweden");
//$ga->SetTransactionItem("1234", "PR1", "", "Product 1", 190, 1);
//$ga->SetTransactionItem("1234", "SH1", "", "Shipping 1", 29, 1);
?>
<?=$ga->GetTrackingCode()?>

Posted by xyz 2 years ago

pic
 xyz
Mobile Expert
Posts: 53
Joined: 5 years ago
[offline]

Noodles wrote:
I don't see how it would be a violation of Google's TOS.

cf. GOOGLE ANALYTICS TERMS OF SERVICE

"You will not nor will You allow any third party to (i) copy, modify, adapt, translate or otherwise create derivative works of the Software or the Documentation; (ii) reverse engineer, de-compile, disassemble or otherwise attempt to discover the source code of the Software, except to the extent applicable laws specifically prohibit such restriction (iii) rent, sublicense, lease, sell, assign or otherwise transfer rights (or purport to do any of the same) in or to the GATC, the Processing Software, the Documentation or the Service; (iv) remove any proprietary notices or labels on the Software or which are otherwise placed by the Service; or (v) use, post, transmit or introduce any device, software or routine which interferes or attempts to interfere with the operation of the Service or the Software."

Posted by Richard Hearne 2 years ago

pic
 Richard Hearne
mobiForge Newbie
Posts: 4
Joined: 4 years ago
[offline]

@XYZ - I don't think this code breaks TOS. All JonLindh is doing here is writing code to output the beacon to GA.

You'll find there are tonnes of third party developers building weird and wonderful stuff on top of GA.

@JonLindh - will check this out. It looks like a very interesting way to use GA in a mobile environment. Thanks for posting it here.

Posted by xyz 2 years ago

pic
 xyz
Mobile Expert
Posts: 53
Joined: 5 years ago
[offline]

Hello,

unfortunately Google Analytics has no email contact option to ask if such a tracking code would be accepted.

A second issue could be that the server side construction of the utm.gif URL and the cookies could conflict with ga.js if one uses both tracking methods.

Posted by eduardocereto 2 years ago

pic
 eduardocereto
mobiForge Newbie
Posts: 2
Joined: 2 years ago
[offline]

hey jonlindh,
This is great code and might help us a lot. I still miss _setVar, but I can live with that for now. You should host this code somewhere like google code or bit bucket so we could more easyly track your changes or submit new patches.

Thanks for that work

Posted by eduardocereto 2 years ago

pic
 eduardocereto
mobiForge Newbie
Posts: 2
Joined: 2 years ago
[offline]

One more thing. I'm pretty sure the timestamps stored on google cookies are divided by 1k.
Sou you should store it like this:

time()/1000

Sure you should double check it. But I remember having problems with it in the past.

Posted by beatler 2 years ago

pic
 beatler
mobiForge Newbie
Posts: 1
Joined: 2 years ago
[offline]

In case you cant use PHP, you can try with a public service:

<img src="http://nojsstats.appspot.com/UA-123456/mywebsite.com" />

Documentation here.

Greets

Posted by Bensbury 2 years ago

pic
 Bensbury
mobiForge Newbie
Posts: 1
Joined: 2 years ago
[offline]

Hi Jon,

I'd like to try out your script.
I can see quite a bit of cookie setting in the php, but many mobile devices don't support cookies.
Especially in Japan.

I'm not a php coder, so does the script work without cookies?
And if not would it be easy to convert it to work without cookies?

Thanks.

Posted by Sprize 2 years ago

pic
 Sprize
mobiForge Newbie
Posts: 1
Joined: 2 years ago
[offline]

http://www.acleon.co.uk/posts/galvanize-google-analytics-without-the-javascript/comment-page-1

Here's another good script. Don't think they are that different :)

Posted by mattan 2 years ago

pic
 mattan
mobiForge Enthusiast
Posts: 17
Joined: 4 years ago
[offline]

And here's the script from google themselves: http://analytics.blogspot.com/2009/10/google-analytics-now-more-powerful.html

Posted by ruadhan 2 years ago

pic
 ruadhan
dotMobi logo
Mobile Champion
Posts: 710
Joined: 5 years ago
[offline]

mattan wrote:
And here's the script from google themselves: http://analytics.blogspot.com/2009/10/google-analytics-now-more-powerful.html

Brilliant! This should shake things up a bit.

Ruadhan O'Donoghue
dotMobi

Posted by jonlindh 2 years ago

pic
 jonlindh
mobiForge Newbie
Posts: 5
Joined: 3 years ago
[offline]

mattan wrote:
And here's the script from google themselves: http://analytics.blogspot.com/2009/10/google-analytics-now-more-powerful.html

This is great, but it looks like e-commerce tracking function is missing. Hope they'll add it soon...

/Jon

Posted by garbetjie 2 years ago

pic
 garbetjie
Mobile Guru
Posts: 70
Joined: 3 years ago
[offline]

Just thought I might throw this in here, but there's also the mobile analytics available from Admob -- http://analytics.admob.com. I'm not 100% sure how it would match up to GA, but I've been pretty stoked with the tracking I get from it.

Posted by Suma 2 years ago

pic
 Suma
mobiForge Newbie
Posts: 1
Joined: 2 years ago
[offline]

http://www.project83.com/blog/installing-google-analytics-on-a-mobile-website/

Posted by CRUCIFER 2 years ago

pic
 CRUCIFER
mobiForge Newbie
Posts: 5
Joined: 3 years ago
[offline]

garbetjie wrote:
Just thought I might throw this in here, but there's also the mobile analytics available from Admob -- http://analytics.admob.com. I'm not 100% sure how it would match up to GA, but I've been pretty stoked with the tracking I get from it.
I have had no luck getting this to work properly using PHP. I had some small success with a tracking pixel but the stats are inaccurate. What code snippet are you using and did you have to tweak it to make it work?

................... QRable.mobi

Posted by garbetjie 2 years ago

pic
 garbetjie
Mobile Guru
Posts: 70
Joined: 3 years ago
[offline]

Hey crucifier.

I've never had any hassles getting it working. The only modifications I've made to it is to integrate it into CakePHP (which is the PHP framework that I use). Other than that, I'm pretty much using it as it is given.

I'm using the cURL PHP snippet, if that's worth anything :)

Posted by benicoz 1 year ago

pic
 benicoz
mobiForge Newbie
Posts: 1
Joined: 1 year ago
[offline]

Hey,

I would like to track ecommerce transactions on a mobile website visited mostly with non javascript compatible devices.

I've found this thread and I thought I was saved but I don't get how to use and install the custom PHP class.

Now that google analytics for mobile is released, does that kind of custom code still work?

thanks for your help

Posted by mikehenry 17 weeks ago

pic
 mikehenry
mobiForge Newbie
Posts: 2
Joined: 23 weeks ago
[offline]

Google analytics is really an informative and amazing topic which is beautifully discussed in the post, i liked it. tours in India

Posted by mikehenry 17 weeks ago

pic
 mikehenry
mobiForge Newbie
Posts: 2
Joined: 23 weeks ago
[offline]

The Google is the most amazing and big search engine of the world and i am happy to read an amazing post about its analytics, it is really remarkable for me. tours in India

Posted by xiaopy12 1 week ago

pic
 xiaopy12
Mobile Champion
Posts: 582
Joined: 1 week ago
[offline]

Christian Louboutin Sale fdyey