Today I want to talk about tracking organic ranking in Google Analytics. Previously, we were able to determine the page from which a Google organic click was coming from (detailed on the Distilled blog by Will Critchlow). This was nice because we could append this to the end of our keywords in Google Analytics for some interesting data (André Scholten's post at Yoast.com has a step by step) as seen below.
Image courtesy of Yoast.com
This solution provides limited utility, and if you're like me, you implemented it, maybe checked it out once in a while, but never really turned this into actionable or otherwise meaningful data. I'm going to detail how rank tracking in Google Analytics can be made a lot more useful thanks to custom variables and a change in Google's referring URLs. But first...
Some History
When Google began testing an AJAX search interface in early 2009 there was a flurry of concern that it could mean the end of traditional rank tracking, web analytics packages, and I'm sure someone said SEO was dead, too. The concern wasn't without merit; Google was serving results in AJAX with the URL pattern as https://www.google.com/#q=keyword, and most analytics packages ignored the hash and everything after.
Fast forward to September 8th, when Google introduced Google Instant. The AJAX SERP usage had been steadily increasing over time, but shot up in usage when Instant was rolled out. Fortunately for Omniture, WebTrends, and other third party analytics packages, Google worked out a way to pass the referrer information from the SERPs, rank tracking still works, and I'm still working as an SEO in a living industry.
As it turns out, Google includes even more information in the AJAX SERPs than they previously did, including one really interesting parameter: "cd=". The cd= parameter contains the exact ranking position of the search listing, which makes for some really awesome possibilities, especially when paired with Google Analytics' custom variables.
Why Custom Variables?
Custom variables are a bit of an enigma to even advanced Analytics users. I'll admit that I never really made much use of them in the past. You'll often see examples where custom variables are used to track logged in vs. unlogged in users, which is definitely a great use. Rob Ousbey's 6 cool things YOU can do with custom variables is a good set of examples to get your feet wet.
In André Scholten's example above we're using Google Analytics user defined value, isn't that just as good a custom variable? Well, the difference depends on how you intend on using your data. With custom variables, you're granted much more flexibility within Google Analytics for slicing and dicing data. For instance, through the use of either custom reporting or advanced segments with custom variables, I can pretty easily track how much revenue a keyword has brought in when ranked in the 2nd position, as opposed to the 4th. While this may be possible with the user defined variable, it would require quite a bit of work after an excel data dump.
Now, let's get to business:
The How
Getting this properly set up was remarkably easy for me, and I have so very little programming knowledge, so I would imagine most wouldn't have much issue. I used PHP, as I was working with a WordPress site, but I'm sure you crazy hackers can do the same in most any language.
Update: See Joost and André Scholten's comments below for a JavaScript method of passing the cd= value
Step One - Extract cd= Value from Referrer String
I used this snippet to do this.
<?php preg_match("/cd\=(\d+)/",$_SERVER['HTTP_REFERER'], $matches); $str = $matches[0]; preg_match("/(\d+)/",$str,$matches); $rank = $matches[0] ?>
Please don't make fun of my hacky coding
This assigns the cd= value to the $rank variable. We'll reference this in...
Step 2 - Call cd= Value in our Google Analytics snippet
Now, we want to insert the custom variable call between the setAccount and trackPageview lines in our Analytics snippet (shown below using the asynchronous code):
var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-XXXXXX-X']); _gaq.push(['_setCustomVar',1,'Google_Ranking','$rank',2]); _gaq.push(['_trackPageview']);"
We've set the custom variable slot to 1, and the scope to the session-level (the last argument, set as 2). If you are already making use of custom variables, be sure to not overwrite a previously occupied slot. For more information on how the custom variable is formatted, see Google's help page on the topic.
Step 3 - Create an IF Statement so the CustomVar isn't Called Every Time
We only want to include this line when we have a cd= value, otherwise every new click will overwrite the last value. To do this, I used the following IF statement, again coded in PHP. This is the final step, and the complete Google Analytics snippet:
<?php if ($rank != '' ) { echo "<script type=\"text/javascript\">\n var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-XXXXXX-X']); _gaq.push(['_setCustomVar',1,'Google_Ranking','$rank',2]); _gaq.push(['_trackPageview']);"; echo "\n"; } else { echo "<script type=\"text/javascript\">\n var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-XXXXXX-X']); _gaq.push(['_trackPageview']);"; } echo "\n"; ?> (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); </script>
Here we're checking if $rank has a value. If it does, we'll include the custom variable call with that $rank value, if not, we'll print the Google Analytics code as normal. Also included in the above are some line breaks (\n), so that the code formats correctly.
The Most Important Part - Analyzing Our Data
What's the point of going through all this effort if it doesn't provide you with any analytical insight? None, of course. But this rank tracking solution has some added benefits over the traditional rank tracking software that may be really useful to some SEOs. These include:
Rankings by City, Region, Country
Traditional rank tracking software suffers in that its ranking results are dependent on the location of the servers. With custom variable rank tracking and a little spreadsheet pivot table magic it's pretty easy to get your site's rank for any location.
Historical, Definite, Data
Once this is properly set up you've got access to definite rankings within your Analytics data from that point on. So as holiday season 2011 rolls around, its easy enough to review where your site ranked during the 2010 holidays, helping to set budgets, goals, and expectations.
Bounce Rate/eCommerce Data/etc. by Rank
Whatever your KPI, you can compare it against search ranking. Reporting the ROI of link building efforts or on site optimization becomes much easier when you've got rankings included in your dataset.
Some of the quick ideas I had around this include:
- Average rank over time for top 50 keywords
- Average rank over time for 4+ word keyphrases
- Bounce rate for 2nd+ page clicks
- Revenue % increase for Keyword X when ranking increases from 2 to 1
I should note that getting averages is a lot easier in Excel with a pivot table.
Creating Custom Reports and Advanced Segments
Custom variables aren't included in the default reports for Google Analytics, so unless you do all your work in Excel, you'll probably want to create some custom reports or advanced segmentation to work with the data directly in Analytics.
Advanced segmentation is great for this data. Below is the function one would use to track rankings between 11 and 15, which might be strong candidates for on-page optimization that could provide the boost onto the first page:
You can apply this particular advanced segment with this link.
The Downsides
The most obvious downside is that you're only receiving a ranking when a listing is being clicked on, so for very small sites there may be limited utility. Ranking data will be spotty past the 2nd page, as well.
Additionally, the AJAX SERPs are not being served to all users in all locations. Small sample size warning here, but I'm seeing about 40% of organic Google traffic coming from the AJAX SERPs (done through a simple calculation of visits with our custom variable divided by total Google organic visits over the same time period). Michael Whitaker is seeing this number over 50% in his data. This number is likely going to increase as Instant is rolled out further.
The #-pack local listings can really throw things off, too. If a particular query gets one of these to start the SERP, the cd= continues after:
Lastly, there does exist the possibility that Google discontinues its use of the cd= variable for whatever reason.
Go Analyze
I hope some of you can make some good use out of this functionality. I've only had it installed on my sites for a short time, but I've definitely found it interesting to play around with. If you don't already have Excellent Analytics installed in your Excel I would highly recommend doing so, even if you don't implement this tracking, and especially if you do.
I'd like to thank Michael Whitaker of Monitus for his help. He's been installing this setup for his clients for a bit now. Monitus offers proper eCommerce Google Analytics installation for Yahoo! stores, which is surprisingly difficult without Monitus.
If you've got any other ideas for working with this data, sound off in the comments or let me know on Twitter @MikeCP. Personally, I'm really excited to have this data rolling in and the possibilities are nearly endless. I'll be sure to report any interesting ways to manipulate the data in future blog posts. Cheers!
Since the SEOmoz blog doesn't seem to support pingback or trackback, I'll blatantly throw the URL to my follow up post in here:
https://yoast.com/track-seo-rankings-with-google-analytics/
:)
Great,
Looking forward to you bringing this tool to the masses! JavaScript version is obviously a must.
Cool thanks! Let us know when the plugin is updated.
Thanks for the speedy addition. Can't wait to try it out. I think it will be a really great way to monitor things.
And to the OP, awesome post. I love advanced Analytics tricks like this.
Mike
Best and most useful SEO post I've read for a while. The code snippets just helped "the penny drop" - thank you.
This would make a pretty awesome addition to Joost De Valks Analytics for WP plugin - https://wordpress.org/extend/plugins/google-analytics-for-wordpress/...
Richard
Joost's updated his blog with a JavaScript tracking snippet to do all of this for you without falling victim to caching enabled sites (eg: W3 Total Cache on WP)
https://yoast.com/track-seo-rankings-with-google-analytics/
Given that the analytics for WP is hash tag tracking enabled too - this makes for a pretty formidable analytics set-up out of the box - no PHP hacks required.
Absolutely. I actually had W3 Total Cache installed on my test site, which was giving me fits. In the end I used <!--mclude--> to disable caching on that code, which worked fine, but Joost's solution would probably work even better.
When he puts this functionality in his Google Analytics for WordPress plugin, I'll definitely update the post.
Just noticed. While creating advanced segment set the custom variable value to 'Google_Rank' and not 'Google_Ranking' as you have created the 'Google_Rank' custom variable in your analytics code. Otherwise you won't get any data.
Thanks! I fixed it in the code.
Would it be possible to do this via JavaScript? My JavaScript skills aren't too good, but this would make it far easier for most CMS' to include JS code in the head, also making this platform independent?
Any JavaScript devs out there that can advise on this?
Put this between the setAccount en trackPageview line:
var regex = new RegExp("cd=([0-9]+)");
var match = regex.exec(document.referrer);
if (match) { _gaq.push(['_setCustomVar',1,'Google_Rank',match[1],2]); }
It will set the setVar only when there's a cd parameter in the referring URI.
Thanks Andre, will give it a go on a test site and see how I get on!
Hey André, of course I see your response AFTER I've spent the couple of minutes to figure out my own solution :)
Joost, I thought you were the one who originally posted this solution on your blog :)
Here is the script in a pure javascript form:
(please excuse the excess line breaks, this was due to the comment box editor)
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXX-X']);
if(document.referrer.indexOf('cd=')>0)
{
var rank = document.referrer.split('cd=',2);
rank = rank[1].split('&',2);
_gaq.push(['_setCustomVar',1,'Google_Ranking',rank[0],2]);
}
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
Thanks Sean! Good stuff.
Hi SEOSEAN,
Thanks for this wonderful code. I hve tried using this on my website. But when I see the analytics reports I was not able to identify the keywords with ranking posisitions. I have used the code which you've given here. Also i have used my analytics account perfectly.
Please advice
Hi,
Here is a more condensed version of your custom variable script in PHP. I've used some PHP functions avaliable in PHP4 and up which use less code to do the same thing. Plus I condensed the rest of your code to... again use less code to do the same thing.
(Please excuse extra line breaks, there were due to the comment box editor)
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXX-X']);
<?php
parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY),$refer);
if($refer['cd']) { echo "_gaq.push(['_setCustomVar',1,'Google_Ranking','".$refer['cd']."',2])\n"; }
?>
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
Is it possible to just do the analysis in Google Analytics rather than having to set a custom variable with php?
I don't think so... custom variables needo to change... if they need to change automaticly - they need to be programmed
You can get something similar (but a bit more more manual work) if you set up an account filter (analytics settings -> filter manager) in analytics that just grabs the whole URL, something along the lines of what is described in the Distilled article but with a less restrictive filter - i.e. (.*) - so that you simply grab and store the whole URL.
Then when you are actually looking at traffic from Google Organic use the 'advanced filter' link at the foot of the table to create a filter that will only show URL's containing 'cd=', or more specific such as 'cd=1'.
This is true. Just be sure to set up a separate profile with these filters. This can be done in like 2 minutes as opposed to adding all of that code. Also, Google does not currently put the cd= parameter on all links, from what I have noticed its about 15% so be weary of the numbers coming in, and that they are only a sample of organic traffic.
Is there an easy way to track full referrer path through custom variables?
Excellent post, excellent idea. Thanks for sharing. I've noticed that referrals from at least Safari's built in Google search box doesn't trigger Google Instant results so the cd var isn't present: /search?client=safari&rls=en&q=walkjogrun&ie=UTF-8&oe=UTF-
For anyone using ColdFusion you can use this snippet to grab the rank or return the empty string when it's not present:
\<cfset rankVar=rereplace(cgi.http_referer,".*?google.com.*?cd\=(\d+).*?|.*?","\1","ALL") /\>
so the last part to conditionally send it to GA (using old _setCustomVar) becomes:
pageTracker._setCustomVar(1,'Google Ranking',#rankVar#,2);
Note that I added google.com as part of the regex to make sure we only gather cd= params from Google.
Great blog post!
I have been using this setup for some time now and I really like how it is possible to track keyword rankings in GA. However, as I see it the drawback (for us lazy people) is that I am unable to create a report which at a glance shows me how my keywords are performing.
This led me to develop an alternative approach where you can create a report which at a glance shows you your keywords and how they are ranking - and the cool thing is that it makes it so easy to receive alerts when your SERP drops for important keywords.
You can read about this alternative approach on my blog post on how to create the ultimate SEO report using Google Analytics.
Really happy to come across this post. I've not made use of the custom variables before, but this is definitely something I want to implement now. I tried a different method I saw online for our website: https://www.vormetric.com, but the information I got was inaccurate, so I'm going to give this a try to see if I can get to see the Google Ranking I need.
By the way, anyone tried the filter suggested by blind5yerasold, I would like to decide which I should implement for our site www.vormetric.com
Very good post.For custom report automation on Google Analytics data, I use an application that it's saving us a lot of time and money. It's is really worth checking it out:
www.reportingsuite.com
I've started implementing this now. I can't wait for the results.
Thanks great post.
But any suggestions on what I would do if I have a big list of keywords that I want to keep track of? Is there a way of automating this for lots of keywords?
Thanks in advance for your help!
Michael
This is definitely a hot post. I would love it if my rankings were actually IN GA and not in another external tool. I'm not as adapt at PHP though so I may have to spend some time digesting this one. Thanks for the tips!
Really useful post. I've not made use of the custom variables before, but this is definitely something I want to implement on now. I just hope that Google do not decide to discontinue the use of the cd= variable. It’s a shame that something like this was not made available before Google Instant as it would have been nice to see the comparison in rankings and traffic between the 1st and 2nd half of the top 10 results.
This is great. And your code doesn't look hacky at all.
Thanks for this piece. I have always wondered why such a glaring omission existed in the tools available on Analytics - given it is Google's own intervention.
Really useful post. I've not made use of the custom variables before, but this is definitely something I want to implement now. I just hope that Google do not decide to discontinue the use of the cd= variable. It’s a shame that something like this was not made available before Google Instant as it would have been nice to see the comparison in rankings and the difference in traffic received between the 1st and 2nd half of the top 10 results due to Google’s update.
Great addition to the post I wrote on Yoast's site.
Why did you choose for putting the customvar on the session and not on the visitor? In the last case you could track return visitors also. But than you also need a script to clear the customvar when people return through another source.
That's right Andre.
If the scope is set to visitor, it will overwrite every time there's a new referral for that visitor. Actually, with the above code, it will only really overwrite when the regex finds a cd= value. So in the end it would just only track the most recent keyword the visitor has come into the site on.
I'm sure it could be expanded to track repeat visitors and all sorts of other cool stuff. All depends on what you're looking to track.
nice post :)
I used to track some of these things with Google Webmasters Tools... takes a bit more time - but the right combination of data from GWT and GA (and Google Keyword Tool) can bring some nice feedback as well
this is a great way to find keywords that do not have to many searches, that we are not strong at, but keywords that can turn into high converting ones
A great post. I'll have to hand this to one over to my coder..
Mike your post looks awesome but too bad it is not for me. I am either dated or seo from the future. When no two people see the same ranking then what's the point of comparing your KPIs against search rankings and whats the point of going through all this pain of setting up this super advanced analytics set up. I stopped using rankings as a perfomance metric years ago. Rankings don't equal either targeted traffic or conversions/sales. ROI of link building efforts is measured through traffic volume, conversions and sales and not through rankings. IMO the best tool to measure your site rankings is Google Webmaster Tool. Not only you can see the average position of your keywords but also the impressions, clicks and CTR.
I think there are a several interesting and insightful things you can do with this data. 1) It allows you to analyze how behavior and activity correlates to certain positions. You might see bounce rate and goal conversions performing much worse in the 5th ranking compared to the top 3. If this is going on for a select group of keywords, it makes for a very strong case for focusing your effort in moving these phrases higher.
Also, as you mentioned, different people see different rankings. So if you want a better understanding of the bell curve (something a ranking tracker or manual search won't tell you), this method is ideal. You may see your site show up number 1 in a rank tracker or when you search by yourself, but then see in Google Analytics that over half your traffic is actually coming in from the 2nd or 3rd position. This means you have more work to do than you thought.
Hi Caleone!I fail to understand how you will establish any correlation between searcher's behaviour, bounce rate, conversions and ranking position when their is no fixed ranking in the first place. Rankings fluctuates all the time. People get geo targeted, personalized results. For one person you may be at no. 5 and for another you may be at 10 or on the second page. So what you are going to adjust and what analytical insight you will get.
What I'm suggesting is segmenting traffic based on ranking conditions. So, for example: display the KPIs of people who visited my site who clicked on keyphrase-x when it was in the 1st position (or 2nd position, or 3rd position). You MAY see a difference in behavior based on where your site displayed on the SERP. So now you know a higher ranking doesn't just bring you more traffic, but maybe a higher conversion rate or a lower bounce rate. You may find there's absolutely no impact at all, but the point is we have a new condition we didn't previously have.
AJ made a good point that this data can give insight into the rankings other people see. While Google Webmaster Tools gives this information as well, it can't tell us how the rankings relate to outcomes. Webmaster Tools only goes as far to tell us what happens on the SERP. Analytics takes it a step further by telling us how that translates into site behavior.
I am still skeptical but then there is no harm in trying it out. Lets see what we can get through this reporting. Thanks for pushing me :) Here is thumbs up to Mike for coming up with this new reporting.
Well, I'm not sure anyone is advocating for using rank (alone) as a way to measure performance. But it's rather easy to track rank in Google Analytics, using this or establishing a filter. (https://www.blindfiveyearold.com/track-keyword-rank-in-google-analytics)
The data can actually prove quite useful once you have it, and quickly demonstrates that the majority of people do see the same results. SERPs aren't snowflakes yet.
I know the volume by rank, conversion by rank, bounce rate by rank - you name it, it can be sliced and diced. GWT is fantastic but only provides a liimited set of data. And that's where the real benefit comes in, I can trend by rank. This is particularly important for very large sites (~1,000,000 pages) where a movement in the aggregate rank can have large implications.
In addition, you can get insight into how Google is testing and how things like Google Instant are impacting search behavior. (My initial read is that there is some change which will make SEO even more vital.)
Have you used 'search queries' report in Google webmaster tools? It shows different position in search results for a single keyword and different impressions, clicks and CTR for each position. If you can come up with something like this in Google Analytics, i will truly appreciate. However i don't think you will be able to establish any correlation as explained in the comment above.
No, you can't get impressions in Google Analytics and thus, you can't get CTR.
But you get a lot of other things in GA that you don't get in GWT. Conversion, Time Spent, Bounce Rate etc.
I wouldn't want to optimize for CTR in isolation without knowing how that traffic performed.
Both GWT and GA rank reports are useful - particularly if you use them together to give yourself a full picture.
This is an interesting way to track rank in Google Analytics but why not simply use a filter and output to User Defined.
https://www.blindfiveyearold.com/track-keyword-rank-in-google-analytics
From there you can do a number of different reports, particularly using Advanced Segements and Custom Reports.