Google Analytics

Visualizing Google Analytics Data with Google Chart Tools

Alexander Lucas, Google Analytics API Team – July 2010


  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:

  • A working knowledge of Javascript.
  • A working knowledge of Google Analytics, including an understanding of dimensions and metrics.
  • Access to an active Google Analytics account with at least a week's worth of data.
  • You have a local copy of the source code of the finished result of this article, which you get by downloading analyticsCharts.js and analyticsCharts.html.

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 view (profile) you wish to pull data from.
  • The view (profile) ID of the Google Analytics view (profile) you wish to pull data from. The easiest way for you to get the view (profile) ID is to visit the "View (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. You can start with the code in this example below.

Back to Top

The Query

For the purposes of this article, we're going to create a query that returns sessions by user type, and look at various ways of displaying that data. The ga:userType 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 User" and "Returning User." It's very useful to graph these over time. For instance, spikes in new sessions vs returning sessions 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:userType',
  '&metrics=ga:sessions',
  '&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 you can 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 sessions 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 sessions from new users, and one array of sessions from returning users. 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 "Sessions by User Type" query. The pieces you're going to need are:

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

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

ga:day: 1
ga:userType: returning user
ga:users: 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 user 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 newUser or returningUser arrays when no entry is detected for that day/user type combo.

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

function getUserChartData(result) {
  var entries = result.feed.getEntries();
  var returningUsers = [];
  var newUsers = [];
  var days = [];
  var maxReturningUsers = 0;
  var maxNewUsers = 0;

  for (var i = 0, entry; entry = entries[i]; ++i) {
    var visType = entry.getValueOf('ga:userType');
    var numSessions = entry.getValueOf('ga:sessions');
    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 user'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(newUsers, returningUsers);
      }
    }

    if (visType == 'New User') {
      newUsers.push(numSessions);
      maxNewUsers = Math.max(maxNewUsers, numSessions);
    } else {
      returningUsers.push(numSessions);
      maxReturningUsers = Math.max(maxReturningUsers, numSessions);
    }
  }
  fillToSameSize(newUsers, returningUsers);

  return {
    'returningUsers': returningUsers,
    'newUsers': newUsers,
    'maxNewUsers': maxNewUsers,
    'maxReturningUsers': maxReturningUsers,
    '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 user numbers in two arrays, "returningUsers" and newUsers. The days, returningUsers, and newUsers arrays are added to a return object, along with the max values for new and returning users.

In order to keep the user 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.

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 returningUsersStr = chartData.returningUsers.join();
  var newUsersStr = chartData.newUsers.join();
  var maxValue = chartData.maxReturningUsers + chartData.maxNewUsers;

  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': 'Users+By+Type', //Title
    'chdl': 'Returning+Users|New+Users', //Legend
    'chd': 't:' + returningUsersStr + '|' + newUsersStr, //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 newUsers = getArraySum(chartData.newUsers);
  var returningUsers = getArraySum(chartData.returningUsers);

  chartData.maxValue = returningUsers + newUsers;

  chart.setParams({
    'chs': '500x150', //Image dimensions
    'chts': '000000,15', //Title Style
    'cht': 'p3', //Chart Type
    'chco': 'a3d5f7,389ced', //Colors
    'chtt': 'Users+By+Type', //Title
    'chdl': 'Returning+Users|New+Users', //Legend
    'chd': 't:' + returningUsers + ',' + newUsers, //Chart Data
    'chl': returningUsers + '|' + newUsers, //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 user, 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('userDiv',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('userDiv',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!

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.