Google Analytics Core Reporting API (Data Export) with Google Chart Visualizations

Updated 12/20/11 and 01/04/12 to reflect Google’s API changes

You can punch into the Google Analytics Core Reporting (Data Export) API, pull out some stats, and stuff them into some nice graphical charts using Google Chart Visualizations. This demo is done in PHP.
Google Chart Visualizations

Authenticate the User

The user can authenticate via the ClientLogin or using the AuthSub login which is actually more secure. For the ClientLogin, a typical username/password form is used. For the AuthSub login a link is used to send the user to Google to log in. Both are shown below. Normally you would use one or the other.

* Use ClientLogin ONLY for installed apps and not web apps

<form name="loginForm" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
		    <label for="email">Gmail:</label>
		    <input id="email" type="text" name="email" />
		    <label for="password">Password:</label>
		    <input type="password" name="password" id="password"/>
		    <br /><br />
		    <button type="submit" id="submitLogin">Submit</button>
		</form>
        <p><a class="button" href="https://www.google.com/accounts/AuthSubRequest?next=http://your-return-url&scope=https://www.googleapis.com/auth/analytics.readonly&secure=0&session=1">Or,authenticate using AuthSub through Google.</a></p>

And, of course, the two authentication methods use different http calls to return a token that can be used to access the API.

//ClientLogin: try to log in and get session token for multiple API calls
if(isset($_POST['email']) && isset($_POST['password'])){
	$_SESSION['sessionToken'] = googleLogin($_POST['email'],$_POST['password']);
}
//AuthSub: exchange token for session token so multiple calls can be made to api
if(isset($_REQUEST['token'])){
	$_SESSION['authSub'] = true;
	$_SESSION['sessionToken'] = get_session_token($_REQUEST['token']);
}

//returns sessionToken for multiple calls to API
function googleLogin($email,$passwd){
	
    $clientlogin_url = "https://www.google.com/accounts/ClientLogin";
     $clientlogin_post = array(
    "accountType" => "GOOGLE",
    "Email" => $email,
    "Passwd" => $passwd,
    "service" => "analytics",
    "source" => "my-analytics"
	);
 
	$curl = curl_init($clientlogin_url);

	curl_setopt($curl, CURLOPT_POST, true);
	curl_setopt($curl, CURLOPT_POSTFIELDS, $clientlogin_post);
	curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

	$response = curl_exec($curl);
 
	preg_match("/Auth=([a-z0-9_\-]+)/i", $response, $matches);
	$sessionToken = $matches[1];

	if (strlen($sessionToken) == 0){
		$sessionToken = "Authentication Failed.";
	}
	 
 	return $sessionToken;
}

//AuthSub returns session token for multiple calls to API
	function get_session_token($onetimetoken) {
		$output = call_api($onetimetoken, "https://www.google.com/accounts/AuthSubSessionToken");
				
		if (preg_match("/Token=(.*)/", $output, $matches))
		{
			$sessionToken = $matches[1];
		} else {
			echo "Error authenticating with Google.";
			exit;
		}
		
		return $sessionToken;
	}

Data Requests

Once authenticated to a Google Analytics account and a multi-use session token is acquired, the data requests can be made. The first one will request the profiles (websites) associated with the account. If there is more than one, a dropdown select is populated allowing for the selection of the profile from which to pull data.

The key is added to the request per this post by Google.

$accountxml = call_api($_SESSION['sessionToken'],"https://www.googleapis.com/analytics/v2.4/management/accounts/~all/webproperties/~all/profiles?key=Axxxxxxxxxxxxxxxxxx4");
// Get an array with the available accounts
$profiles = parse_account_list($accountxml);

The call_api function is going to return the XML data from Google based on the request URL sent in. In this case, it is getting the profile data and the parse_account_list function is rolling through that XML and putting the profile data in an array.

//gets the data
function call_api($sessionToken,$url){
	$curl = curl_init($url);
 
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);	
	if (isset($_SESSION['authSub'])){
		$curlheader[0] = sprintf("Authorization: AuthSub token=\"%s\"/n", $sessionToken);
	} else {
		$curlheader[0] = "Authorization: GoogleLogin auth=" . $sessionToken;
	}
	curl_setopt($curl, CURLOPT_HTTPHEADER, $curlheader);

	$response = curl_exec($curl);
	curl_close($curl);

	return $response;	    
}

//returns accounts list as array	
function parse_account_list($xml){
	$doc = new DOMDocument();
	if(stripos($xml,"<") !== FALSE)
	{
		$doc->loadXML($xml);
	
		$entries = $doc->getElementsByTagName('entry');
		$i = 0;
		$profiles= array();
		foreach($entries as $entry)
		{
			$profiles[$i] = array();

			$properties = $entry->getElementsByTagName('property');
			foreach($properties as $property)
			{
				if (strcmp($property->getAttribute('name'), 'ga:accountId') == 0)
					$profiles[$i]["accountId"] = $property->getAttribute('value');

				if (strcmp($property->getAttribute('name'), 'ga:profileName') == 0)
					$profiles[$i]["title"] = $property->getAttribute('value');

				if (strcmp($property->getAttribute('name'), 'dxp:tableId') == 0)
					$profiles[$i]["tableId"] = $property->getAttribute('value');
			}
				
			$i++;
		}
		
		return $profiles;
	} else {
		$sessionToken = "Authentication Failed.";
	}
}

The dropdown of the profile array:

echo "<form name='siteSelect' id='siteSelect' method='post' action='" . $_SERVER['PHP_SELF'] . "'><p><label for='tableId'>Select Site:</label><select name='tableId' id='tableId'>";
		foreach($profiles as $profile)
		{
			if($profile["tableId"] == $table_Id)
				$selected = "selected='selected'";
				echo "<option value='" . $profile["tableId"] . "|" . $profile["title"] . "'" . $selected  . ">" . $profile["title"] . "</option>";
				$selected = " ";
		}
		echo "</select></p>";

// set $tableId
if(isset($_POST['tableId'])){
    $tableId = substr($_POST['tableId'],0,strpos($_POST['tableId'],"|"));
}

The parse_data function below is going to roll through the data returned from Google Analytics and spit out an array that can be used to create the Google Visualization graphs.

//returns data as array	
function parse_data($xml){
		$doc = new DOMDocument();
		$doc->loadXML($xml);

		$entries = $doc->getElementsByTagName('entry');
		$i = 0;
		$results = array();
		foreach($entries as $entry)
		{		
			$dimensions = $entry->getElementsByTagName('dimension');
			foreach($dimensions as $dimension)
			{
				$results[$i][ltrim($dimension->getAttribute("name"),"ga:")] =  $dimension->getAttribute('value');
			}
			
			$metrics = $entry->getElementsByTagName('metric');
			foreach($metrics as $metric)
			{
				$results[$i][ltrim($metric->getAttribute('name'),"ga:")] =  $metric->getAttribute('value');
			}
			
			$i++;
		}
		return $results;
}

Graph Generation

Request the data

// For each website, get referrals
$requrl = sprintf("https://www.googleapis.com/analytics/v2.4/data?ids=%s&dimensions=ga:source&metrics=ga:visits&filters=ga:medium==referral&start-date=%s&end-date=%s&sort=-ga:visits&max-results=10",$tableId,$start_date,$end_date);
				
$referralsxml = call_api($_SESSION['sessionToken'],$requrl);				
$referrers = parse_data($referralsxml);

$requrlvisitsgraph = sprintf("https://www.googleapis.com/analytics/v2.4/data?ids=%s&dimensions=ga:date&metrics=ga:visits&start-date=%s&end-date=%s",$tableId,$start_date,$end_date);
$visitsgraphxml = call_api($_SESSION['sessionToken'],$requrlvisitsgraph);				
$visitsgraph = parse_data($visitsgraphxml);		

Google Visualizations requires the inclusion of a javascript file in the head tag and empty div’s that will be the target for the graphs:

<script type="text/javascript" src="//www.google.com/jsapi"></script>

The target div’s should be placed on the page where you want them to appear.

<div id='barchart_div'></div>
<div id='piechart_div'></div>

Finally, the data can be added to the chart generation javascript:

<script>      
function drawPieChart() {
	var data = new google.visualization.DataTable();
    data.addColumn('string', 'Referrer');
    data.addColumn('number', 'Visits');
    data.addRows(<?php echo sizeof($referrers) ?>);
    <?php
    $row = 0;
    foreach($referrers as $referrer)
		{
	?>
	data.setValue(<?php echo $row ?>,0,'<?php echo $referrer["source"] ?>');
	data.setValue(<?php echo $row ?>,1,<?php echo $referrer["visits"] ?>);
	<?php	
	$row++;
	}
	?>

	var chart = new google.visualization.PieChart(document.getElementById('piechart_div'));
    chart.draw(data, {width: 600, height: 440, is3D: true, title: 'Referrer/Visits'});
}

function drawBarChart() {
	var data = new google.visualization.DataTable();
    data.addColumn('string', 'Day');
    data.addColumn('number', 'Visits');
    data.addRows(<?php echo sizeof($visitsgraph) ?>);
	<?php
    $row = 0;
    foreach($visitsgraph as $visits)
		{
	?>
		data.setValue(<?php echo $row ?>,0,'<?php if ($visits_graph_type === "month"){echo date("M", mktime(0, 0, 0, $visits["month"]))." ".$visits["year"];}else{echo substr($visits['date'],6,2)."-".date('M', mktime(0, 0, 0, substr($visits['date'],4,2)))."-".substr($visits['date'],0,4);} ?>');
		data.setValue(<?php echo $row ?>,1,<?php echo $visits["visits"] ?>);
		<?php 
		$row++; 
		}
		?>
    var chart = new google.visualization.ColumnChart(document.getElementById('barchart_div'));
    chart.draw(data, {'width': 700, 'height': 400, 'is3D': true, 'title': 'Visits'});
}

google.load("visualization", "1.0", {packages:["corechart"]});
google.setOnLoadCallback(drawPieChart);
google.setOnLoadCallback(drawBarChart);

</script>

Recommended

Demo

Download code

Posted in Google Analytics, php, Web development. Tags: , , , . Permalink. Both comments and trackbacks are closed.

22 Comments

  1. July 20, 2011 at 1:04 pm | Permalink

    amazing work, works like a charm :) tnx for this great contribution!

  2. June 24, 2011 at 6:11 pm | Permalink

    @Andrei
    You are correct it is a mistake. It is doing no harm so it can be deleted. I forgot to clean it out after improving on the parse_data method.
    Thanks for pointing it out.

  3. Andrei
    June 24, 2011 at 4:52 pm | Permalink

    In parse_data method – is variable $countries[$i] being used at all over there? seem to be a mistake.

  4. June 22, 2011 at 6:53 pm | Permalink

    @Playup

    Awesome! Would love to see what you finally come up with but, considering the data, I understand if you can’t share. Good Luck!

  5. June 22, 2011 at 6:30 pm | Permalink

    I spent a while trying to get this to work for me, got it in the end. now I’ve got to work it into a data load script.

    Thanks

  6. March 29, 2011 at 5:04 am | Permalink

    Hi there great script, light and easy to implement took just a couple of minutes to setup.
    One question, Im not a coder but was wondering if i could just store the login info to the clientlogin so there is no need to post the data? I would like to implement it in a secure area on a cms and the user can just look at the page via there navigation?

    Thanks for the great script!

  7. Towfiq I.
    February 1, 2011 at 3:42 pm | Permalink

    Awesome post. I am thinking of integrating this to a wordpress theme.

  8. October 12, 2010 at 7:37 am | Permalink

    Thanks for this sample!

    Also want to tell if anyone will have problem with secure connections to Google (it looks like nothing returned in list of sites) they should read this article and configure properly their curl library.

    http://unitstep.net/blog/2009/05/05/using-curl-in-php-to-access-https-ssltls-protected-sites/

  9. September 29, 2010 at 11:48 pm | Permalink

    All i can say is wow.
    I have never thing like cURL with Google library can be mixed like this.
    I want to try your code to show my google analytics on my blog. Thanks mate.

  10. August 6, 2010 at 12:47 am | Permalink

    Hi,

    Its informative articles and we had checked that non-php embed script we are doing our self with XML for PHP want to know is there any one who did for iphone – Thanks

2 Trackbacks

  1. [...] This post was mentioned on Twitter by A.Elduayen, jkang. jkang said: New Post: Google Analytics Data Export API with Google Chart Visualizations on jensbits.com: http://bit.ly/aZo4nz [...]

  2. By Gadget Newz on June 25, 2010 at 2:28 pm

    [...] Google Analytics Data Export API w/ Google Charts [...]