Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

User Behavior Tracking with Google Analytics, Garb, and Vanity

31,653 views

Published on

User behavior tracking can be difficult. If done properly, it can be invaluable in helping to shape the evolution of your product. Done poorly, and it can lead to expensive mistakes. Learn the tools and techniques that will help you make the right choices. If you'd like to do this, check out Legato: https://github.com/tpitale/legato

Published in: Technology, News & Politics
  • Be the first to comment

User Behavior Tracking with Google Analytics, Garb, and Vanity

  1. USER BEHAVIOR TRACKING with Google Analytics, Garb, and a RailsConf 2010 | Baltimore, MD Tony Pitale | @tpitale | Viget Labs
  2. Google Analytics Garb Vanity
  3. 1. Track! 2. Interpret and Identify 3. Alternate and Refactor
  4. 1. Google Analytics 2. You w/ Garb 3. Vanity
  5. QUESTIONS TO ANSWER:
  6. WHICH LINKS ARE BEING
  7. WHERE ARE USERS LANDING?
  8. WHERE ARE USERS EXITING?
  9. WHERE DO USERS SPEND TIME?
  10. WHAT ARE LOGGED-IN USERS DOING?
  11. QUESTIONS TO ANSWER:
  12. WHICH LINKS ARE BEING CLICKED?
  13. GOOGLE ANALYTICS
  14. ASYNC TRACKING
  15. _gaq.push
  16. var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-65432-1']); _gaq.push(['_trackPageview']);
  17. (function() {   var ga = document.createElement('script');   var src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www');   src += '.google-analytics.com/ga.js';   ga.type = 'text/javascript';   ga.async = true;   ga.src = src;   var s = document.getElementsByTagName('script')[0];   s.parentNode.insertBefore(ga, s); })();
  18. WHAT SHOULD WE TRACK?
  19. TRACK EVERYTHING!
  20. TRACK CLICKS AS VIRTUAL PAGEVIEWS
  21. _gaq.push(['_trackPageview', '/signup/header']); _gaq.push(['_trackPageview', '/signup/call-to-action']);
  22. Modal Windows
  23. _gaq.push(['_trackPageview', '/new-repo/add']); _gaq.push(['_trackPageview', '/new-repo/cancel']);
  24. TRACK EVENTS
  25. _gaq.push(['_trackEvent', 'signup-button', 'clicked']);
  26. LIMITATIONS TO GA
  27. A BETTER IDEA
  28. def create   @thing = Thing.new(params[:thing])   if @thing.save     track_pageview("/things/create")     flash[:notice] = "Thanks for saving that thing."     redirect_to thing_path(@thing)   else     render :action => :new   end end
  29. def create   @thing = Thing.new(params[:thing])   if @thing.save     track_pageview("/things/create")     flash[:notice] = "Thanks for saving that thing."     redirect_to thing_path(@thing)   else     render :action => :new   end end
  30. def analytics_pusher_meta_tag   meta_tags = ""      if track_pageview?     content = Rack::Utils.escape_html(session.delete(:pageview_to_track))     meta_tags << %(<meta name="track-pageview" content="#{content}" />)   end   meta_tags.html_safe end
  31. var track_pageview = $('meta[name=track-pageview]').attr('content'); if(track_pageview !== undefined) {   _gaq.push('_trackPageview', track_pageview); }
  32. WHICH LINKS ARE BEING CLICKED?
  33. WHERE ARE USERS LANDING?
  34. LET’S EXPORT SOME DATA
  35. GARB
  36. LOGGING IN & SESSION
  37. # access_token = Ruby OAuth Gem access token # global, default Garb::Session.access_token = access_token # instance session = Garb::Session.new session.access_token = access_token
  38. # global, default Garb::Session.login('username', 'password') # instance session = Garb::Session.new session.login('username', 'password')
  39. ACCOUNTS & PROFILES
  40. # global session accounts = Garb::Account.all # explicit session; better accounts = Garb::Account.all(session)
  41. account = accounts.first puts account.id puts account.name profile = account.profiles.first puts profile.web_property_id # UA-65432-1 puts profile.table_id # internal id for GA puts profile.title puts profile.account_name # matches account.name puts profile.account_id # matches account.id # Find the first profile with UA number, explicit session profile = Profile.first('UA-65432-1', session) # Find the first profile with this table id, global session profile = Profile.first('1234567')
  42. # Find the first profile with UA number, explicit session profile = Profile.first('UA-65432-1', session)
  43. REPORTS
  44. class Landings   extend Garb::Resource   metrics :entrances   dimensions :landing_page_path end
  45. RESULTS
  46. Landings.results(profile) Landings.results(profile,   :limit => 20,   :offset => 99,   :start_date => (Date.today - 30),   :end_date => (Date.today))
  47. #<OpenStruct landing_page_path="/", entrances="2529"> #<OpenStruct landing_page_path="/team.html", entrances="26"> #<OpenStruct landing_page_path="/features/control.html", entrances="14"> #<OpenStruct landing_page_path="/contact.html", entrances="10"> #<OpenStruct landing_page_path="/services.html", entrances="9"> #<OpenStruct landing_page_path="/features/customer.html", entrances="5"> #<OpenStruct landing_page_path="/features/complete.html", entrances="4"> #<OpenStruct landing_page_path="/industry.html", entrances="4"> #<OpenStruct landing_page_path="/blog.html", entrances="3"> #<OpenStruct landing_page_path="/blog/las_vegas_trade_show.html", entrances="3"> #<OpenStruct landing_page_path="/features/location.html", entrances="2"> #<OpenStruct landing_page_path="/blog/imbibe-wine-and-spirits.html", entrances="1"> #<OpenStruct landing_page_path="/blog/nrf_trade_show_2009.html", entrances="1"> #<OpenStruct landing_page_path="/blog/retailer_incentive_program.html", entrances="1"> #<OpenStruct landing_page_path="/home", entrances="1"> #<OpenStruct landing_page_path="/support.html", entrances="1">
  48. ADDING FILTERS & SORTING
  49. class Landings   extend Garb::Resource   metrics :entrances   dimensions :landing_page_path   sort :entrances   filters :landing_page_path.contains => 'blog'   # OR   filters do     contains(:landing_page_path, 'blog')   end end
  50. #<OpenStruct landing_page_path="/blog.html", entrances="3"> #<OpenStruct landing_page_path="/blog/las_vegas_trade_show.html", entrances="3"> #<OpenStruct landing_page_path="/blog/imbibe-wine-and-spirits.html", entrances="1"> #<OpenStruct landing_page_path="/blog/nrf_trade_show_2009.html", entrances="1"> #<OpenStruct landing_page_path="/blog/retailer_incentive_program.html", entrances="1">
  51. Operators on Metrics eql => '==', not_eql => '!=', gt => '>', gte => '>=', lt => '<', lte => '<=' Operators on Dimensions matches => '==', does_not_match => '!=', contains => '=~', does_not_contain => '!~', substring => '=@', not_substring => '!@'
  52. REPORT ON-THE-FLY
  53. report = Garb::Report.new(profile, :limit => 20, :offset => 99) report.metrics :exits report.dimensions :page_path report.sort :exits report.filters :page_path.contains => 'season' # OR report.filters do   contains(:page_path, 'season') end
  54. WHERE ARE USERS LANDING?
  55. WHERE ARE USERS EXITING?
  56. COMMON CALCULATIONS
  57. class Exits   extend Garb::Resource   metrics :exits, :pageviews   dimensions :page_path end
  58. EXITS/PAGEVIEWS Exit Rate per Page Path
  59. ABANDONMENT
  60. TRACK GOALS
  61. _gaq.push(['_trackPageview', '/contact/submit']);
  62. WHERE ARE USERS EXITING?
  63. WHERE DO USERS SPEND TIME?
  64. COMMON CALCULATIONS
  65. class PageviewExitsAndTime   extend Garb::Resource   metrics :pageviews, :exits, :time_on_page   dimensions :page_path end
  66. TIME/(PAGEVIEWS-EXITS) Average Time on Page, Per Page
  67. WHERE DO USERS SPEND TIME?
  68. WHAT ARE LOGGED-IN USERS DOING?
  69. SETTING CUSTOM VARIABLES
  70. _gaq.push(['_setCustomVar', 1, 'logged-in', 'member', 1]); // or as an admin, to partition their data _gaq.push(['_setCustomVar', 1, 'logged-in', 'admin', 1]); _gaq.push(['_trackPageview']);
  71. // track just this pageview to a custom variable _gaq.push(['_setCustomVar', 1, 'purchase', 'level-2', 3]); _gaq.push(['_trackPageview']); // what do users do the rest of this session _gaq.push(['_setCustomVar', 1, 'purchase', 'level-2', 2]); _gaq.push(['_setCustomVar', 2, 'upgrade', '1', 2]); // use slot 2 _gaq.push(['_trackPageview']);
  72. GREAT FOR SEGMENTS
  73. SEGMENT ID IN REPORTS
  74. class Pageviews   extend Garb::Resource   set_segment_id 0   metrics :pageviews, :visits end
  75. WHAT ARE LOGGED-IN USERS DOING?
  76. HOW DO WE IMPROVE?
  77. A/B TESTING
  78. VANITY
  79. METRICS
  80. # in file experiments/metrics/signup.rb metric "Signup (Activation)" do   description "Measures how many people signed up for our awesome service." end
  81. # looks for the metric in experiments/metrics/signup.rb # done in UsersController#create, for example track! :signup
  82. A/B TEST
  83. ab_test "Tagline" do   description "Testing to see if a different tag line increases number of signups."   metrics :signup end
  84. <% tagline = (ab_test(:tagline) ? "Buy Now!" : "Signup for Free!") %> <h1><%= tagline %></h1>
  85. ab_test "Tagline" do   description "Testing to see if a different tag line increases number of signups."      alternatives "Buy Now!", "Signup for Free!", "Always Free, Signup Now!"      metrics :signup end
  86. <h1><%= ab_test :tagline %></h1>
  87. INTEGRATE VANITY W/GARB
  88. metric "Acquisition: Visits" do   description "Visits"   google_analytics "UA-65432-1", :visits end
  89. CUSTOM VANITY/GARB
  90. metric "Signups Welcomed" do   google_analytics "UA-65432-1"   # report is an instance of Garb::Report   report.metrics :visits   report.dimensions :page_path   report.filters do     eql(:page_path, 'welcome')   end end
  91. REALLY CUSTOM REPORTS
  92. metric "Activation" do   description "Measure page views for /"   def values(from, to)     report = Garb::Report.new(ACTIVE_PROFILE, {:start_date => from, :end_date => to})     report.metrics :pageviews     report.dimensions :page_path, :date     report.sort :date     report.filters do       eql :page_path, '/'     end     # hack because data isn't returned if it's 0     data = report.results.inject({}) do |hash, result|       hash.merge(result.date => result.pageviews.to_i)     end     (from..to).map do |day|       key = day.strftime('%Y%m%d')       data[key] || 0     end   end end
  93. HOW DO WE IMPROVE?
  94. COMMON USES
  95. ENCOURAGE USERS
  96. EASY ADMIN
  97. FOR THE ROAD
  98. FOLLOW THE MONEY
  99. NOBODY IS PAID BY THE PAGEVIEW
  100. USER TESTING STILL WINS
  101. RESOURCES ‣ http://vanity.labnotes.org/ ‣ http://github.com/assaf/vanity ‣ http://wiki.github.com/vigetlabs/garb/ ‣ http://github.com/vigetlabs/garb ‣ http://code.google.com/apis/analytics/docs/ ‣ http://code.google.com/apis/analytics/docs/gaJS/gaJSApi_gaq.html ‣ http://code.google.com/apis/analytics/docs/gdata/ gdataReferenceDimensionsMetrics.html ‣ http://code.google.com/apis/analytics/docs/gdata/ gdataReferenceValidCombos.html ‣ http://code.google.com/apis/analytics/docs/gdata/ gdataReferenceCommonCalculations.html
  102. THANKS! http://speakerrate.com/talks/3455 Photo Credits ‣ Fi ‣ jstbtrflyz2 ‣ RobertClavarro ‣ krm_gib ‣ talllguy ‣ fragglerawker RailsConf 2010 | Baltimore, MD ‣ erica_marshall Tony Pitale | @tpitale | Viget Labs
  103. Q&A BONUS ROUND

×