Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Piwik in Ruby on Rails with Turbolinks (and proxy)
# Heavily inspired by
# Call `PiwikAnalytics.init()` once per document load, e.g.:
# unless $(document).data("piwik_loaded")
# PiwikAnalytics.init()
# $(document).data("piwik_loaded", "loaded")
class @PiwikAnalytics
@trackerUrl: -> "//"
@siteId: ->
switch document.location.hostname.toLowerCase()
when "" then "1"
when "" then "2"
else "3"
# ========
# = Core =
# ========
@init: ->
return if PiwikAnalytics.isLocalRequest()
# Piwik Analytics depends on a global _paq array. window is the global scope.
window._paq = []
window._paq.push(['setTrackerUrl', PiwikAnalytics.trackerUrl() + '/piwik.php'])
window._paq.push(['setSiteId', PiwikAnalytics.siteId()])
# Create a script element and insert it in the DOM
pa = document.createElement("script")
pa.type = "text/javascript"
pa.defer = true
pa.async = true
pa.src = PiwikAnalytics.trackerUrl() + '/piwik.js'
firstScript = document.getElementsByTagName("script")[0]
firstScript.parentNode.insertBefore pa, firstScript
# If Turbolinks is supported, set up a callback to track pageviews on page:change.
# If it isn't supported, just track the pageview now.
if typeof Turbolinks isnt 'undefined' and Turbolinks.supported
document.addEventListener "page:change", (->
), true
@isLocalRequest: ->
host = PiwikAnalytics.documentDomainIncludes
return true if host "localhost"
return true if host ""
return true if host "staging"
@documentDomainIncludes: (str) -> document.domain.indexOf(str) isnt -1
@push: (ary) -> window._paq.push(ary)
@trackPageView: (url) ->
unless PiwikAnalytics.isLocalRequest()
if url
if url == "refresh"
window._paq.push ["setCustomUrl", document.location.href]
window._paq.push ["setDocumentTitle", document.title]
window._paq.push ["trackPageView"]
window._paq.push ["enableLinkTracking"]
window._paq.push ["trackPageView", url]
window._paq.push ["trackPageView"]
# =========================================
# = Add your custom tracking methods here =
# =========================================
# @trackEcommerceView: (sku) ->
# unless PiwikAnalytics.isLocalRequest()
# window._paq.push(['setEcommerceView', sku])
# @trackGoal: (id, price=0 ) ->
# unless PiwikAnalytics.isLocalRequest()
# window._paq.push(['trackGoal', id, price])
# @addEcommerceItem: (sku, name, category, price) ->
# unless PiwikAnalytics.isLocalRequest()
# window._paq.push(['addEcommerceItem', sku, name, category, parseFloat(price)])
# @trackEcommerceOrder: (order_id, revenue) ->
# unless PiwikAnalytics.isLocalRequest()
# window._paq.push(['trackEcommerceOrder', order_id, parseFloat(revenue)])
# @trackEcommerceCartUpdate: (sum) ->
# unless PiwikAnalytics.isLocalRequest()
# window._paq.push(['trackEcommerceCartUpdate', parseFloat(sum)])
# NOTE: requires HTTParty gem
# - Change your trackerUrl to your domain, no need to change the js location as with the PHP proxy!
# - Add to your config/routes.rb:
# get 'piwik' => 'piwik#proxy'
class PiwikController < ApplicationController
# Required because you will get this errors otherwise (don't ask me why):
# Security warning: an embedded <script> tag on another site requested protected JavaScript.
# If you know what you're doing, go ahead and disable forgery protection on this action to
# permit cross-origin JavaScript embedding.
skip_before_filter :verify_authenticity_token
def proxy
# Edit the line below, and replace
# with your Piwik URL ending with a slash.
# This URL will never be revealed to visitors or search engines.
piwik_url = ''
# Edit the line below, and replace xyz by the token_auth for the user "UserTrackingAPI"
# which you created when you followed instructions above.
token_auth = 'xyz'
# Maximum time, in seconds, to wait for the Piwik server to return the 1*1 GIF
timeout = 5
# Don't edit below here!
if params[:format] == "php"
headers = { "User-Agent" => request.user_agent }
data = params.except(:action, :controller, :format).merge(cip: request.remote_ip, token_auth: token_auth)
gif = HTTParty.get("#{piwik_url}piwik.php?#{data.to_query}", timeout: timeout, headers: headers).response.body
send_data gif, type: :gif
# Rack::Cache will take care of the heavy lifting
response.headers["Expires"] = 1.hour.from_now.httpdate
render js: HTTParty.get("#{piwik_url}piwik.js").response.body

This comment has been minimized.

Copy link

@erpe erpe commented Apr 29, 2015

the additional
window._paq.push ['enableLinkTracking']
in @trackPageView causes piwik to error on page-reloads:

The method enableLinkTracking is registered more than once in "_paq" variable. Only the last call has an effect. Please have a look at the multiple Piwik trackers documentation:

but nice improvement anyway



This comment has been minimized.

Copy link
Owner Author

@2called-chaos 2called-chaos commented Jun 9, 2015

@erpe yeah you are right but it's only a warning and we couldn't find any disadvantage due to this. I removed the warning from the js code. As it says "only the last call has an effect" and that's okay. Otherwise you won't track after loading a page via turbolinks.

If I'm not mistaken the warning doesn't show up anymore in the new releases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment