How can I set a (Google Analytics) Content Experiment (A/B test) with a singular URL? - google-analytics

I want to test whether a variant of my current homepage will perform better (reach a certain goal defined on GA), but I'm struggling to find a good solution.
Let's say the current version (Original) has sections A, B, C in that order. The other version (Variant), though, has sections in the order B, C, A. Note: the top navigation menu (linking to each section's anchor) must reflect this change.
I first considered Client-Side Experiments, which I have done in the past, but I'm worried those wouldn't look good when rendering the site: depending on loading speed, a Variant user would first see section A, and then they would see section A vanish (into the bottom of the page), while they could also notice the menu being changed.
I then considered the regular Experiment mode on Analytics, which asks me to determine two URLs to compare: the Original is my root path (e.g. http://mywebsite.xyz/) and the Variant would be something like http://mywebsite.xyz/home. But I can't orientate half of my users to this different URL - I want to test people who reach my homepage from wherever they may come.
I tried something through the Google Cloud App Engine: publishing two versions of my application, and splitting traffic 50/50 between both (cookie-based). When visiting the root path, one renders the Original, while the other renders the Variant version. Great. It works! But now Google Analytics has no idea which version it's tracking...
What I did: when the page first loads, I send an event with the version identifier as parameter, such as
ga('send', 'event', 'AB_Test', 'A');
// or
ga('send', 'event', 'AB_Test', 'B');
I suppose these would help me check the Events Flow and determine which version reaches more Event goals, but it's still not linked to an Experiment or its features.
Is there any better way to implement this? Am I missing something? It feels too complicated to do something that both the Cloud App Engine and the Analytics should help me achieve. (Thanks for reading, I know it's a huge text)

When I run this type of experiment, I typically try to leverage the API to determine the variation in the backend and then render the template appropriately.
For your current workaround, rather than sending events, I'd recommend instantiating the test on each server and manually setting the variant for each. See code below:
<!-- App 1 / Original -->
<script type="text/javascript" src="//www.google-analytics.com/cx/api.js?experiment=<EXPERIMENT ID>"></script>
<script type="text/javascript">
(function () {
cxApi.setChosenVariation(0);
}());
</script>
<!-- App 2 / Variant -->
<script type="text/javascript" src="//www.google-analytics.com/cx/api.js?experiment=<EXPERIMENT ID>"></script>
<script type="text/javascript">
(function () {
cxApi.setChosenVariation(1);
}());
</script>

Related

The Google Optimize snippet for the container with ID GTM-... is not correctly installed on this page

I'm trying to use Google Optimise with Analytics installed by gtag.js and am getting errors in some parts of the Optimise UI but not others.
Here's what I've done:
Installed Google Analytics following the instructions "Set up Analytics tracking with gtag.js" (and confirmed it's working by using the Real-Time Preview).
Set up Google Analytics following the instructions "Deploy Optimize using Global Site Tag (gtag.js)"
Added the page-hiding snippet.
When I set up an experiment using the Chrome extension, Optimise appears to be running as Google expect - notice that there's no number shown by the exclamation mark icon in the screenshot below (there is if I remove the Optimise code), and clicking it says "no issues detected". (Also, the chrome extension's icon doesn't have any error symbol.)
However, if I then preview either the original or the variant (clicking the "screen" icon in Optimise), I get a javascript alert which says:
The Google Optimize snippet for the container with ID GTM-abcdef is not correctly installed on this page. To preview variants for this experiment, make sure the Google Optimize snippet is installed on any pages you want to test.
(I've replaced my actual container ID by "abcdef" in the above.)
And the Chrome extension icon also shows an error and a similar message when clicked (I've blacked out the experiment name here):
Here's my HTML <head> section (with IDs redacted):
I've compared the script from this with the example in "Deploy Optimize using Global Site Tag (gtag.js)" and they appear identical except that my code contains real IDs:
<head>
<meta charset="UTF-8">
<!-- Page hiding snippet (recommended) -->
<style>.async-hide { opacity: 0 !important} </style>
<script>(function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date;
h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};
(a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c;
})(window,document.documentElement,'async-hide','dataLayer',4000,
{'GTM-zyxzyx':true});</script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-abcdef"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-abcdef', { 'optimize_id': 'GTM-zyxzyx'});
</script>
<title></title>
</head>
I've tried this against a site running locally (on Flask's webserver, port 5000) and against a site deployed onto Heroku, and behaviour is the same in both instances.
I've also tried removing the page-hiding snippet code, but that didn't help.
I've also tried actually running the experiment but always saw the original variant even when setting the alternative one to have 100% traffic, so it's not working there. (I only tried this against local site, haven't tried against the Heroku instance.)
It's worth noting that there's this line in the GA code:
function gtag(){dataLayer.push(arguments);}
I've seen it online in that form and with the semi-colon at the end:
function gtag(){dataLayer.push(arguments)};
I've tried both without any effect.
What am I doing wrong here?
I don't know if this is correct, but should the hiding snippet be using the ID UA-abcdef?
If you’re using Google Tag Manager to deploy Optimize, populate the
page-hiding snippet with your Tag Manager container ID, not your
Optimize container ID. Learn more about using Optimize with a
tag-management system (from here: https://support.google.com/optimize/answer/7100284?hl=en)
I'm not sure whether deploying the code this way is classed as deploying Optimize with Google Tag Manager though. What do others think?

DOXFX using Application Insights end-user user analytics

How can you add Application insights end-user user analytics to DocFx to track the usage of every documentation page?
The Application Insights documentation states you need to insert the JavaScript snippet listed below immediately before the closing tag, but I'm not sure if this is possible in DocFx or the best way to accomplish.
Would you need a postprocessor, or could you use a custom template?
<!--
To collect end-user usage analytics about your application,
insert the following script into each page you want to track.
Place this code immediately before the closing </head> tag,
and before any other scripts. Your first data will appear
automatically in just a few seconds.
-->
<script type="text/javascript">
var appInsights=window.appInsights||function(config){
function i(config){t[config]=function(){var
i=arguments;t.queue.push(function(){t[config].apply(t,i)})}}var t={config:config},u=document,e=window,o="script",s="AuthenticatedUserContext",h="start",c="stop",l="Track",a=l+"Event",v=l+"Page",y=u.createElement(o),r,f;y.src=config.url||"https://az416426.vo.msecnd.net/scripts/a/ai.0.js";u.getElementsByTagName(o)[0].parentNode.appendChild(y);try{t.cookie=u.cookie}catch(p){}for(t.queue=[],t.version="1.0",r=["Event","Exception","Metric","PageView","Trace","Dependency"];r.length;)i("track"+r.pop());return i("set"+s),i("clear"+s),i(h+a),i(c+a),i(h+v),i(c+v),i("flush"),config.disableExceptionTracking||(r="onerror",i("_"+r),f=e[r],e[r]=function(config,i,u,e,o){var s=f&&f(config,i,u,e,o);return s!==!0&&t["_"+r](config,i,u,e,o),s}),t
}({
instrumentationKey:"###-###-###-##"
});
window.appInsights=appInsights;
appInsights.trackPageView();
</script>
No PostProcessor is needed. You can achieve this by customizing the template. More information can be found in official tutorial or this question. You can add your code in partials/head.tmpl.partial. It will affect all the generated page.

Efficiently reusing (poorly designed) JSON template for additional sites?

My supervisor just handed me a pile of JSON files from a freelancer which we are going to use to make multiple (similar) websites. Lucky me, I'll get to be the one updating the content and css for the different versions.
This is my first time working with JSON, so while I can't be sure that this is a poorly designed template, the fact that the css is very messy (in order to change the color of buttons throughout the site from yellow to orange, at least 15 different classes need to be adjusted, which seems to me to defeat the whole purpose of css...) doesn't give me hope.
I've brute-forced my way through the first two different sites, but since it looks like we'll be doing a lot more of them, I'm looking for ways to streamline the process (in particular making sure to change the content in all the places the content needs changing, which is a lot of files, with different content for different versions).
I'm personally old-school enough to like awk (well, that, and it's what I'm most used to programming in), so my backup plan is to just set up an awk/batch script or two which will take in a "these are the bits of info that go in these specific places" file and update all the relevant files. However, I'm sure there's a better way to do this, which is why I'm turning to y'all.
Is there anything that already exists for streamlining processes like these? Or a coding system/language that's well-suited to this project? A GUI which I can connect to bits of text that need changing?
Ideally, I'd like to set up something that even a monkey (or a non-caffeinated me) could use as often as needed. I'm already going to have to dive into the source code to clean it up (because, gasp, we might need to be able to have more than 5 people on the "our team" page, for example - without bad css/html workarounds), so making other tweaks that'll help with the content update process can happen en route.
I have recently used underscore to render templates from JSON. this is a front end tool, but you could automate it with some backend tools (a simple cURL or file_get_content in php will do).
Here is a link to a tutorial
your template will be a JavaScript template in your html file:
<div id="rendered"></div>
<script type="text/template" class="template">
<%- rc.listTitle %>
</script>
and in your JavaScript code you load:
<script type="text/javascript">
// When rending an underscore template, we want top-level
// variables to be referenced as part of an object. For
// technical reasons (scope-chain search), this speeds up
// rendering; however, more importantly, this also allows our
// templates to look / feel more like our server-side
// templates that use the rc (Request Context / Colletion) in
// order to render their markup.
_.templateSettings.variable = "rc";
// Grab the HTML out of our template tag and pre-compile it.
var template = _.template(
$( "script.template" ).html()
);
// Define our render data (to be put into the "rc" variable).
var templateData = {
listTitle: "Olympic Volleyball Players",
};
// Render the underscore template and inject it after the div rendered
// in our current DOM.
$( "#rendered" ).after(
template( templateData )
);
</script>

Upgrading to new asynchrous Google Analytics code - should you do it?

I had read somewhere and have now forgotten that upgrading to the new asynchronous code will not enable one to track actual clicks for downloading items when user stays on the same page and that for tracking that you need to use the old version of GA code.
My question is, is that still the case and does anyone have any other reasons for not upgrading to use the newer asynchronous tracking?
thanks
Hmm...are you sure the "old" version of GA automatically tracked downloads? AFAIK GA never automatically tracked download links, that you always had to attach GA code (like a _trackEvent call) to your links yourself. But in any case, it's pretty easy to do it yourself, so it's really not a big deal. Plus, you get lots of benefits upgrading, and one day it may not even be an option to stick with the old version...
If you have jQuery you can for example do this:
// file types you want to consider a download
var downloadFileTypes = ['pdf','doc','docx','mp4'];
$(document).ready(function() {
$('a').filter(function() {
var ext = $(this).attr('href').split('.').pop().toLowerCase();
return ( $.inArray(ext, downloadFileTypes )>-1 );
})
.click(function() {
_gaq.push(['_trackEvent', 'Downloads', $(this).attr('href')]);
});
});
If you do not have a framework like jQuery, you can still do this easy enough with .getElementsByTagName() and using regular loops and conditions instead of the jQuery conveniences like .filter and .inArray
edit: Some things to note about that example:
the jQuery code was an example to hook the GA code to standard links pointing to the file types you specify in downloadFiletypes. It will only apply to links that exist at the time the code is executed. If you have links that may be dynamically generated on the page later, consider looking into .on() instead of .click()
you will need to make tweaks to matching links you want to consider downloads if they do not point to regular files with extensions. For instance, some websites have a controller script that expects a parameter with an ID and it dynamically serves up a pdf or whatever..if your files are like this, you will have to alter the logic to look for that instead.

Going "Stateless" and loading scripts dynamically

What I want to know is if I am approaching this from the right angle.
I have an asp.net app I am building. I am using a Masterpage for the overall look of the app (below you can see the code).
I'd like to have the menu system use a dynamic load like jQuery's .load() function to load the content. That is fine and I have that down. The .load() function uses innerHTML to pump that content into the page. This is a problem if on that page you want to load module specific scripts and styles.
My question is, in an environment such as this, how do you guys load your scripts for these modules? Should I load every script on the initial load of the app? This app will not ever be "that big" however I want to make sure I do it right just in case.
MasterSheet
<div id="primaryNavigation">
<ul>
<li class="current">Main</li>
<li>Some Overview</li>
<li>Reporting</li>
<li>More Reporting</li>
<li>About</li>
</ul>
</div>
<div id="mainContentContainer">
<asp:ContentPlaceHolder ID="cphBody" runat="server" />
</div>
Example Module inside of the Content tag
<div id="container">
Inside a page
<script id="scriptToLoad" type="text/javascript">
alert('Something');
head.ready(function () { console.log('please print'); });
</script>
</div>
<div id="includeScripts">
../Files/Javascript/SomeModuleSpecificJs.js
../Files/Javascript/SomeModuleSpecificJs1.js
</div>
My idea was to set up a div in each module that would have the id of "includeScripts" and load those from a method within the mastersheet like this. This method works (needs some tweeking obviously) however if the user keeps clicking on modules eventually every file will be loaded. If thats the case I might as well load them all on the mastersheet.
JS to be ran when the MasterPage is loaded
$navigation = $("#primaryNavigation").delegate('ul li a', 'click', function () {
$('#primaryNavigation').find('li').removeClass('current');
$(this).parent().addClass('current');
$('#mainContentContainer').load($(this).attr('href') + ' #container');
// Obviously this would overwrite the content from the container, this is merely proof of concept
$('#mainContentContainer').load($(this).attr('href') + ' #includeScripts');
var jsArray = $('#includeScripts').text().trim().split("\n");
$.each(jsArray, function (index, value) {
$.getScript(value);
});
return false;
});
I don't know about .load(), but JQuery's .html(), .append(), and a few other related functions will automatically run any script tags that they find in the given HTML. If load() doesn't do that for you, it should be easy enough to use $.get(..., function(){$('#myElement').html();}); instead. You could even write your own extension specifically for this purpose.
Style sheets may be a different story. I've typically just used a single style sheet per page.
Edit
I just spent some more time reading your question, and I realized that I didn't answer it fully.
Should I load every script on the initial load of the app?
It really depends on the size of your scripts and the way you expect users to interact with your system. In this seminar, the people who made Google Wave talk about how they addressed this issue. At one point the speaker says, "Perceived latency is the most important thing to optimize for." The problem was, in an early version, their javascript file (optimized and compiled by GWT) was a few megabytes in size. People with a slow connection (a cell phone browser, e.g.) would have to wait a long time for all this code to download before they could see what was in their Inbox. Their solution was to create "split points" in their code so that it could be loaded in chunks. The code necessary for displaying the Inbox could be loaded first, whereas the Contacts panel could wait until the user clicks "Contacts."
But you can take this too far. The other speaker in this video says the time spent in loading falls largely under one of two categories:
Fetching data you don't need, and
Too many HTTP requests
Each HTTP round-trip involves a certain amount of overhead, so it can be worthwhile to load some code you don't need yet in order to avoid having to make another round-trip in a few milliseconds when you realize you need it.
Since you say:
This app will not ever be "that big"
... I'm guessing that you'll probably fall mostly under the latter category (too many HTTP requests). The best thing to do in that case is:
Use a tool like Chirpy to consolidate all your javascript files into a single file (which can be automatically minified when not in Debug mode).
If your application has a login page that doesn't use all this javascript functionality, add a script tag for this javascript file at the bottom of the login page so that the user's browser will download the file behind the scenes while the user is busy entering their username and password. The master page for the rest of the site should simply include the script file once in a standard script tag.
Make sure your site's caching rules are set up properly so that user's browser will only request this file once.
Make sure your site is set to compress this javascript file since javascript (especially minified javascript) lends itself to gzip compression very nicely.
Once you've done this, you should find that there is no "perceived latency" from loading your javascript file.
If your application does eventually become "that big," you'll want to break your program down into modules like the Google Wave team did. But choose your modules based on how you expect the system to be used. If only a small handful of users is likely to use your admin interface, for example, you'll want to put all of your admin UI code into a separate module that "normal" users will never have to download.
When deciding where to draw the line, UI experts basically say one-fifth of a second is the point where the typical human's brain starts wondering, "Did that work?" If a user clicks a button and has to wait longer than that before they see something happen, you've reached the point of "perceived latency." Anything beyond that will become increasingly annoying to the user.

Resources