My favorites | English | Sign in

Google Analytics

Visualizing Google Analytics Data with Google Chart Tools

Alexander Lucas, Google Analytics API Team
July 2010

Contents

  1. Introduction
  2. Before You Start
  3. Retrieving Data from the Google Analytics API
    1. Before You Start
    2. The Query
  1. Making It Look Awesome - Visualizing Your Data
    1. Converting Your Analytics Data
    2. Setting up Chart Parameters
    3. Displaying The Chart
  2. Next Steps

Introduction

This article shows you how to take data from the Google Analytics Data Export API and visualize it with a variety of different graph types using the Google Charts API. This particular article is going to focus on doing it in Javascript, which allows for things like setting up slick dashboards in your web applications, without having to figure out how to draw charts yourself. However, since requests to the Chart API only use URLs, this can be done in any language you wish.

The code you're going to write will do the following:

  1. Pull a week's worth of data from Google Analytics
  2. Format that data into something that can be used by the Charts API
  3. Configure parameters for the chart that will display your data
  4. Convert those chart parameters into a chart URL, and insert an image into your web page using that URL

Before You Start

You'll get the most out of this article if you have the following:

Back to Top

Retrieving Data from the Data Export API

Prerequisites

To pull data from Google Analytics, you'll need the following pieces of information:

  • Your username/password information for a Google Analytics account with at least read-access to the profile you wish to pull data from.
  • The profile ID of the Google Analytics profile you wish to pull data from. The easiest way for you to get the profile ID is to visit the "Profile Settings" page in Google Analytics, as described the Data Export API Feed Reference.

The first step is to create two files, analyticsCharts.html and analyticsCharts.js. The HTML file is almost identical to what you see in the Setting Up Your HTML File section of the Getting Started guide. You can start with the code in this example below.

View Full HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- Author:  Alexander Lucas (api.alexl@google.com) -->
<html>
  <head>
    <title>My First Google Analytics Data Export API Script</title>
    <script type="text/javascript"
    src="https://www.google.com/jsapi"></script>
    <script type="text/javascript"
    src="analyticsCharts.js"></script>
  </head>
  <body>
    <h1>Analytics Data Export API Script</h1>
    <button id="authButton">Loading...</button>
    <div id="dataControls" style="display:none">
      <p>
        For this user, retrieve the first 50 accounts with profile ID and table ID
        <button id="getAccount">Get Account Data</button>
      </p>
      <p>
        For this profile, show visitor type and entrance/exit graphs:
        <input type="text" id="tableId"/> (insert Table ID)
        <button id="getData">Get Report Data</button>
      </p>
    </div>
    <table>
      <tr>
      <td><div id="visitorsDiv"></div></td>
      <td><div id="entrancesDiv"></div></td>
    </tr>
  </table>
  <img src="dummy.gif" style="display:none" alt="required for Google Data"/>
</body>
</html>
  

Back to Top

The Query

For the purposes of this article, we're going to create a query that returns visits by visitor type, and look at various ways of displaying that data. The ga:visitorType dimension is unusual in that it only has two possible values, as opposed to a dimension like ga:keyword, which is open-ended. These two possible values are "New Visitor" and "Returning Visitor." It's very useful to graph these over time. For instance, spikes in new visits vs returning visits can indicate a great new link to your site, or the kickoff of an effective ad campaign. Let's measure these by day, and grab about 10 days worth of data. The query looks like this:

var myFeedUri = ['https://www.google.com/analytics/feeds/data',
  '?start-date=2010-06-01',
  '&end-date=2010-06-10',
  '&dimensions=ga:day,ga:visitorType',
  '&metrics=ga:visits',
  '&sort=ga:day',
  '&max-results=20',
  '&ids=', document.getElementById('tableId').value].join('');

So far none of this is new territory. This query returns a result object which, because you read the Javascript Data Export API Getting Started Guide, you already know how to manipulate and extract information from in order to produce gorgeous, stunning... rows of tabular data. The next section shows you a better way to visually express that data, in a way that's much easier for people to digest.

Back to Top

Make It Look Awesome - Visualizing Your Data

Choosing Your Graph Type

Using the Google Chart API, you have the power to create practically any type of chart you could possibly want. But, with great power comes great responsibility. Before you run off to create an entire powerpoint presentation's worth of lines, bars, arrows and pie slices, take a minute to peruse the types of charts available, and think about which one is appropriate for the data relationship you're trying to display. Different types of relationships go best with different types of graphs. Also, remember that it's those relationships that are worth graphing — a number in isolation doesn't actually tell you anything, and shouldn't be graphed at all. Let's take total visits and graph it.



A few ideas to get you started: Line and bar graphs are particularly good at showing trends — whether certain metrics are going up or down over days, weeks, or months. Pie charts, on the other hand, are particularly well suited to comparing values against eachother — showing whether one number totals 2x, 3x, or 4x bigger than the other. While bar/line charts can do this too, pie charts make it easier to express things like "how total number of x is split up by category." However, while pie charts can be great at showing data for snapshots in time, one pie chart can't really express a trend over time the way a bar or line chart can. By way of example:

Good display of trend Visually confusing nonsense
Here you can see one value is bigger Here you can see one value is 3x bigger

Back to Top

Converting Your Analytics Data

Before you can create a graph, the data you get back from the Data Export API needs to be massaged into the right format. That format can vary a little from graph type to graph type, as you'll see, but if you at least pull the data out into a more manageable data structure, it'll be easier to format for specific graph types later on. Two useful places to start are:

  • Dropping the results of each data into their own array. In our case, that's one array of visits from new visitors, and one array of visits from returning visitors. Let each entry in the array represent a particular day.
  • Create a dictionary somewhere of name/value pairs for everything that will go into the resulting graph. What colors you want, what data you're using, the dimensions of the graph, all these things should be easy to look up and modify by key.

Let's start with our "Visits by Visitor Type" query. The pieces you're going to need are:

  • A day value to associate with each entry
  • A visitor type to associate with each entry
  • The number of visitors for that specific type, on that specific day
  • A running count of the max values for each visitor type (for setting the graph to the right scale)

Keep in mind that for a 10-day span, and two possible visitor types, the result set might not contain 20 entries. For instance, if on day 1 there are 10 new visitors and 0 returning visitors, there won't be an entry that says

ga:day: 1
ga:visitorType: returning visitor
ga:visitors: 0

Instead, no entry will be returned at all.

The only time it will ever return 0 for a single metric is if the only dimension in the query is a date. As a result, it's necessary to make sure, client-side, that your visitor count arrays are staying in sync with the correct date (assuming you're using date dimensions). This means we need to make sure our table rows stay in sync, which we do by adding a zero to the newVisitor or returningVisitor arrays when no entry is detected for that day/visitor type combo.

The following method grabs the data from the Analytics result, copies it into an object, and returns that object.

function getVisitorChartData(result) {
  var entries = result.feed.getEntries();
  var returningVisitors = [];
  var newVisitors = [];
  var days = [];
  var maxReturningVisitors = 0;
  var maxNewVisitors = 0;

  for (var i = 0, entry; entry = entries[i]; ++i) {
    var visType = entry.getValueOf('ga:visitorType');
    var numVisits = entry.getValueOf('ga:visits');
    var day = parseInt(entry.getValueOf('ga:day'), 10);

    // At the beginning of each day, check if data was missing for previous
    // day.  Insert "0" in appropriate visitor's array as necessary, using
    // fillToSameSize helper method.
    if (!days.length) {
      days.push(day);
    } else {
      var lastDay = days[days.length - 1];
      if (day != lastDay) {
        days.push(day);
        fillToSameSize(newVisitors, returningVisitors);
      }
    }

    if (visType == 'New Visitor') {
      newVisitors.push(numVisits);
      maxNewVisitors = Math.max(maxNewVisitors, numVisits);
    } else {
      returningVisitors.push(numVisits);
      maxReturningVisitors = Math.max(maxReturningVisitors, numVisits);
    }
  }
  fillToSameSize(newVisitors, returningVisitors);

  return {
    'returningVisitors': returningVisitors,
    'newVisitors': newVisitors,
    'maxNewVisitors': maxNewVisitors,
    'maxReturningVisitors': maxReturningVisitors,
    'days': days
  };
}

function fillToSameSize(firstArray, secondArray) {
  if (firstArray.length < secondArray.length) {
    firstArray.push(fillValue);
  } else if (secondArray.length < firstArray.length) {
    secondArray.push(fillValue);
  }
}

This method iterates through the results returned by the Analytics Export API, and dumps visitor numbers in two arrays, "returningVisitors" and newVisitors. The days, returningVisitors, and newVisitors arrays are added to a return object, along with the max values for new and returning visitors.

In order to keep the visitor arrays "in sync" with the days array, a helper method fillToSameSize checks at the beginning of each day to make sure the two arrays are the same size. If not, a "0" is added to the smaller array, making them the same size.

Now that you've got all the data, it's time start configuring your charts.

Back to Top

Setting up Chart Parameters

Every aspect of the chart you're going to build, from the colors used to the data it displays, is configured with a URL parameter. The number and type parameters depends on what kind of chart you're trying to build. Some are optional, many are required. The complete list of chart types and parameters that can be built are beyond the scope of this article. They're beyond the scope of any article. Seriously, there's a lot of them. If you wish to dive into the complete list, go to the Getting Started With Charts guide, and click on your chart type of choice in the left-hand nav. A detailed reference of the relevant parameters, and how they apply in the context of that chart type can be found there.

Because chart parameters are nothing more than name/value pairs, they lend themselves perfectly to being expressed with Javascript object properties. Also, use of objects instead of a giant concatonated string of parameters makes it easier to modify later. As you'll see, this method makes turning bar chart into a line chart a trivial matter of changing one or two of these parameters. To make things easy, let's create a "wrapper" object for the chart with some helper methods and a basic interface.

Chart Wrapper

function getChartObj() {
  var params_ = {
    'chs': '', // Image Dimensions
    'chtt': '', // Title
    'chxt': '', // Axes
    'chts': '', // Title Style
    'cht': '', // Chart type
    'chd': '', // Data
    'chdl': '', // Legend
    'chco': '', // Colors
    'chbh': '', // Width and spacing
    'chxl': '', // Axis Labels
    'chds': '', // Scaling
    'chxr': '', // Axis Scaling
    'chm': ''   // Chart Markers
  };
  var baseURL_ = 'http://chart.apis.google.com/chart';

  function getParams_() {
    return params_;
  }

  function getParam_(key) {
    return params_[key];
  }

  function setParam_(key, val) {
    if (params_[key] !== undefined) {
      params_[key] = val;
    }
  }

  function setParams_(obj) {
    for (key in obj) {
      setParam_(key, obj[key]);
    }
  }

  /**
   * Given a base URL and an array of parameters, construct the complete URL.
   * @return {string} The complete URL for the chart.
  */
  function getURL_() {
    paramArray = [];
    for (key in params_) {
      if (params_[key]) {
        pairStr = [key, params_[key]].join('=');
        paramArray.push(pairStr);
      }
    }
    paramStr = paramArray.join('&');
    url = [baseURL_, paramStr].join('?');
    return url;
  }

  return {
    'getParam': getParam_,
    'getParams': getParams_,
    'setParam': setParam_,
    'setParams': setParams_,
    'getURL': getURL_
  };
}
    

Here's a method that generates a new chart "object" and populates it with all the necessary parameters for a bar chart. Each parameter is sent as a key/value pair, which will eventually be converted to a URL parameter.

function getBarChart(chartData) {

  var chart = getChartObj();
  var returningVisitorsStr = chartData.returningVisitors.join();
  var newVisitorsStr = chartData.newVisitors.join();
  var maxValue = chartData.maxReturningVisitors + chartData.maxNewVisitors;

  scaleData = getScaleData(maxValue);

  // Set chart meta-data
  chart.setParams({
    'chs': '500x150', //Image dimensions
    'chxt': 'x,y', //Axes
    'chts': '000000,15', //Title Style
    'cht': 'bvs', //Chart Type (Bar, Vertical, Stacked)
    'chco': 'a3d5f7,389ced', //Colors
    'chbh': 'a,5,20', //Width & Spacing
    'chm': 'N,FF0000,-1,,12', //Markers
    'chtt': 'Visitors+By+Type', //Title
    'chdl': 'Returning+Visitors|New+Visitors', //Legend
    'chd': 't:' + returningVisitorsStr + '|' + newVisitorsStr, //Chart Data
    'chxl': '0:|' + chartData.days.join('|'), //Axis Labels
    'chds': '0,' + scaleData[0], //Scaling
    'chxr': '1,0,' + scaleData[0] + ',' + scaleData[1] //Axis Scaling
  });

  return chart;
}

Stepping through these parameters:

  • chs — Image Dimensions (in pixels) of the image file to be returned
  • chxt — Which axes (x and/or y) get labels
  • chtt — The title displayed at the top of the chart, in URL-escaped text
  • chts — Color and font size, comma-separated. FF0000,12 would mean red text in 12-point type
  • cht — The type of chart. For example, "bvs" means is a stacked vertical bar chart
  • chl — Pipe-seperated list of names for the data sets being displayed. Names should be URL escaped
  • chco — Colors (in RRGGBB format) to use in representing these data sets
  • chbh — Spacing between bars
  • chm — Text on the graph displaying the values represented by each bar
  • chd — Each data series to be used in the graph. Commas between every value in a series, pipes seperating one series from the next
  • chxl — Custom axis labels, one for each axis you want to label
  • chds — Custom min/max values for the chart. Any value larger than the max value will be displayed as though it were the max value. For instance, the default is always is min:0, max:100, so a bar with a value of 200 is larger than the max, and will show at the same height as a bar with the value 100. It's often the case that you'll want to find the largest value in your data set and use that as the max value.
  • chxr — Custom min, max, and increment-by values for a specified axis. Note that this does *not* have to correspond to the min/maxes defined by the "chds" variable. Those control the size of the object (line, bar, pie slice, etc) displaying the value can be. This one controls the start, end, and increment-by values for axes. They ONLY affect the labels on the axis. This can be confusing at first! Click the links to read up on these two parameters.

Astute readers will have noticed another helper method, getScaleData. This is a helper method which recommends a max value and increment values for the chart, based on a parameter representing the max value of a data point contained within the chart, in such a way that the following criteria are met:

  • The Y axis increments are nice, round numbers. If the max value of your graph is 186, and you want to have 5 "notches" along the y axis, the graph would be hard to follow with values of "37.2,74.4", etc. It's best to round up to something that can cleanly be divided by 5, like 200, and use that as the max value instead
  • Values on the graph are near, or over, the value halfway between 0 and the max. A trend in the data series of "9,12,13,15,18" is going to be a lot more visible on a graph that scales from 0 to 20, then it is on a graph that scales from 0 to 1000.

This very simple algorithm attempts to "guess" the right max value, so you could have better luck by knowing your data and using a pre-determined max value based on your own site traffic. For the interested, here's the body of the getScaleData method.

function getScaleData(currMax) {
  var result = [0, 0];
  // Determine order of magnitude (number of digits left of decimal).
  var magnitude = Math.log(currMax) / Math.LN10;
  magnitude = Math.ceil(magnitude);

  var newMax = Math.pow(10, magnitude);
  if (newMax / 5 > currMax) {
    newMax = newMax / 5;
  }
  while (newMax > (currMax * 2)) {
    newMax = newMax / 2;
  }

  var step = newMax / 5;
  result[0] = newMax;
  result[1] = step;
  return result;
}

You may have noticed that the method responsible for setting all the chart parameters is called getBarChart. If you want to set data for the pie chart instead, several of the parameters used are different. If you think about it, this makes sense— there's no x or y axis that needs labeling, there's no such thing as spacing between values in a pie chart, and pie charts aren't meant for displaying multiple data sets simultaneously but rather for one set of values being compared against eachother.

function getPieChart(chartData) {
  var chart = getChartObj();
  var newVisitors = getArraySum(chartData.newVisitors);
  var returningVisitors = getArraySum(chartData.returningVisitors);

  chartData.maxValue = returningVisitors + newVisitors;

  chart.setParams({
    'chs': '500x150', //Image dimensions
    'chts': '000000,15', //Title Style
    'cht': 'p3', //Chart Type
    'chco': 'a3d5f7,389ced', //Colors
    'chtt': 'Visitors+By+Type', //Title
    'chdl': 'Returning+Visitors|New+Visitors', //Legend
    'chd': 't:' + returningVisitors + ',' + newVisitors, //Chart Data
    'chl': returningVisitors + '|' + newVisitors, //Labels
    'chds': '0,' + chartData.maxValue //Max Value
  });

  return chart;
}

//Helper method to get the sum of values in an array.
function getArraySum(input) {
  var total = 0;
  for (var i = 0; i < input.length; i++) {
    total += input[i];
  }
  return total;
}

Note that unlike the previous set of data, we're using totals for each type of visitor, instead of expressing each data point individually. Also, we need fewer parameters in general.

Back to Top

Displaying the Chart

Now that you've got all that data, how do you create a chart out of it? You need to do two things.

  1. Construct the URL for the chart.
  2. Embed an IMG tag in the HTML file with that URL as the source.

Begin with constructing the URL. A method within the wrapper object called getURL combines the parameters with the base URL (also defined in the wrapper object). The resulting URL works as a request to the Chart API for an image of the chart. For reference, the method looks like this:

function getURL_() {
    paramArray = [];
    for (key in params_) {
      if (params_[key]) {
        pairStr = [key, params_[key]].join('=');
        paramArray.push(pairStr);
      }
    }
    paramStr = paramArray.join('&');
    url = [baseURL_, paramStr].join('?');
    return url;
  }

Now that you have the URL, use the drawChart method to embed an image at that URL into the DOM. The drawChart method takes two parameters, the name of the HTML container element where you want to embed the image, and the URL location of the image. The drawChart method can be written like this:

function drawChart(parentElementId, url) {
  document.getElementById(parentElementId).innerHTML +=
      '<img src="' + url + '" /></br />';
}

When you call the method with your bar/pie chart URLs, you'll have images that look something like this:

Bar Chart Pie Chart

Now that you've come this far, you can actually turn this stacked bar chart into other chart types with relatively little effort. For instance, to change it into a grouped bar chart, just modify the chart type to "bvg," change the markers so there's one for each series, and recompile the URL.

var groupedChart = getChartObj();
groupedChart.setParams(barChart.getParams());
groupedChart.setParam('cht', 'bvg');
groupedChart.setParam('chm', 'N,FF0000,0,,12|N,FF0000,1,,12');
var groupedChartURL = groupedChart.getURL();
drawChart('visitorDiv',groupedChartURL);

The end result will look like this:

Alternatively, you can skip out on bars altogether and convert it into a line chart. Change it to a chart type of "lc," and remove the markers entirely (they don't look good in line charts), like so:

var lineChart = getChartObj();
lineChart.setParams(barChart.getParams());
lineChart.setParam('cht', 'lc');
lineChart.setParam('chm', '');
var lineChartURL = paramsToURL(chartData.chartParams, chartData.baseURL);
drawChart('visitorDiv',lineChartURL);

And voila! Line charts!

This is why you delete the markers. Ah... much better.

Back to Top

What Next?

Now you can successfully visualize analytics data using the charting API. You know how to create bar, line, and pie charts at a whim. There are TONS of things you can do with this.

  • Make an iGoogle gadget!
  • Create a fancy traffic dashboard for your CMS!
  • Make super-important-looking wallpapers to impress your boss and/or loved ones!

But it doesn't stop there. This article only covered 3 chart types, and one single query. There are a hundred dimensions/metrics for you to query against, and a dozen different charts to display your results in. To see what options are available to you, explore these links. Happy coding!