Where do your customers come from? Building a simple solution for marketing attribution
There are many different channels you can use to acquire new customers. If you want to understand which ones work for your business, you have to start from understanding where your customers come from.
Let’s start with a definition of a marketing channel: simply put it is some means of finding customers. It can be all sorts of things, your Twitter account, a blog, or an ad in a local newspaper.
A couple of weeks ago we started to run tests to validate different marketing channels. We wanted to have an understanding of how well each of those channels is doing, what’s bringing us a lot of customers, and what’s useless.
What do I need to track?
For each new account created in Probe, we want to know how this account found us. We decided to go with a simple text label indicating where the customer came from, for example, email_campaign_2020_09
or blog
. We already have an Accounts table in our database to store account-related information. We can thus simply extend it by adding a new column named marketing_ref
identifying the marketing channel the customer originated from.
How to track it?
There are 3 main steps we have to do:
- Adding
marketing_ref
to the URL - Saving the
marketing_ref
value for the web page visitor - Passing the
marketing_ref
value to the backend when a visitor creates a new trial account
Adding marketing_ref
to the URL
When we post a link to our web page we want to add a marketing_ref
parameter with a text label that will help us identify channels later on. For example – when creating Google Ads campaigns we would enter https://getprobe.io?marketing_ref=google_ads
. This google_ads
label tells us that a visitor came from clicking on our Ad.
Saving marketing_ref
value for the web page visitor
Once a new visitor comes to our web page, we have to parse the URL, fetch the value of the marketing_ref
parameter then store it. We have added a piece of Javascript code to our landing page that applies this logic to store the marketing_ref
using localStorage
.
Parsing the URL and returning the value of marketing_ref
parameter:
# this code is using https://www.npmjs.com/package/query-string
function getMarketingRef() {
if (window.location.search) {
return queryString.parse(window.location.search).marketing_ref
} else {
return null
}
}
Storing marketing_ref
in localStorage
. This snippet of code will be run on onDocumentReady
event.
const marketingRef = getMarketingRef()
if (marketingRef) {
localStorage.setItem(‘marketing_ref’, getMarketingRef())
}
We decided not to overwrite the existing value if no marketing_ref
is given. It is an important choice because it determines what happens when the same person visits your website for the second time with a different marketing_ref
. Do we want to attribute the signup to the first source, or the latter? We decided that the first one wins.
There could be other solutions like remembering a list of sources that you keep, but that was too complicated for our case.
Passing the marketing_ref
value to backend when a visitor creates a new trial account
When a trial is requested, marketing_ref
value has to be passed to the backend. The backend creates a new trial account and, along with it, stores the marketing_ref
value. The choice of how to associate the marketing_ref value to the account is more subtle as it depends on your database structure. In our case, we have a table called accounts and we simply store the marketing reference in it.
An important assumption here is that we have a one-to-one relationship between a channel and a customer. There is no “blending” of channels – it's either channel A or channel B that was responsible for bringing customers, not a mix.
Here is a snippet of JavaScript code from our web page that creates a new trial account.
# this code is using https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
fetch(‘https://getprobe.io/signup’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’
},
body: JSON.stringify({
email: signupEmail,
passwords: password,
marketing_ref: localStorage.getItem(‘marketingRef’)
})
})
When creating the customer in our backend system we expect the parameter marketing_ref
passed from the landing page. Here is a snippet of Ruby code from our backend responsible for creating a new trial account.
def create
Account.create!(email: params[:email], password: params[:password], marketing_ref: params[:marketing_ref])
render json: {‘ok’: true}
end
Summary
Once you implement these 3 steps above you have built a simple marketing attribution model. You will have information about where your customers come from. The next step would be to calculate how much MRR each of these channels brings you. Based on that you can start making informed decisions on where to invest your marketing efforts to get the most out of it.
You might wonder what possible marketing channels are out there? This is a rather broad topic but luckily there are a few great books about it. One we like is Traction by DuckDuckGo founder Gabriel Weinberg. It’s a must-read to educate yourself not only on the available marketing channels and how you can use them but also on the framework you can implement to test many of them.