This one is deprecated since the demise of Gadgets on sites.
Each night I used to run a scheduled task which takes the Google Analytics data for this Google Sites and matches it up to the site pages. At the time of writing I have 1000 different pages in analytics to match to 500 pages on this site.
The code is pretty straightforward, and will clean up the result of an analytics query and place it in a nicely formatted object. As usual I’m using exponential backoff to avoid rate limiting problems
function getAnalytics(propertyId,optStart,optEnd,optDimension) {

  // get all data ever for this property
  var data = pageViews (propertyId, optStart || new Date(2010,0 ,1 ), optEnd || new Date(), optDimension || 'ga:pagePath');
  // clean up into a json object
  return ( function (row) {
    var i =0;
    return row.reduce(function (p,c) {
      p[data.columnHeaders[i++]['name'].replace("ga:","")] = c;
      return p;
  .sort ( function (a,b) {
    return (a.pagePath > b.pagePath ? 1 : (a.pagePath === b.pagePath ? 0 : -1)) ;
function pageViews (propertyId, start , finish, dimensions) {
  return cUseful.rateLimitExpBackoff(function () { 
    return Analytics.Data.Ga.get('ga:' + propertyId , gaDate(start), gaDate(finish),  'ga:pageViews', {
      "dimensions":  dimensions,
function gaDate (dt) {
  return Utilities.formatDate(dt, Session.getScriptTimeZone(), 'yyyy-MM-dd');

I called this for each time period in my report – I was going for the past month, the past year, and all time – and then match up the analytics with the each page on the site.

// create a set of analytics for each of these periods
  options.periods.forEach ( function(d,i) {
    // now get the analytics data - for each period
    matchAnalytics ( getAnalytics(options.propertyId,d.start,d.end) , root, site.getUrl(),i);

This returns an array of objects like this – notice how the urls have spelling mistakes to deal with in the matching process.


See more like this in  Displaying analytics data on site pages.