Sign up attribution for a Rails app

“I know I waste half of my advertising dollars...I just wish I knew which half.” said Henry Procter.

Knowing where your site signups come from is a good way of knowing if you are spending your advertisement dollars on the right target, but how would you do that?

Google Analytics is the most common tool used by many for that. The problem is Google Analytics can become very complicated very quickly. More importantly linking a campaign with a single signup is something that should happen in the app during the signup process. This will mark each individual user with the campaign they came from.

Mark your campaigns

Started by Google Analytics, UTM parameters in URLs were created to link campaigns to visits, but they are not limited to Google Analytics and are supported by almost any visitor tracking utility out there.

To start with, make sure all the links coming to your website use UTM parameters. You can use Google Analytics URL Builder or just simply add utm_source and utm_campaign to the URL coming to your site. This will end up looking something like this:

http://www.mysite.com?utm_source=test&utm_campaign=promo

Capture the UTM into a cookie

Not every one who visits the site is going to signup immediately, but they might do that later, so we need a way to capture that.

To achieve that, we are going to capture the utm parameters into a cookie that expires in a month. That way if the visitor signs up for up to a month, we know where he came from.

In Rails, we can do that by a filter:

before_filter :capture_utm

private

def capture_utm  
    unless cookies[:utm]
      cookies[:utm] = { :value => utm.to_json, :max_age => "2592000" }
    end
end

def utm  
    {
        :utm_source => params[:utm_source],
        :utm_campaign => params[:utm_campaign],
        :utm_medium => params[:utm_medium],
        :utm_term => params[:utm_term],
        :utm_content => params[:utm_content]
    }
end  

Read the cookie before signup

Linking the utm parameters with the new user is easy. If you are using Devise to manage your users, you can customise the signup controller to capture the value:

class CustomRegistrationsController < Devise::RegistrationsController

    def create
        super

        begin
            utm = cookies[:utm]
            if utm
                resource.utm_params = utm
                resource.save
            end
        rescue => exc 
            Rails.logger.error "Error reading utm cookie due to #{exc}"
        end

Make sure you add this line to your routes.rb:

devise_for :users, :controllers => {:registrations => “custom_registrations” }  

utm_params is a text field we added to the User class in a migration. This will store the JSON serialised version of the utm parameters in database next to each new signup.

You might want to avoid addin the values if they are empty (like when the signup came from no campaign) but I prefer having them there all the time to simplify reading and deserialising them during analysis.

What if you have multiple subdomains?

If you are like us, you don't only have 1 website. We have a blog (this one), help website and our community website. Also our main website (www.cloud66.com) is a separate app.

All of our apps are hosted on cloud66.com subdomains: blog.cloud66.com, help.cloud66.com and community.cloud66.com

This means we can use cookies that run across all of our websites. In Rails you can do this by adding domain to the cookies.

This will change the capture_utm method above to this one:

def capture_utm  
    unless cookies[:utm]
      cookies[:utm] = { :value => utm.to_json, :max_age => "2592000", :domain => ".mydomain.com" }
    end
end  

Note the . before the domain name. Using this method the cookies will be sent to the main app (where the signup happens) regardless of where the first visit was.

How about CDN?

We also use AWS Cloudfront as a CDN for our main website. This speeds up requests and reduces load on our servers. We use custom origin servers for our Cloudfront but the default settings is not going to work with the solution above.

This is because Cloudfront CDN by default ignores query strings and doesn't forward cookies to the origin server. Solving this is simple!

Login to your AWS Cloudfront dashboard and select the Cloudfront distribution. Under Behaviors, you can select edit and change these two settings:

Forward Query Strings to yes and Forward Cookies to all

Done!

Try Cloud 66 for Free, No credit card required