Fetch Your Google Analytics Data Using Rails

Today we will see how to collect your data from Google Analytics. Everyone use it, I’m sure, but sometime, for many different reasons, you can have to collect those data using the API provided by google. Of course with rails most of the time you can find a gem to do that and for Google Analytics API you have garb.

This gem allows you to connect to your google account (or the one of your customer) and then fetch all the information you need.

In theory it’s not so complicated, but in practice if you want to provide a real analytics engine, this gem in not so convenient.

Let’s see how to implement it in a basic way first. Let’s say I just want all the time the same metrics, the number of visits per day during the last month.

First step connect and fetch the google profile you need (the one with UA-XXXXXXXX-XX).

1
2
3
4
def get_profile ga_ua
  Garb::Session.login MY_ACCOUNT, MY_ACCOUNT_PWD
  Garb::Management::Profile.all.find { |p| p.web_property_id == ga_ua }
end

Second step create the report you want

app/reports/visits.rb
1
2
3
4
5
6
module Report
  class Visits < Garb::Model
    metrics :visits
    dimension :date
  end
end

And then fetch the results

1
Report::Visits.result get_profile("UA-XXXXXXXX-XX"), start_date: 1.month.ago.to_date

So this is not so bad but let’s say you want to have a report now with the number of new visitors per days, then also per month, the visits per hours and just even let the user select the metric, the dimension and even some filter (s)he want. You will not be able to write a report for everything so let’s adapt this to create a dynamic report.

A generic report

First you need to add the reset function in ReportParameter (this class manage a list of elements which can be your metrics or your dimensions).

1
2
3
4
5
6
7
module Garb
  class ReportParameter
    def reset elements=[]
      @elements = elements
    end
  end
end

When this is done, you can remove all your reports files and write only one.

app/reports/report.rb
1
2
3
module Report
  class Generic < Garb::Model; end
end

And now start the “tricky” part. Instead of just Report::Visits.result() we will have to create a report and add the metrics and dimensions just like that.

1
2
3
4
5
6
def create_report metrics, dimensions
  report = Report::Generic
  report.metrics.reset metrics
  report.dimensions.reset dimensions
  report
end

Once this is done you can fetch your result like before

1
2
report = create_report [:visits], [:date]
report.result get_profile("UA-XXXXXXXX-XX"), start_date: 1.month.ago.to_date

For filters you need to give it on the result function like that

1
2
3
report.result get_profile("UA-XXXXXXXX-XX"), start_date: 1.month.ago.to_date, filter: {
  :campaign.contains => "whatever_you_want"
}

Of course this is not really convenient if you want to let the user choose its own filter because you need to play with some symbols but with a small function you can convert all.

1
2
3
4
5
6
7
8
9
10
11
12
13
# filter parameter should be like that
#   { campaign: { contains: "what_you_want" } }
# if you have multiple value only the first one will be taken
#   { campaign: { contains: "what_you_want", substring: "blabla" }, visits: { gt: 20 } }
#   will generate
#   { :campaign.contains => "what_you_want" }
# have a list of all filters on lib/garb/core_ext/symbol.rb
def convert_filter filter={}
  return if filter.empty?
  filter_name = filter.keys.first.to_sym
  comparator = filter[filter_name].keys.first.to_sym
  { filter_name.method(comparator).call => filter[filter_name][comparator] }
end

(you can see some meta-programming with method(comparator).call this will call the method which have the name of the value of comparator)

Now you can simply create a controller to give all your parameters and then just create the report you want.

report_controller.rb
1
2
3
4
5
6
7
8
9
10
...
  def index
    report = create_report params[:metrics], params[:dimensions]
    render json: report.result get_profile(params[:ga_ua]), {
      start_date: Date.parse(param[:start_date] || 1.month.ago.to_date.to_s),
      end_date: Date.parse(param[:start_date] || Date.current.to_s),
      filter: convert_filter params[:filter]
    }
  end
...

Now you can create a nice UI to display all possible metrics and you can do your clone of Google Analytics (or maybe not…). You will see the API is not really fast so you will need to use a lot of cache or display a nice loader for your user ;)

Note: Of course you can write your report(s) as a model but personally I prefer to create a folder for that and then load it in my config/application.rb with config.autoload_paths += %W(#{config.root}/app/reports)

Comments

Copyright © 2014 - Anthony Estebe -