Affiliate Click Tracking With Rack And Redis Because I Care

I’ve been investigating methods for performing affiliate based click tracking, for both work and my own personal needs. I’ve tried using Rails directly, Sinatra and Rack.

  1. Rails – Slow, hell no.
  2. Sinatra – Fast, but now another app to maintain (as small as it is), but still an option.
  3. Rack – Faster than Rails, slower than Sinatra. Less to manage.

I built some Rack middleware today, and thought I’d show you guys what I came up with. Here is how it works:

  1. Surfer hits http://click.ourdomain.com/track/7868635/campaign/some/path/here.
  2. Rack takes the request, shoves into Redis using lists.
  3. Rack sets a cookie.
  4. Rack redirects to http://ourdomain.com/some/path/here.
  5. A daemon polls Redis to post process the data. This is out of the scope of this post though, maybe later.

You might be wondering what’s with the url. Simple, the digit is the affiliateID, the ‘campaign’ is whatever dynamic text-tag they want for organizing the traffic, and /some/path/here is where on ourdomain.com to redirect the user. This allows affiliates to send surfers anywhere on the site and still get credit, no need for generating custom links.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
require 'rubygems'
require 'redis'

class Click
  def initialize(app)
    @app = app
  end
 
  def call(env)
    if env["PATH_INFO"] =~ /^\/track\/([0-9]+)\/[a-zA-Z0-9-]+\/(.*)/
      host = parse_host(env["HTTP_HOST"])
      add_click_to_queue(env)
      response = Rack::Response.new("Redirecting ...")
      response.set_cookie("click#{host[:domain]}", {
        :domain => host[:domain],
        :path => '/',
        :expires => 30.days.from_now,
        :value => $1
      })
      response.redirect("#{host[:host]}/#{$2}")
      response.finish
    else
      @app.call(env)
    end        
  end

  def parse_host(host)
    base = host.split('.', 2)[1]
    { :host => "http://#{base}", :domain => ".#{base.split(':').first}" }
  end
 
  def add_click_to_queue(env)
    redis ||= Redis.new
    redis.push_tail 'clicks', Marshal.dump({
      :path => env["PATH_INFO"],
      :ip =>  env["REMOTE_ADDR"]
    })    
  end  
end

This is just a mockup. Like I said, I’m not covering the post-processing of the data by polling Redis, that might come soon. I encourage you to leave comments on better methods for doing tracking clicks, integrating with Redis, etc. Thanks to @seanstickle for helping me on the cookie details.

Werd.

Related posts:

  1. Ezmobius Is The Devil And Is Gaining Followers For The Apocalypse Using Nanite
  2. Find Missing Table Indexes With ActiveRecord For The Inept
  • Adam
    Would love to hear more about the analytics you're running against the data collected in redis. Thanks!
  • BenDamond
    Hi! great idea, interesting method but I guess it is a lot to work to create click tracking to work very good, although I appreaciate that you decided to post your work not everybody does that.

    ______________________
    Affiliates
  • In the system I'm building, you just add more nodes to post-process the clicks, unlike most click tracking systems that process on click then redirect.
  • apeacox
    hi mrkris,

    to implement link tracking, I've used a LAMP stack (lack of choice from customer). the tracking worked in a way similar to google-analytics:
    - in the affiliate page, insert a reference to a remote js, specifying ID of the site (yes, generate a custom JS for each request related to an affiliate site). the js can eventually load an image (for example a banner) working on the page DOM (that's why there's a custom generated JS).
    - the system gets the requests and save the record. if there's a cookie, then check the record on db for eventual UPDATES instead of INSERT (speacking in SQL terms). saved referer too.
    - every 10-15 secs, the JS make ajax update request, so there's a track of time per page.

    I've worked on the analisys and first core implementation of that system (http://bit.ly/1c1Pk1), then I left the job to others (I was a consultant) . I know it isn't the best way of doing link tracking, but it worked very well :) (seems that the official launch will be during the next weeks).

    if you want, we can talk about it more in detail ;)

    cheers,
    apeacox
  • Interesting method, though I don't think it's easily maintainable. I only say this because placing JS on each page to track it seems overkill. The way I have it working is you hit the click tracking system and it redirects you. Track from one point for clicks, track per page with analytics for site specific tracking.
  • apeacox
    I agree with you :) but the app had to be very similar to analitycs. the goal was to sell/buy banners from/to affiliated sites. so we had to calc collected data in way to give a value for ads. moreover, we had only that tools, I'd use other ways and/or technologies :P
    anyway, your solution looks very interesting! getting request and repliyng with a redirect is a cool idea (and redis too) ;-)
  • zaach
    Sinatra runs on Rack, so I'm not sure how Rack could be slower. Rails also runs on Rack, so you could conceivably use this middleware with either framework, or a minimal Rack app as I believe you suggest.
  • I was more meaning, Rack on Rails -- With Sinatra, `ab' was yielding between 700~ requests/sec, whereas Rails is yielding 350~ requests/sec.
  • zaach
    Oh, yeah, that makes more sense.
blog comments powered by Disqus