Quantcast
Channel: s_code.js – Web Analytics for Developers
Viewing all 46 articles
Browse latest View live

Basic Tracking

$
0
0
Most web analytics data is gathered within browsers using Javascript. There’s other ways, but we’ll get to that later.So how do you track a web page?

(Too) Minimal Code

The very minimum are 4 lines of code, like so:

<script type="text/javascript" src="/include/s_code.js"></script>
<script type="text/javascript">
s.t();
</script>

The first line loads the s_code.js file which contains three important pieces (we’ll go into that later).

For now, suffice to say that it defines the s.t() method which is called in the third line. The s.t() method is what actually triggers the tracking of the page.

The 4 lines above work, but they won’t produce good reports. One crucial bit is missing, the s.pageName variable.

Content in Adobe Analytics is identified not by the URL but by the s.pageName. If you’re not sending anything in that variable, the system will revert to using the URL, but your reports will look like this:

Can anybody tell me which page “site.com/?id=987654321″ refers to? Unlikely.

So let’s improve our code!

(Better) Minimal Code

Let’s add one line to turn it into something usable.

<script type="text/javascript" src="/include/s_code.js"></script>
<script type="text/javascript">
 s.pageName="Testpage";
 s.t();
</script>

So what do you put into the s.pageName variable on a given page?

The answer to that depends on your site, your marketers and possibly your CMS. In general, the name should follow the “three Cs”: context, concise, complete.

My suggestion would be to run it by the marketer. The ultimate test is to fake a report with a couple of names, show it to them and see whether based on the name they know whcih page you are talking about. If they do: good name!

What do you get?

With the minimal code you will get a bunch of built-in reports along with all the traffic metrics: Page Views, Visits, Visitors. You also get pathing reports like “Next Page Flow” and even geo segmentation if that’s enabled for the report suite.

This is the level of tracking that most people will easily understand: you can look at trends (did we have more or less traffic? From more or less Visits or Visitors?) and rank your pages (“Oh, the campaign landing page really took off this month! See, it passed the home page in popularity!”) as well as find out where your visitors went after the landing page.

Minimal Useful Code

I will come back to the subject traffic metrics at some point, let me just say for now that I think web analytics should go a lot further than Page Views. Minimal code will get you minimal results.

The next step is to track “micro conversions” on the site, i.e. activities done by the visitors which we (the marketer) deem important. That could be buying something, looking at a product, downloading a white paper, signing up for a newsletter or searching.

Most sites do not just exist in a void. They have a specific purpose. Micro conversions are like little steps on the way there and tracking them allows us to see how far visitors go down the path to conversion.

Adobe Analytics has space for up to 100 micro conversions in the s.events variable. The events are called “event1″ to “event100″. Your marketer (or an Adobe consultant) will define which one is which. They might give you a “Solution Design Reference” or “Tech Spec” document that includes the mappings.

So let’s look at an example.

Our site contains a blog and our marketing department wants to get a more detailed look at article consumption. The “Tech Spec” tells you that “event21″ should be “Blog Article Views”.

The code on the article about “Basic Tagging”, which is the 2nd blog article on the site, might look like this:

<script type="text/javascript" src="/include/s_code.js"></script>
<script type="text/javascript">
 s.pageName="Blog:b2:Basic Tagging";
 s.events="event1,event21";
 s.t();
</script>

We added two events here: event1 (“Page Views (custom)”) and event21 (“Blog Article Views”). The “Blog Article Views” metric is already a step forward because in a lot of cases it will be more relevant than “Page Views”.

We have also entered the world of conversion metrics and variables, which we’ll explain later.

For now, our marketers will be able to analyse their campaigns based on “Blog Article Views” rather then “Click-throughs”, which is a huge step.

What next?

We shall go into more advanced tracking in due time so let me just drop a couple of concepts here that I’ll explain later.

We can add “plugins” to the s_code.js file. Those plugins can capture data independently of page code (i.e. on every page on the site). Good examples would be: capture campaign tracking codes, visit number, time of day, days since last visit, marketing channel and much more.

Once we talked about SAINT and classifications, you’ll see how classifying some of the data can produce much better reports. We’ll essentially add meta data to our reports to make them ore readable or to aggregate data.

That’s it for now, really.

Apart from the s.pageName variable, everything so far can easily be done in the template if your CMS works with templates. That makes your job a lot easier


Filed under: Javascript, Page Code Tagged: javascript, s_code.js

Email Tracking

$
0
0

Your marketer sent an email yesterday night:

“I have a new email campaign going out and want to track the performance of these email in terms of how they drive visits and conversion on the website.

My needs are as follows:

  1. I need to know which links users clicked in the email
  2. What did they do on the website
  3. If possible I want a conversion funnel for email journeys
  4. It would be great if you can also tell me how I can get this tracking in place for all my email campaigns going forward.

Thanks
Sarosh, your friendly colleague in marketing.”

So what now?

Campaign Tracking

Luckily, campaign tracking is a pretty standard thing to do in any analytics package. Adobe Analytics is no exception.

In the web analytics world we call something a “campaign” if it

    1. is off-site (not on our own web site)
    2. has been paid somehow (either directly, per click, per email sent, or because we’re paying someone to tweet)
    3. has links bringing visitors to our site

Campaigns come in all sorts of shapes and sizes. Emails sent out to prospects or customers are campaigns. Our paid keywords on Google or Bing are campaigns. Those banners we’re placing all over the known Internet are campaigns. Even our tweets and Facebook postings are campaigns!

So how do we measure them?

The crucial part is the 3rd item above, the link that brings people to our site. We cannot rely on the HTTP Referer (sic) header, because often people come from apps and there is none.

So, we ask the marketers to assign “campaign IDs” or “tracking codes” to their campaigns. They are supposed to place those tracking codes on every link that they distribute, be it in an email or on twitter.

Now when a visitor clicks on the link, all we have to do is to detect that tracking code in the URL, pull it out and send it into the analytics system.

Let’s look at the details.

Tracking Codes

This is the easy part, from a technical perspective. All the marketers have to do is make sure every link they post or send anywhere in the Internet has a tracking code on it.

Usually, the code would be in a URL parameter named ‘cid’, ‘cmpid’ or ‘extcam’ or something similar. An example link to this posting might look like this:

http://webanalyticsfordevelopers.com/2013/03/26/email-tracking/?cid=1303selfreflink

The tracking code would be “1303selfreflink”.

Easy.

Some notes:

  • Tracking codes should probably be relatively short. We don’t want to run into the 2048 byte URL length limit on older IEs.
  • A tracking code should be specific, either to the email sent, banner placed or keyword bought, or a level deeper: specific for each link in an email. The more specific it is the more insight the marketer can gain, if they use that data. Don’t worry about having too many tracking codes. There’s a tool called SAINT which will allow you (or your marketer) to aggregate.
  • It makes a lot of sense to agree on a structure for the tracking codes! Coding things like date (“1303″), distribution channel (“eml”, “ppc”, …) or even the name of the person responsible is a good idea! “eml1303jenewmerch01″ could be the first link in an email about new merchandise that I sent via email in March 2013. Again, SAINT helps turning those tracking codes into readable campaign names.
  • Use SAINT!

Sending the Code into the Analytics System

Now this is where your skills come into play.

We can do this two ways: a) put JS code on eveyr landing page that looks for the ‘cid’ parameter and reads the code, or b) do it in a central place somewhere.

Once the code has been read from the URL, it needs to go into a special variable that Adobe Analytics provides specifically for campaign tracking: s.campaign.

Being an (ex-) programmer, I definitely prefer option b, of course. We’ll explain how this works exactly, but for now it’s enough to know that you can use a “plugin” in the s_code.js file. The code looks like this:


s.campaign=s.getQueryParam('cid');
s.campaign=s.getValOnce(s.campaign,'s_cmp',0);

The first line tries to read the ‘cid’ parameter from the URL.

The second line uses another plugin to deduplicate, meaning if within the current Visit we have seen this tracking code, we won’t send it into the analytics system again. Most marketers prefer it this way.

We won’t go into the difference between “traffic variables” and “conversion variables” at this point, but just so you know: s.campaign is a conversion variable, a bit like a persistent tag tied to the visitor.

With the tracking code sent into Adobe Analytics, the marketer can now answer all the questions they raised in their email above. They can segment by a tracking code or a campaign. They can look at funnels based on the campaign, and they can even find out which link worked best if they assigned individual tracking codes to all the links in the email.

Next week we’ll post a series of articles about the s_code.js file.


Filed under: Javascript, Principles Tagged: campaigns, plugins, s_code.js

The s_code.js File – Overview

$
0
0

This article and the following four will discuss a file that is vital for Adobe Analytics: the s_code.js file.

We’ll explain what it does and why you need it. We’ll tell you what you have to configure inside the file. We’ll also give you some tips around using it to make your life easier.

Overview

The s_code.js file contains 4 parts:

  1. a section with configuration variables,
  2. the definition of a useful callback method called s.doPlugins(),
  3. space for defining “plugins“, and
  4. the core Javascript code that defines how Adobe Analytics works in the browser.

[Screenshot]

The s_code.js File

The first section is about configuration. Line 10 is the most important part, it tells the system where the tracking should go, into which “report suite” (think of it like a database).

We’ll get to the concept of a repoert suite and to the other settings in a separate post.

The second section, from line 30 – 50 in the screenshot, contains the definition of the s.doPlugins() callback method.

We’ll get to it later as well, as it is a) really important and b) allows you to automate a lot of your tracking.

For now we’ll just mention two things:

The callback will be executed whenever a tracking call is sent to the Adobe servers, just before it is actually sent. So, when you call s.t() somewhere on a page, the system collects some data, then calls s.doPlugins() and then sends everything off.

Example: in the screenshot we assign s.campaign on lines 32 – 36. This allows us to pick up tracking codes for campaign tracking anywhere on the site without additional code on any page!

The third section, from line 51 – 132, contains the definition of the plugins we use in s.doPlugins(). Some of these you get from your Adobe consultant during implementation. Some of them you can download from the Adobe knowledgebase, and some even float around on the Internet. You can even write plugins yourself, of course!

Lines 134 – 138 contain more configuration. This bit you will probably never touch.

Everything down from line 140 to the end is the core Javascript library code. Again, you would probably never touch this.

How do I get the file?

You can get the s_code.js file in two different places: 1. from the Adobe consultant who helps you with the implementation, and 2. straight out of the SiteCatalyst Admin interface.

The former will likely have plugins added whereas the latter won’t.

It usually makes more sense to use the code that the consultant gives you. But there are exceptions, the most important one being when you want to update the core JS library to the latest version.

The official way of getting the latest code has two flavours:

  1. Use Adobe Tag Manager which can automatically update it for you, or
  2. Download the latest version from the SiteCatalyst Admin UI, then transfer your plugins and other customisations over into the new file.

The unofficial, simpler way is to just take all the code below line 140 (or whereever the core JS starts in your file) from the new file into your existing s_code.js file. Works a treat.

Make sure you test before you put the new s_code.js file live!

So much for now, look for the other four articles over the next couple of days!


Filed under: Javascript Tagged: javascript, s_code.js

The s_code.js file – Configuration

$
0
0

The s_code.js file – Configuration

This article is part of the mini series about the s_code.js file. You can find the other articles here:

The Configuration Section

The configuration of some of the tracking is defined in the s_code.js file in two locations.

[Screenshot]

code – configuration section part 1

Let’s look at all the settings in detail. We won’t be repeating information from the knowledge base. Instead, we’ll introduce some concepts.

Report Suites

Adobe Analytics is mostly used to track web sites, mobile apps and other online “real estate”. Data gets sent into the system via a couple of different methods, predominantly Javascript-generated HTTP GET requests.

The backend processes and aggregates the data and creates reports that a marketer can look at when they log in.

Companies might have more than single site or app and so Adobe Analytics has the concept of a “report suite”, which is basically like a database for tracking data. When the marketer logs into the system, they can select which report suite they want to look at using a drop down.

[Screenshot]

Report Suite Selection

So how do we configure the tracking code to send data into a specific report suite?

We need the “report suite ID” or “rsid”. An Adobe consultant would usually give you the rsid, but your marketer might actually be savvy enough as well.

Once you get the rsid, put it into the s_account variable on line 10.

Tracking Servers

Adobe currently has 4 data centres around the world and a whole bunch of data collection centres. The data in a report suite resides in one of the 4 data centres (San Jose and Dallas in the US, London in the UK and Singapore), so we need to tell the system where to send it. This is what the s.trackingServer variable is for.

The value could look like any of these three:

  • s.trackingServer="jexnerinc.112.2o7.net";
  • s.trackingServer="janexnerinc.d1.sc.omtrdc.net";
  • s.trackingServer="om.jan-exner.de";

The first one points straight to the data collection servers situated in the data centre. This used to be the standard for 3rd party cookie implementations.

You can see what data centre the traffic goes to: “112″ designates San Jose, “122″ means Dallas.

[Screesnhot]

s.code – configuration section 2

The second points to a data collection server somewhere near the visitor. This is called “Regional Data Collection” or RDC. Most Adobe Analytics implementations these days should use RDC for 3rd party cookie setups, so this is what you’ll likely find in your file.

Again, you can tell the data centre: “d1″ is San Jose, “d2″ is Dallas, “d3″ is London and “d4″ is Singapore. The “sc” tells you that this will go into Adobe Analytics.

The third one is an example of a 1st party cookie setup, where the tracking goes to a domain set up by your company. Technically, this is a CNAME record pointing to one of the Adobe servers.

[Screenshot]

s.code – configuration section 2

If you have an old s_code.js file, you might not have s.trackingServer. Instead, you might see the s.dc variable instead, with a value “112″ for San Jose or “122″ for Dallas. We’d encourage you to use s.trackingServer instead.

Other Configuration

In a retail environment or when your site tracks any revenue, you will want to define the currency using the s.currencyCode variable. If your company has sites using different currencies, setting this properly is vital as the back end will use it to convert to a standard currency (which can be set up for each report suite).

The variables in lines 18 – 22 configure how some automatic tracking works, specifically tracking of exit links, download links and internal links.

Exit links are links on your site that transport the visitor off the site and somewhere else. Two variables configure how Adobe Analytics treats these links:

  • s.linkInternalFilters defines all URLs that are considered internal, therefore allowing the code to see which links are not.
  • s.trackExternalLinks controls whether the code should automatically track those or not.

The list in s.linkInternalFilters is a list of substrings of URLs which will be matched against the href parameter of any link clicked on the page. If the URL does not match, the system tracks the click as an “Exit Link”.

Fun fact: if you put a “.” into s.linkInternalFilters, the Javascript code will basically treat the whole Internet as internal. You will therefore not see any exit links in the reporting. Good for a development site with changing URLs, bad for production.

“Download Links” work in a similar way, using the s.trackDownloadLinks variable to enable/disable and the s.linkDownloadFileTypes variable to specify which type of content should be tracked. Clicks on links to any of these file types will show up in the “File Downloads” report.

The s.linkLeaveQueryString variable determines whether the URL in Exit Link and File Downloads reports will be truncated (without query parameters) or not (with query parameters).

Some download links do only make sense with the parameters, so this variable allows you to enable them in these two reports.

The other two variables in this section, s.linkTrackVars and s.linkTrackEvents are used by the system to determine which of the custom variables it will send in on link tracking. We shall get to that when we discuss link tracking in general.


Filed under: Javascript Tagged: javascript, link tracking, report suite, s_code.js

The s_code.js file – s.doPlugins()

$
0
0

The s_code.js file – s.doPlugins()

This article is part of the mini series about the s_code.js file. You can find the other articles here:

The s.doPlugins() Callback Method

Now this one is a proper subject for developers. So far we have only seen configuration variables and talked about principles behind Adobe Analytics.

This time, though, we’ll dive into the world of automation and code!

Remember when in the post about basic tracking we mentioned that tracking happens whenever you want on a page or, to be precise, when you call the s.t() method.

Well.

First of all, that was only half the truth. There is a second method that can send tracking into Adobe Analytics. It is called s.tl() (for “track link”), and it is used when you want to track anything that is not a Page View. Prominent examples would be download links or clicks on specific buttons.

Furthermore, when you call s.t(), the Javascript code does a couple of things before it actually sends the tracking off. In a usual setup, setting variables on the page and calling s.t() only does about 20% of the work. The rest is done within the s.doPlugins() method.

Collect Data

The s.t() method takes the “s object” that was defined when s_code.js was loaded. It then amends it with a couple of data points, such as the current time, the version of Javascript supported in the browser, whether Java is enabled or not, screen and viewport sizes and a couple of other mostly technical bits and pieces.

Once it has done that, it calls the s.doPlugins() method. Upon return, it finally sends off the HTTP GET request to the Adobe collection servers.

Automate!

The s.doPlugins() method acts like a call back function that hands you the “s object” and allows you to modify it before it is sent out.

Now keep in mind that the s.doPlugins() method is defined in the s_code.js file. This file is loaded on every page that is tracked on the site!

Basically, we can use the s.doPlugins() method to do things that we want to do on every tracked page, without having to put any further code on the pages!

We have already mentioned tracking codes and campaign tracking, where we basically capture a tracking code off the URL and place it into the s.campaign variable. This is a perfect example for something that should be done in the s.doPlugins() method! You never know where exactly visitors will land.

Other examples include tracking how often visitors have been on the site, how many days have passed since their last visit, or how far they scroll on pages.

You can put any code into the s.doPlugins() method, and you have access to all the attributes of the “s object”. Pure power!

Abuse

With power comes responsibility.

I know a (very capable) implementer who used the s.doPlugins() method to bypass the fact that the agency in charge of the web site at a UK client was less than forthcoming with implementing any web analytics. He added Javascript code that would heavily scrape the page and abuse the DOM to get out the data that the client wanted to track.

This is obviously ingenious, and it allowed the client to track things they would otherwise not have had. But.

When spending cuts at the client meant they stopped working with that implementer, it all fell apart very quickly. Noone was able to keep the code in the method up-to-date and on par with the changes that were made on the site, so one by one, reports stopped working, tracking started to fail, and once the actual site itself was impacted.

So be careful!

We’re not saying “don’t be ingenious”, that would be ridiculous. All we’re trying to convey is: be careful and document the living daylights out of your s.doPlugins() method! Make sure there is a process in place that keeps the communication open between core web site development and the people responsible for the s_code.js file! And test! A lot!

Page Names

On a more practical level, please do not use the s.doPlugins() method to set s.pageName, especially not based on the <title> element of the DOM!

The s.pageName variable uniquely identifies content in Adobe Analytics. That means two things:

  1. Two different pages with the same s.pageName are treated as the sane content in Adobe Analytics.
  2. If you change the s.pageName for an existing page, Adobe Analytics treats the page as a new one, essentially breaking historical reporting.

It is therefore good practise to set s.pageName either on the page itself where it is unlikely to change, or using a specially designated field in you CMS.

Tomorrow we will introduce some of the plugins that are part of any decent implementation of Adobe Analytics.


Filed under: Javascript, Plugins Tagged: campaigns, javascript, pagename, plugins, s_code.js

The s_code.js file – Plugins

$
0
0

This article is part of the mini series about the s_code.js file. You can find the other articles here:

Plugins

Yesterday we mentioned that you can do a lot of things in the s.doPlugins() method, which often means less code on the pages and therefore easier maintenance.

To help with that practice as well as to add interesting functionality, Adobe Consulting have over time written a whole family of code called “plugins”.

Plugins are little bits of Javascript code that are placed into the s_code.js file. They can subsequently be used inside the s.doPlugins() method to assign variables to your liking.

A couple of examples:

  • The s.getQueryParam plugin is used to read query parameters in the URL and return their value.
  • Using the s.getValOnce plugin, you can make sure a value is only sent once. We call that “de-duplication”.
  • The s.getTimeParting plugin returns time of day and day of week.
  • To track visits over time, we can use the s.getVisitNum and the s.getDaysSinceLastVisit plugin.
  • We can track activities across visits using the s.crossVisitiParticipation plugin.
  • The s.getPercentPageViewed plugin helps figure out whether and how far down visitors scroll on the site.

Let’s look at some of those in more detail.

s.getVisitNum & s.getDaysSinceLastVisit

The s.getVisitNum plugin returns a number that represents how many visits the visitor has had on the site, while s.getDaysSinceLastVisit returns the time since the last visit.

	s.eVar35 = s.getVisitNum('m');
	s.eVar36 = s.getDaysSinceLastVisit('s_lv');

For a visitor who comes to the sie for the first time ever, s.getVisitNum will return 1. If they come back a second time some other day, the plugin returns 2, and so on. The s.getDaysSinceLastVisit plugin will return whether the last visit was less than 1 day ago, less then 7 days, more than 7 days or more than 30 days ago.

The reports you get out of this are relatively useless without classifications. We’ll explain those in the article about SAINT. Once they are classified, though, they can be really powerful!

[Screenshot]

Classified Visit Number Report

Your marketer ideally wants visitors to come back to the site often and frequently, no matter what the purpose of the site may be. Using the visit number and days since last visit, we can segment returning visitors into 4 “quadrants”:
  1. Visited few times, low frequency
  2. Visited few times, high frequency
  3. Visited often, low frequency
  4. Visited often, high frequency

Analysing the “visited often, high frequency” quadrant might give us an understanding of what these people do. And we could from there figure out how to get some ofther visitors into that quadrant as well, i.e. turn them into more valuable visitors.

The ‘m’ parameter in the s.getVisitNum('m') call stands for ‘monthly’ and tells the plugin to reset the count at the beginning of a new month. Other possible values are ‘d’ (daily), ‘w’ (weekly), or any number which the plugin will read as a number of days.

The related s.getNewRepeat plugin has less functionality than s.getVisitNum and we therefore never use it.

s.getPreviousValue

This plugin is used to store a value for later use and at the same time retrieve the last value stored. It is slightly non-intuitive to use, so let’s look at an example:

	var test1 = s.getPreviousValue('foo','gpv_test');
	var test2 = s.getPreviousValue('bar','gpv_test');

At this point, test1 will contain whatever value had been stored in the “gpv_test” cookie originally, the cookie will now contain “bar” and test2 will contain “foo”.

You would usually call s.getPreviousValue on every page of your site, not twice on the same. One common use case is to store the page name, like so:

	var s.prop4=s.getPreviousValue(s.pageName,'gpv_page');

We’ll get back to the use case around this.

We deliberately did not want to explain s.getQueryParam in too much detail, even though it is the most used of all the plugins by far. There’ll be a separate article when the time comes.

Cookies

Most of the plugins use cookies to store state. Especially those that work across visits (like s.getVisitNum, s.getDaysSinceLastVisit or s.crossVisitParticipation) are obviously relying on people to not delete their cookies!

The bad thing is that cookies are not as reliable as they used to be. People are getting increasingly aware of their ability to delete them. The good thing as that all cookies set by plugins are set through Javascript and are therefore by design 1st-party cookies, which means even Safari and Firefox 22+ accept them.

As a rule of thumb, cookie acceptance and deletion rate these days are still ok in the sense that the reports based on the plugins allow marketers to draw valid conclusions.

Notes

[Screenshot]

Plugins in the Knowledge Base

While some plugins come for free and can be found in the Knowledge Base, others are implemented by Adobe Consulting only. Yet others are written by 3rd parties.

For two good examples, you might want to visit Kevin Rogers or Jason Thompson. Both are active on twitter as well (@vabeachkevin & @usujason). Talking about twitter, you can and probably should follow the “#measure” hash tag.

Once you start thinking about plugins and the s.doPlugins() method in general, you’ll quickly get to tag management. Tag management systems offer similar capabilities and much more.

We just mention this because it is the logical next step once you get more savvy and your marketing department gets more demanding.

For a different view on plugins, and without wanting to endorse any particular 3rd-party tool, let me point you towards Jennifer Kunz’s article “Breaking up with SiteCatalyst Plugins“.

The same can be done with pretty much any tag management system on the market.


Filed under: Javascript, Plugins Tagged: javascript, plugins, s_code.js

The s_code.js file – Core Javascript Code

$
0
0

This article is part of the mini series about the s_code.js file. You can find the other articles here:

Core Javascript Code

The biggest portion of the s_code.js file is the core Javascript code underneath the “DO NOT CHANGE” line.

In this part of the file, all the important client-side functionality of Adobe Analytics is defined. The “s object” creation method s_gi is declared along with a couple of helper methods.

Most importantly, s.t and s.tl are defined here, the two methods that you use to actually send tracking information. We have introduced s.t and will discuss s.tl at some point.

A big part of the code handles setting of the so-called “automatic variables”.

If you check with a debugger, you will notice that tracking calls actually contain a lot more than the data you set:

Data points like screen size (URL parameter “s”), browser width and height (“bh” & “bw”), colour depth (“c”), Javascript version (“j”), local time (“t”), the URL of the page (“g”) and others are automatically appended.

Depending on what browser you are using, you might see more parameters.

Netscape-based browsers send a list of installed plugins in the “p” parameter, while IE sends things like connection speed (“ct”) and whether the current page is the home page (“hp”). How useful those measurements are is a matter of discussion…

Closing Thoughts

The s_code.js file is the heart of all Javascript-based, client-side tracking in Adobe Analytics.

It does the heavy-lifting you’d expect from a library. It handles automatic variables. It provides the “s object” container that allows you to store data for transfer. It also provides you with methods to send that data.

On top of that, it contains the very useful s.doPlugins call back method, which allows you to handle everything that has to be done across the whole site in a central place.

The s_code.js file truly is the most important piece in the whole tracking picture.

Now having said that, we hope that in the future it won’t be.

Two reasons:

  1. The file really has two broader purposes, and those should be separated.
  2. Tag Management is on the rise, fortunately.

We can broadly group the four parts of the s_code.js file into two: core Javascript code versus the rest.

The core Javascript code gets an update every now and again. Adobe Engineering is driving these updates. While a year ago or so they shipped version “H.24.2″, we are now on version “H.25.4″.

Note: there is a change log available for the core Javascript code.

The rest of the s_code.js file will be updated by you or other implementers.

That raises an obvious question: how to easily integrate?

We will post an article on best practise, but for now let’s just say it would be easier if those two groups would be separate.

Secondly, tag management systems are more and more powerful and more customers are using them for convenience and sometimes enhanced functionality.

It makes a lot of sense to put at least some of the four sections that currently sit inside s_code.js into a tag management system instead.

So there you have it, our mini-series on s_code.js concludes. Please feel free to post any questions or remarks in the comments below this or the relevant posting! We’d love to hear from you!


Filed under: Javascript, Principles Tagged: javascript, s_code.js

Debugging

$
0
0

You are a developer – you develop! Also, sometimes, you debug.

Our article today focusses on the latter: how to debug when you are implementing Adobe Analytics.

Let’s start off by finding out what exactly we can expect to debug.

Adobe Analytics has a lot of moving parts, some of them client-side, some “in the cloud”. Debugging the latter is very much an end-to-end test situation, while the former can be debugged “traditionally”.

Client-Side

In the article about variables, we explained how you send data into Adobe Analytics and that it eventually ends up being parameters of the URL in an HTTP GET request.

That makes it fairly easy to debug. You can use all sorts of tools to see what your browser actually sends:

Let’s start with the Adobe Debugger. Here’s what it looks like:

[Screenshot]

Adobe Debugger

The Adobe Debugger is a bookmark with Javascript that when called displays the window you can see on the left in the screen shot. It works with Adobe Analytics (“SiteCatalyst”) but also other parts of the Adobe Marketing Cloud.

The big plus is that it “decodes” the information it finds in the URL.

You can clearly see that this specific page we’re looking at has set s.prop1="DE";.

If your browser has built-in tools or you are using a tool like Firebug you can look for the HTTP request and check the parameters.

[Screenshot]

Firebug

You won’t have the variable names. s.prop1 will instead be c1, s.eVar9 will be v9. The documentation has a list of all symbols.

Apart from that, the actual data you see is exactly the same!

It is also exactly the same if you debug using a proxy like Charles or Fiddler.

[Screenshot]

Charles

Proxies have advantages: they can show you a timeline of requests, not just what the current page sent out. Especially useful when we get to link tracking.

They can usually save a file containing all HTTP traffic they grabbed. That means you can load it back and look at it later, in case you’re not sure about parts of it.

Also, proxies let you tweak the requests, the pages or even the s_code.js file on the fly. (Look for a feature called “Map Local” in Charles!) Extremely useful for testing changes to the s_code.js file before putting it live. Don’t forget to switch it off after testing!

Server-Side

As we said above: there’s not a lot of debugging you can do server-side, mostly because the processing really is a black box. Also, there are a lot of settings that govern how the system processes the data once it has arrived, and some of those settings you will probably never touch when you implement. It’s a bit of a grey area. Or gray area, if you’re in the US.

Our suggestion: run controlled tests!

Here’s how it works:

Say you just made a change to your s_code.js file. From now on, your site is supposed to pick up the “fb_ref” parameter for links coming from Facebook and put the value into s.campaign.

  1. Think of a use case and define a step-by-step test.
  2. Determine what data you expect to see after the test (this is crucial!)
  3. Run through the test.
  4. (Bonus step: check the value in s.campaign using one of the tools mentioned above.)
  5. Log into Adobe Analytics and compare the data you see with what you expected.

Two notes:

  • Make sure you give the system some time before you check the results (see Latency in SiteCatalyst 15 for details).
  • It is imperative that you figure out the expected results before you run the test! I guarantee you that if you run the test first, you’ll be able to explain the results to yourself, no matter how wrong they are. It’s called “confirmation bias“. I even sometimes look at the data and my expected outcome and try to argue that I my expectations were wrong. Don’t fall into that trap!

So there you have it, no go and develop something so you can use your new-found skills to debug it!


Filed under: Principles Tagged: campaigns, debug, s_code.js

Tracking Mobile Apps

$
0
0

So far we have explained what basic tracking of web pages looks like.

Today we’ll broaden our horizon and briefly introduce how mobile apps can be tracked — apps for iOS, Android, Windows Phone 8, apps developed for iOS or Android using PhoneGap, apps for WinRT (Windows 8) or even OS X and some other mobile operating systems like RIM, Symbian or Windows Phone 7, XBox or even Flash/Flex.

The idea is relatively simple:

  1. Add the Adobe Marketing Cloud Mobile library to your app,
  2. Tag the different “screens” of your app as if they were web pages,
  3. Decide whether you’d like to see “offline data”,
  4. Configure a report suite for your app tracking,
  5. Develop and debug, as usual.

So let’s look at the steps one by one.

AMC Mobile Libraries

When you tag a web page, you use Javascript and a file called s_code.js that contains the definition of all Analytics-related functionality used on the page.

For mobile apps, the Mobile Libraries do the same job. They define the neccessary environment, methods and stubs that you can use when you build tracking into your apps.

For some of the libraries, there’s more.

On iOS, Android and Windows Phone 8, you get what we call “Lifecycle Metrics” when you tag up your app. Those metrics include data points like app installs, launches, engaged users, install date, launch number, days since first use, OS version and many more. The documentation lists all lifecycle metrics.

These allow your friendly marketer to judge how engaged users are with your apps or to run mobile cohort analysis, extremely useful especially if your company is relatively new to apps in general.

Updates

The libraries get updated every now and again. Sometimes, the update requires code changes on your end or configuration changes in Adobe Analytics. The move to v3.x of the libraries on iOS and Android was such a case. Point releases should usually be “compatible” and only require a drop-in of the new lib and a recompile.

Tagging

It’s best practice to treat apps almost exactly like web sites. The equivalent of a web page would be an Activity on Android or a View on iOS. When an Activity or a View loads, you should track it just like you would a web page when it loads. So where you’d use s.t on a web page, you’ll use trackAppState in a mobile app.

The libraries contain a TrackingHelper class that you should use as a container for functionality you want to add. The example in the documentation speaks about tracking logins, but it obviously applies to all sorts of tracking. Use it!

The examples in the documentation also heavily use the so-called “Context Data variables”, which we haven’t mentioned yet. In a nutshell, they “replace” the usual Analytics “variables”. Context Data variables are more like a hash map and they should make it easier for developers to know what data to put where.

Offline Data

We’re talking about tagging mobile apps. Apps run on mobile devices, phones and tablets, or maybe cameras. Mobile devices tend to be carried around and they tend to drop off the network every now and again. Now that might prevent your app from running, but most likely it doesn’t; people will still be able to use your app without network access.

That raises the question: how do we track the app when the device is offline?

Two possibilites: only track when the device is online, or track all the time and buffer when needed.

The libraries can do both, and they handle the buffering for you for option 2 if you tell them to.

Consider this:

  • For offline tracking to work, the tracing calls have to be “timestamped”, meaning the libraries will transmit them with a time stamp that tells the collection servers when the tracking actually happened.
  • Those tracking calls can only be processed if the collection and processing queue knows that they’re timestamped — the report suite needs to be “timestamp-enabled”.
  • If the report suite is timestamp-enabled, all tracking sent into it has to be timestamped!
  • If you want to track mobile app traffic and web traffic into a single report suite, you have to add timestamps to your web tracking calls (which you can do if you use code H.24.4 or later).

We reckon your friendly marketer will discuss whether mobile app traffic and web traffic should be tracked into a single report suite or separately, but just one thing to think about: do the site and the app have the same goals and do they provide roughly the same functionality? If so: track them into the same report suite.

Once you have decided whether offline tracking should be used, you can contact ClientCare and ask them to enable timestamps for the report suite(s) in question. Only they can do it.

Develop and Debug

We won’t be telling you how to develop, but we can help you with the debugging.

The usual approach is to configure your emulator or device to use a proxy and then use your favourite debugger and check the data being sent in the tracking call by looking at the URL — really not that different from how you would debug on the web.

We hope that makes sense.

Remember that there is a ton of material on developer.omniture.com and that you can always contact your Account Manager and get help from Adobe Consulting should you need it. We think you won’t.


Filed under: Principles Tagged: debug, mobile, report suite, s_code.js

Migrating to Tag Management

$
0
0

I have been slow with implementing Tag Management on my own sites and until I actually started doing it I didn’t know why. Now I know: it’s not straight-forward.

It is fairly easy once you know what to do, though.

So let me walk you through the process from the perspective of a developer.

We’ll do a simple example first, just a standard blog article with s.pageName, two events and an eVar. Later, we will provide an example with Context Data Variables, which in theory should be easier.

The Original

The page we are going to use looks like this:

[Screenshot]

Original Sample Page

You can see everything that is needed for tracking close to the </body> tag at the bottom of the file.

In the code, we are setting:

  • s.pageName
  • s.events — we’re sending event1 & event15
  • s.eVar21

Now all of that is specific to this very page and we will therefore have to keep it on the page somehow when we move to Tag Manager.

The Change

We are following the online documentation, and we’re specifically interested in step 2 — Migrate Legacy Implementation Code.

The documentation explains how the overall architecture works and what the different parts do, but I am missing one thing: what happens to the code on my pages?

The secret lies with amc.on Tag Event Callbacks!

Tag Management in its current incarnation (“2.0″) executes tags asynchronously. That means the tags are loaded at the top of the page but they can fire whenever they want.

You can no longer just include a <script> block on your page that sets the various “variables” or otherwise accesses the s object, because the object might not yet exist, or you might be too late!

So, you wrap your code into a function that is part of an amc.on callback handler.

I won’t go into too much detail here. The documentation on Tag Event Callbacks lists them all. In our simple example, all we need is to use a handler for the tagload.sitecatalyst event.

New Code

The new page, with the tag loader inserted and the page code wrapped, looks like this:

[Screenshot]

New Sample Page

Note that the tag loader sits at the top of the page rather than the bottom. That allows the system to fire tags earlier, reducing the risk of lost tracking due to quick clickers. Because it is asynchronous, it should not impact page load times or performance.

Note also how the actual page code hasn’t change at all, except for the wrapper, of course.

Notes

The example is really very simple, and looking at the code it doesn’t seem to make much sense to switch to Tag Management. For bigger sites that is likely completely different. Especially sites that use not only Analytics but also other parts of the Adobe Marketing Cloud, deployment will be a lot easier with Tag Management.

And even in this simple case there is one reason to use it: updating the “core” Javascript code is a matter of clicking in the UI rather than deploying a new file.


Filed under: Javascript, Page Code, Principles Tagged: javascript, s_code.js, tag manager

Versioning Your Tracking

$
0
0

Here comes a good idea: make sure your s_code.js file has a version!

There are three parts to this tip:

  1. Put the s_code.js file into your revision control system.
  2. Make sure the file has a version on the URL.
  3. Track the version of the file into Adobe Analytics.

Let’s go into these one by one.

Revision Control

You might remeber that the s_code.js file contains 4 parts:

  1. a section with configuration variables,
  2. the definition of a useful callback method called s.doPlugins(),
  3. space for defining “plugins“, and
  4. the core Javascript code that defines how Adobe Analytics works in the browser.

Of those 4 parts, only the core Javascript code is provided by Adobe. The other 3 are your repsonsibility. You will likely modify and amend the configuration, add plugins and add custom code to the s.doPlugins() method.

That means the s_code.js file is a source file like any other in any of your projects. And as such it should really be under revision control!

Version on URL

When you change something in the s_code.js file and push the change live, you’d ideally like that change to apply to all visitors of the web site from that very moment on.

Unfortunately, caching can play tricks on you.

Usually that doesn’t matter that much, but sometimes you change things in the file that are not working very well in parallel to old versions, like for example if you reassign a “variable” or an event.

So in order to break caching, we recommend that you add a version to your templates, if possible.

Instead of loading the s_code.js file like so:

  <script src="/include/s_code.js></script>

add a URL parameter with a version, like so:

  <script src="/include/s_code.js?v=2.5.4"></script>

There is one drawback — you will have to update all your templates whenever you release a new s_code.js file.

An alternative could be to only add a major release number to the templates so you only have to update them when there is a major release of the s_code.js file, such as a core Javascript update or a big change.

Track the Version

My all-time analytics hero Adam Greco wrote about this 2 years ago: Track Your JS File Version. The tip is still valid.

Adam looks at it from the point of view of an analyst or someone who provides insight or data. Naturally, trust is the main issue as well as the possibility to quickly find the root cause of issues. For you as a developer, the latter is vital.

All you have to do is to agree with your friendly marketer what “variable” to use for this — say prop10. Then you write the current version of the s_code.js into prop10, like so:

  s.prop10 = "2.5.4";

Some people go further and add the release date to the prop, like so:

  s.prop10 = "2.5.4|2013-05-25";

Two advantages:

  1. Even easier to spot whether data anomalies in the reports correlate with releases of the s_code.js file.
  2. Very easy to see how “old” the core Javascript code is.

Neither of these three tips will save any lives, but they will make everyones lifes easier, especially yours!


Filed under: Javascript, Opinion, Page Code, Principles Tagged: javascript, s_code.js

Tracking Apps vs Web Pages

$
0
0

Today we’ll focus on the differences between tagging a web page (see Basic Tracking) and tagging an app (see Tracking Mobile Apps).

While those two are fairly similar, there are some differences that you need to keep in mind.

Online and Offline

The biggest difference is probably that an app can work even if the mobile device has no network connection. Most apps are built so they can work “alone”. In fact, this very ability is what makes apps so attractive.

You can still track what users are doing in the app even when the network is unavailable.

The Mobile SDKs for the current mobile ecosystems all have buffering built-in.

When an app cannot find network connectivity, the library will simply buffer the tracking calls and send them off once network is back.

If you’re using Javascript-based tracking on a normal web page, you simply can’t do that. (Well… you could in theory use HTML5 local storage, but let’s not go there.)

Visitor IDs

When a person first visits one of your web sites, the Javascript-based tracking code tries to set a cookie on their browser called s_vi. This cookie contains a random visitor ID.

The system uses the visitor ID from the cookie to tie together activities by a single visitor across time. It allows the system to determine activities within a visit and attribute things people do to other things people do later. This is what allows your friendly marketer to track email campaigns for example.

Pretty important.

Unfortunately, some browsers do not accept 3rd-party cookies. In those cases, the code (H.25.4 and later) will set a cookie called s_fid and put a different, random visitor ID into it. If there is no s_vi but an s_fid cookie, the system will use the latter.

Other browsers are set not to accept cookies at all. In those cases, the system will use the HTTP User-Agent field along with the IP address to calculate a visitor ID.

You can imagine that the whole visitor ID thing is not as accurate as most marketers would like it to be. But that’s just the reality of current technology.

The good news: for mobile apps, there is only one mechanism and it is pretty accurate.

When a tracked mobile app is installed on a device for the first time, the library generates a random visitor ID and saves it with the app data. If the app is updated, the visitor ID persists. Only when the app is deleted will the visitor ID be deleted as well.

So on mobile apps, visitor IDs are very stable and your friendly marketer can therefor really analyse user behaviour over time.

Leaving Pages

When a browser loads a page or when a user clicks something, we can easily add tracking. But what about a user leaving a page or closing down their browser?

Currently there is no reliable way to track that with Javascript.

Apps are different.

As we said in App Tracking – Part II, you can track the onPause() callback on Android (or the equivalent on iOS and other systems). Because apps are programs, you can be sure these callbacks will be called! Unless the device crashes, the system will always call onPause() when an Activity closes.

Why does that matter?

Measuring time will be more accurate. Instead of relying on a time out for seeing when a visit ends, the app “knows” when it is done.

The same applies when you compare someone walking away from their browser versus someone putting away their phone: the browser on a desktop computer has no idea whether the user is currently looking at it. But on a phone, when you put it away or it goes to sleep, the Activity or View will be put into the background.

The result is that your marketer can get pretty good “engagement” metrics from an app.

End-to-End Tracking

With the exception of Android (see App Tracking – Part II), most mobile eco systems lack end-to-end tracking capabilites.

What?

Your friendly marketer spends budget on a couple of things, one being acquisition of visitors, basically getting people to your site or app.

They want to use analytics to see whether they spend the right amount in the right places or whether they should change their strategy or channel distribution. For a marketer, this is very important!

So they tag up all URLs that they send out, be it to web sites, specific landing pages or even app downloads.

On web sites, you can very easily track this, see Email Tracking. The automation in the s.doPlugins() method makes it an integral part of the site.

Apps, however, are different. Currently only Google Play passes URL parameters all the way through to the app so they can be grabbed, tracked and reported against. For all other systems, this end-to-end capability simply doesn’t exist.

Here’s hoping that the other vendors will follow Google.

s.doPlugins()

Talking about automation… with Javascript-based tracking on the web, you can automate a lot of things using Javascript plugins or code you write yourself in the s.doPlugins() method.

Remember: this method is called every time a tracking call is generated.

The Mobile SDKs do not have that sort of mechanism, but you can build it yourself fairly easily.

If you are following best practice, you’ll be using the TrackingHelper class a lot. You’ll be adding custom static tracking methods for most of the Activities or Views in your app and you’ll rarely call low-level tracking functions anywhere else in your code.

That means you can build your own doPlugins function and plugins fairly easily within the TrackingHelper class!

I recommend you do that.

Updates

When something goes wrong with the tracking on a web site, or when you simply want to change the tags, you can push a change live either via the s_code.js file or to the actual pages (or templates) that make up your site.

As soon as you do that (and the various caches you might use have expired and are passing through the new version) everybody is tracked according to the new configuration.

In general, every change that you roll out on a site applies to everybody immediately.

Not so with apps!

You can put a new version onto the App Store or Google Play, but noone forces users to get that update. At least not yet.

The result is that every change you make to tracking has to take into account backwards compatibility.

No changing of events for the fun of it. No reassigning of eVars. Once you use a “variable” for something, you’re tied in.

Unless you are using Context Data Variables and Processing Rules, of course. If you tag a mobile app, you should use Context Data Variables if only for this reason! No excuses!

Can you think of any other differences?


Filed under: AppMeasurement, Javascript, Principles Tagged: javascript, mobile, plugins, s_code.js

The s.abort Flag

$
0
0

With the release of H.25.3 in January 2013, the Javascript code was augmented with the s.abort flag — a flag that when set instructs the core Javascript code to not fire the tracking request.

Uh, what?

Where would you use that?

In the interest of keeping the page tagging light (do we have to go into why that is a good idea?), as much of the work done by Javascript code as possible should sit in the s.doPlugins call back method. And this is where you would use s.abort.

What for?

There is an example in the release notes that looks like this:

s.doPlugins = function(s) {
     s.campaign = s.getQueryParam("cid");
     if ((!s.campaign) && (!s.events)) {
          s.abort = true;
     }
};

This code basically aborts all tracking unless there is a campaign tracking code or at least an event happening.

Other use cases include:

  • Cancelling tracking for a rotating banner once it has rotated all the way through
  • Cancelling tracking on exit, download or custom links
  • Cancelling tracking in any other situation that can happen on your site

Let’s look at a specific use case for cancelling tracking for custom links: imagine you have a widget for social sharing. Imagine you are able to tag that widget, because your friendly marketer definitely wants to know when people share content. So far so good.

Unfortunately, the rules are different for the different networks and so your catch-all approach for tagging all social media share/like/pin/… activity might in some cases have to be altered.

For those cases (*cough*facebook*cough*), you can implement special code and just cancel the tracking call coming from the widget.

Another widely used use case: cancelling tracking when Safari or Chrome load the page in “preview” mode. Google calls the feature “Instant Pages”, Apple calls it “Top Sites”. In both cases, the browsers load pages before a user even decides to look at them, which obviously inflates your web analtics data.

So, you might want to cancel tracking in those cases.

For Safari, look out for the X-Purpose: preview header. If it is present, use s.abort = true; to cancel the tracking call.

For Chrome, you can use the Page Visibility API.

One more use case: switching tracking off completely. If you do not have a complete list of tagged pages but you really want to switch off tracking with Adobe Analytics completely, all you have to do is to set s.abort = true in the s.doPlugins method in the s_code.js file or files.

Crude but effective.

The s.abort flag, support for tracking long URLs as well as the addition of a new fall back for visitor identification actually made H.25.3 a pretty big release, much bigger than the announcement sounded like.


Filed under: Javascript, Tips Tagged: javascript, s_code.js

Ode to Charles & Map Local

$
0
0

There once was a tool with a feature
The merits of which like a preacher
I praise on this blog
And I’m almost agog
For it’s part of my normal procedure

If there is one tool in my toolbox that I have to point out, it’s “Charles” by Karl von Randow.

Sure, there are others that are useful (Firebug, Omnibug) or even beautifully efficient (Sublime Text), but no other tool is as important for me as Charles.

I have mentioned Charles before, but today I want to show you my two most common use-cases.

Track the Tracking

Charles sits between the browser and the Internet as a proxy. It muscles itself in automatically when you launch it, so no messing around with proxy settings is needed.

Once started, it can show a structural view (“Structure”) or a timeline (“Sequence”).

A lot of people use the structural view but I am a big fan of the timeline, mainly because it is better suited for troubleshooting or checking work in progress.

Here’s what I do:

  1. Switch to “Sequence”
  2. Add a filter (e.g. “/b/ss”) so I only see the traffic I’m interested in
  3. Select the “Request” tab where I can see the URL parameters spelled out individually

Looks like this:

[Screenshot]

Charles “Sequence” View with a Filter

Some things I do when I use Charles:

I use the “Request” tab, “Query String” sub tab, to see what “variables” the tracking call contains. In the screenshot, we see s.pageName (set to “home”), some events, props and eVars. We even see some Dynamic Variables (eVar11 will have the same value as prop11, and prop14 will contain the contents of the s_vi cookie).

[Screenshot]

“Request” Tab / “Query String” Sub Tab

I can switch to the “Cookies” sub tab where I can see the content of my “s_vi” cookie. I can also see two cookies called “s_pers” and “s_sess”. Those are used by the “Cookie Combining Utility” and contain other cookies, so to speak.

[Screenshot]

“Request” Tab / “Cookies” Sub Tab

On the “Response” tab, “Cookies” sub tab, I can see exactly what cookies the server has sent, along with expiration, domain and path.

[Screenshot]

“Response” Tab / “Cookies” Sub Tab

If you are looking for more control and/or options, Charles has you covered. While I do not use any of these routinely, they certainly have come in handy in the past, mainly the ability to repeat a request to the server. You can change the request before re-sending it as well!
[Screenshot]

Repeat / Edit a Request in the “Sequence” View

Trick the Tracking

Here comes the ultimate killer feature for anybody who builds for or works with anything on the WWW: “Map Local”.

My top use case: modify the s_code.js file and see the results in the live environment.

This is useful in a lot of situations.

  1. When you want to upgrade the core Javascript code
  2. When you want to upgrade, add or remove a plugin
  3. When you want to test Campaign tracking, maybe with live campaigns or paid search
  4. When you want to troubleshoot, maybe start with a simplified version of the s_code.js file

So how does it work?

First you download whichever file it is that you want to work on from the web site and store it locally. Next, you tell Charles to serve the local file rather than the original. Then, you alternate between your editor and the browser, making changes and checking them.

The great thing about this is that the browser has no idea what is happening. “Map Local” is completely transparent!

So, go to Tools > Map Local (or simply press Ctrl+Shift+L) to call up the Map Local Settings dialog.

[Screenshot]

“Map Local” Settings Dialog

Click the “Add” button to add a new mapping or double-click an existing mapping to edit it. The Edit Mapping dialog window appears.

[Screenshot]

“Edit Mapping” Dialog

In this dialog, you specify what exactly you want to map, and what file to use instead.

You can leave some of the fields empty. As an example: if the “Protocol” field is set to “http” Charles will only map files served via HTTP, not HTTPS, but if you leave the “Protocol” field empty, it’ll match both. The same goes for the “Port”, “Query” and even the “Path” field. Careful with the latter!

Close both dialogs and you’re good to go.

A simpler way of adding a “Map Local” to a remote file is via the Structure or Sequence view.

Just find the file, right-click it, then select “Map Local…”

[Screenshot]

“Map Local” in “Sequence” View

Note that if the file is mapped already, Charles displays a helpful tick mark next to it!
[Screenshot]

“Map Local” with Tick in “Sequence” View

Notes

Charles is not the only proxy out there, of course. You can achieve the same using Fiddler, I’m sure.

If you only want to track the tracking, not trick it, there are a lot of tools, including the Adobe Javascript Debugger and Bloodhound.

Pro tip: when you’re done developing and testing, make sure you disable “Map Local”!

I can assure you that by the next time you are looking at something, you’ll have forgotten all about it, and you will see inexplicable effects and a live s_code.js file that looks old, even though you’ll be sure IT just pushed live the latest version. You’ll curse browser caches, proxies and — oh, wait a tick … proxies … d’uh.

Happened to me more often than I’m prepared to admit.

This one goes out to Karl!


Filed under: Javascript, Tips Tagged: campaigns, charles, cookies, debug, javascript, pagename, s_code.js, s_vi

Migrating from H-code to AppMeasurement

$
0
0

In May 2013, the Adobe analytics product team released a new Javascript library, no longer called “H.xx.y” but “AppMeasurement for JavaScript”.

The main selling points for this new lib are it’s speed (3 – 5 times faster than H.25), size (8k compressed, compared to 13k for H.25) and native support for some of the most used plugins (getQueryParam being the big one). My colleague Ed Hewett wrote a post about the new library in May.

The AppMeasurement for Javascript library (I shall call it “the new library” from here on) is small and fast enough to be used on mobile sites but has all of the power of the old H-code so it can also be used on standard sites aimed at desktop browsers. It should therefore be the preferred library going forward for pretty much everybody.

The question then is: how do I migrate from H-code to the new library?

Prerequisites

Let’s start off with the prerequisites.

The new library is new, and it currently comes with support for most but not all Javascript plugins. You will have to check the list of supported plugins to see if all of yours are supported.

Crucially, the “Cookie Combining Utility” is currently not on the list of supported plugins. If you are using it, that is a show-stopper, because removing it would mess with a lot of your data.

The Analytics/Target integration is also not supported at this time (December 2013), which means if you are using both Analytics and Target, you have to wait before migrating.

You might be using the “channelManager” plugin for your marketing channel reporting. Or you might use the “FormAnalysis” plugin to analyse some of your forms. Both are not supported! Do not migrate!

Plugins are usually developed by Adobe Consulting when customers need them. If you are currently using channelManager and you want to migrate to the new library, you should work with a consultant, who will likely be able to create a new channelManager plugin for you. Note that there is a cost associated!

And in case your visitors are stuck on really old browsers, know that the new library does no longer support IE 4 & 5 as well as Opera 6 and earlier. Wow, Opera 6… that is pre-Presto… I was still living in Southern France when that came out!

Migrating

Migrating from H-code to the new library is not overly difficult.

You will basically update your s_code.js file as usual: copy everything below the “DO NOT CHANGE” line from a newly downloaded file into your existing s_code.js file.

Rumours about Adobe engineers diving off cliffs when you do so are wildly exaggerated.

For an upgrade from one H-code to another, this is enough, but when you migrate to the new library, you need to do some extra work.

First, the library now contains functionality to grab URL parameters.

You will have to remove the getQueryParam plugin from your s_code.js file and change all references to it to the built-in s.Util.getQueryParam. Instead of

	s.campaign=s.getQueryParam("cid");

you would now write

	s.campaign = s.Util.getQueryParam("cid");

The parameters are slightly different, and the built-in version does not support multiple URL parameters as far as I can see.

Secondly, if you are using the s.c_r() and s.c_w() functions, you must use s.Util.cookieRead() and s.Util.cookieWrite() instead.

The parameters on the new methods are pretty much unchanged. Note that if you do not give s.Util.cookieWrite() an expiration (a Date object), it will create a session cookie.

If s.Util.cookieRead() does not find the cookie, it will return an empty string, which is in line with most of the plugins in the Analytics universe.

Third, you need to either remove non-supported plugins or test them thouroughly.

Then, you need to test thouroughly.

Seriously, this migration is more than your normal H-code upgrade.

Some s_code.js files out on the Internet have been customised beyond belief! Chances are that yours is one of those, and you owe it to your marketer to double- and triple-check everything is ok before you push your changes to live. Use Charles!

There is no reason why your file should not work with the new library (except for what I mentioned in the section above), but I am quite sure the Adobe QA people couldn’t possibly check everything that people have done to with their s_code.js files.

Again: test until you forget what your job title used to be.

Notes

The new library can go into the <head> of your pages.

I know customers who are using content management systems or templates that would make integration into the <head> much easier than in the <body>. If you are in that camp, migrating to the new library would really make sense for you.

The library offers a new method called s.clearVars(), which removes existing values for most of the “variables”.

This is highly useful for link tracking, or in situations where your page content is changed dynamically and you are “simulating” normal tracking.

You can change the way you instantiate the library.

H-code would rely on a global variable called s_account to be set to the report suite ID(s) before instantiation. The new library can now be used much like it’s siblings from app development. Where formerly, you would use code like this:

	var s_account="rsid";
	var s=s_gi(s_account);

to instantiate the “s object”, you can now do it like this:

	s=new AppMeasurement();
	s.account="rsid";

The old way does still work, though. Because all your page code is also compatible with the new library, the migration can be entirely handled via a change to the s_code.js file.


Filed under: AppMeasurement, Javascript, Plugins Tagged: cookies, javascript, s_code.js, update

s_gi() and Tracking Links

$
0
0

Today we’ll discuss one of the big questions of all times: when tracking links or actions, is it necessary to call s_gi()?

If you don’t know what I’m talking about, go and read the article on Tracking Links & Action while I wait.

At the heart of it is this piece of code:

<script type="text/javascript">
	var s=s_gi(YOUR_RSID); // replace this with your RSID!
	s.events="event21,event22";
	s.prop31=s.eVar31="Link Tracking White Paper";
	s.eVar32=page_name;
	s.eVar33="+1";
	s.linkTrackVars="events,prop31,eVar31,eVar32,eVar33";
	s.linkTrackEvents="event21,event22";
	s.tl(this,"d","Link Tracking White Paper");
</script>

As I wrote in the other article, the call to s_gi() is meant to instantiate the “s object” which will a) carry the “variables” and b) define the s.tl() method used to trigger the tracking call.

So how come you will find sites that use link tracking without s_gi()?

Let’s find out what s_gi() does.

s_gi()

The s_gi() method has two jobs: 1. instantiating an “s object” for a given list of report suite IDs and 2. retrieving that “s object” at any point.

Think of the Singleton patterns_gi() works like the standard getInstance method.

The actual “s object” is implemented as a property of the window object, meaning when you call s_gi(), the method will either create an “s object” and attach it to the window object, or it will return the “s object” that is already attached there.

In the context of link tracking, it is pretty safe to assume that when a visitor clicks the link to be tracked, there will already be an “s object” attached to window from back when the page loaded, so s_gi() will just hand it back.

And that is it.

Contrary to popular belief, s_gi() does not clear all “variables” or otherwise modify the “s object”.

So why do so many sites use s_gi() in their link tracking?

Good question!

In cases where a page is initially not tracked, maybe because the visitor clicks before the tracking has a chance to fire, there might be a race condition and the “s object” might not be ready. Yes, it could happen, but it is sort of unlikely.

I think this is one of those cases where at some point, documentation was written and people followed it. Since everything worked, noone questioned the documentation or the implementation. It became part of “Omniture folklore”, so to speak.

But Adobe Consulting are in recent times omitting it. I guess the days of this particular part of the Omniture legacy are numbered.

s.sa()

Sometimes, you might want to track page loads into one report suites and (some) links or actions into another one.

Do you need a new “s object” for those links? Can you even have more than one “s object” active at a given time?

No, you don’t have to, but yes, you can.

Sometimes sites will be double-tagged — say with an old version of tracking code and a new, fresh one in parallel during a transition period — and the way to achieve that is to rename one of the two objects. This would normally been done in the s_code.js file, most likely by an Adobe consultant.

On your pages, you would then refer to those by their different names, say “s” and “s_legacy”.

More likely, though, you will use the s.sa() method to just change the report suite ID for the next tracking call. Much easier and will almost always do the trick.

Just call s.sa() with the report suite ID(s) that you want to use for the next call, before you call s.tl(), like so:

	s.events="event21,event22";
	s.prop31=s.eVar31="Link Tracking White Paper";
	s.eVar32=page_name;
	s.eVar33="+1";
	s.linkTrackVars="events,prop31,eVar31,eVar32,eVar33";
	s.linkTrackEvents="event21,event22";
	s.sa("YOUR_NEW_RSID");
	s.tl(this,"d","Link Tracking White Paper");

So what about all the “variables” that have been set earlier?

Well, for starters, s.tl() will only transmit those “variables” that are referenced in s.linkTrackVars and s.linkTrackEvents. As an example, s.pageName will not be sent in the example above, even though it will have a value in the “s object” at the time when s.tl() is called.

Secondly, if you use a “variable” both on page load and in link/action tracking and it sometimes should be empty for the latter, make sure you manually clear it by setting it to an empty string.


Filed under: Javascript, Opinion, Page Code Tagged: javascript, report suite, s_code.js

2 Good Reasons to use Context Data

$
0
0

My colleague Carl Sandquist recently wrote “Although you may get a bit teary-eyed bid­ding farewell to expound­ing on the dif­fer­ences of eVars and props to your devel­op­ers, we’re sure you’ll even­tu­ally get over it.”

He’s obviously right about this: developers will shed no tears if they never have to see props or eVars ever again.

So let’s start the new year with a couple of notes about Context Data Variables.

Name Spaces

With Context Data, you can name space your data.

In the world of online tracking and optimisation, a “Data Layer” is the current state of art. It works a treat with tag management. It is one step towards separation of form and function. It is a good idea.

If you put a lot of meta data into the data layer, you will at some point run into issues with naming the data. Name spacing can help. An example:

The term “section” could describe the site section that a page belongs to. It could also be a section of the actual page, e.g. the header or the left navigation bar.

If you track page load, you would send the “section” that describes where the page sits in the site. On tracking a link click, however, you would send the “section” that specifies where the link was on the page.

If you create name spaces, you can use “section” in both situations and there will be no confusion. Call the former “site.section” and the latter “page.section” or maybe “template.section”.

Context Data supports name spacing, so you can assign a variable like this:

	s.contextData['template.section'] = "left nav";

On a retail site, you could have a name space for the product(s) you are displaying on the page. News web sites could use it for data persisting to the authors.

The great part for you, the developer, is that the data layer is likely your project and therefore totally under your control! I am sure you will have to build it up to support some marketing needs, but how you do it will be your decision. And since most developers are comfortable with name spaces in some form or shape, it shouldn’t be too hard for you to use them.

One word of caution: look at Carl’s screenshot of how it all looks like in a debugger…

[Screenshot]

Context Data in the URL

You can see that the individual data items are encapsulated between two short URL parameters which act as a “name space on” and “name space off” pair. If your name space is called “page”, you would have one URL parameter called “page.” before your data and one called “.page” after it.

So, hold back on the length of your name space designations! You might otherwise run into issues with browsers not sending any tracking because the URL of the GET request is too long. Older IEs are notorious for this.

Maybe call it “tm” instead of “template”, and “p” instead of “page”. Make sure your marketer still has a list of what your name spaces mean! They are the ones who have to map the data to props and eVars!

Consolidation

Carl mentions this at the end of his posting, but I think it deserves more space: Context Data is great when you have a lot of (regional) report suites and you want to standardise, be it for multi-suite tagging or just because.

Let me explain the problem.

Suppose your company is running retail sites in two markets, say the US and the UK. Both markets have individual marketing teams, and both sites have in the past been tagged up with Adobe Analytics.

Unless the teams worked together and had similar goals and similar maturity, it is likely that the tagging on the two sites is not identical. The US site might store page section in s.prop2 while the UK site puts it into s.channel.

Now leadership has decided that they want to roll out to more countries. And they want a global view as well.

One way of creating a global view is to use multi-suite tracking, which basically means sending data to more than one report suite. (This can easily be done by listing more than one report suite ID (or “rsid”) in the s_account variable in the configuration section of the s_code.js file.)

Each individual site will be set up to track into an individual report suite plus a global report suite that is the same for all sites.

Now here’s the issue: because the UK and US sites do not use the same “variables” for the same data, the global report suite has mixed data in some reports. Not nice, not pretty, and certainly not useful.

Changing the implementation of either the UK or the US site would deal with this, but the changed site would in essence loose their historical data, or rather the continuity. If your friendly marketer wanted to see a report about site sections, she’d have to check one report for the time before the changes and another one for the time after. This is of course totally impractical.

But you can still do it, using Context Data!

The idea is to switch tracking on one (or both) sites to Context Data instead of the traditional props and eVars.

Your friendly marketer has to set up Processing Rules to get the data into the right reports, but the point is that those rules are report suite specific and she can therefore set up rules on the UK report suite that match the old tracking and at the same time set up rules on the global report suite that match the new, standardised tracking!

The up side is that continuity is assured for the UK and at the same time the global report suite gets clean data.

You can easily see that for the rollout to the other sites, it makes sense to start straight with Context Data as well, of course.


Filed under: AppMeasurement, Javascript, Page Code, Principles, Tips Tagged: context data, debug, eVar, processing rules, prop, report suite, s_code.js

Cohort Analysis

$
0
0

Just like you have editors, debuggers, profilers, libraries, frameworks and other things, your friendly marketer has a bag of tools that they use to do their job. One of these tools is the so-called “cohort-analysis”.

Cohorts

Think about the people coming to your web site. When your friendly marketer ran that facebook competition, she attracted a lot of people who had never been to the site before (“first time visitors”).

Your marketer will be very interested in seeing what those new visitors are up to, so it makes sense to look at them as a group! Your marketer calls those groups “cohorts”.

A couple of weeks or months down the line, she will look at the “January facebook iPad competition” cohort, or maybe the “christmas 2012 first time buyers” cohort. She will want to know whether they ever came back to the site, whether they bought more, consumed more content, engaged, or whatever your key goals for the site are.

She will compare a cohort with the rest of the visitors to see whether specific marketing activity nurtured valuable leads or brought new, valuable customers.

All of this is very important for her, so if you know how to collect data for a cohort analysis, you will make her very happy.

Implementation

In principle, implementing for cohort analysis is very straight-forward. All you need is a way to retain the original first date.

But there is one issue: original first date of what?

Let’s look at one example and come back to that question. So, let’s assume our friendly marketer is interested in cohorts of first time visitors she managed to attract via her different marketing efforts, her campaigns.

The cohort is directly linked to these campaigns and to the first time the people come to the site. In order to pull a report or build a segment that covers the “January facebook iPad competition” cohort, we must know when our visitors came to the site for the first time, and maybe whether they came from that campaign.

We therefore need to store the data of the first visit and make it available for reporting.

Luckily, conversion variables (“eVars”) have a setting that makes this really easy: set allocation to “Original Value (First)”.

[Screenshot]

eVar Settings for Cohort Analysis

What that does is show the first ever value that was passed into that eVar in reports, no matter what was passed in later.

In essence, you can just put a timestamp into that eVar on every hit. The system will make sure that only the first one will be reported on.

How exactly you pass a timestamp into the eVar is up to you. On this blog I just use “YYYY/MM/DD”, which means the report looks like this:

[Screenshot]

Raw Cohort Report

Of course you will use SAINT classifications to make the report easier to read and understand. I just aggregate into months, years and weekdays, but for your marketer, you should also create a classification that assigns dates to campaigns.

[Screenshot]

Classifications for Cohort Analysis

Pulling the classified report will hopefully lead to some answers or more questions, like in my case:

[Screenshot]

Classified Cohort Report

Like: what is it with those 16 people who came in March? I think that is easy: I’m one of them. And what about the searches? 24% were done by people who started reading the blog in November 2011? That’s odd.

People who started seeing in June 2013 saw an average of 3 pages, which is half a page more than almost everyone else!

There is some potential for research there, I’d say.

Notes

Back to the question raised above: which date do you capture?

The first visit is not the only important event in the customer life cycle! It makes a lot of sense to look at cohorts based on others, like first sign-up, first order, first installation of app, first comment posted, or others.

The easy answer is that for every date that your marketer would want to build a cohort for, you need one eVar.

The system provides up to 75 eVars for each report suite (we’ll explain what that is in more depth next week), and you will use some of these for other stuff, so it is impractical to do more than a handful of cohort dates.

That handful will already be extremely useful for your marketer, though. Just make sure you discuss them with her first. You want to track the relevant ones.


Filed under: Principles, Tips Tagged: campaigns, eVar, facebook, javascript, plugins, s_code.js

Multi-Suite Tracking & Report Suites

$
0
0

Short post today to explain two things that have been mentioned on this blog a couple of times but never really explained. Bad blog!

“Report Suite”

The concept “report suite” is pretty important in Adobe Analytics. I have mentioned it a lot but only ever gone into a little bit of detail in the post about the configuration section of the s_code.js file. Let’s go deeper.

As mentioned, a report suite is sort of a separate data storage. While it is not a database, strictly speaking, you can think of a report suite almost as if it was. It is an isolated storage space for your data.

Each report suite has settings that are independent of all other report suites. Some of the things your friendly marketer sees in the interface are attached to the report suite, for example “Bookmarks”, “Schedules” or even the menu structure and semantics of the different “variables”.

It makes sense to think of a report suite as a completely independent tracking environment.

As a user of Adobe Analytics, you can have as many of these as you need.

A lot of people use one report suite per market (country or region), or maybe one for the desktop site and another one for mobile.

Whether you track different sites or apps into a single report suite or separate ones depends on two factors:

  1. People — who is looking at the data? Who should be able to see it? Example: If you have a marketing team per market, it makes sense to have a report suite per market to mirror that.
  2. Site goals / functionality — two sites that do vastly different things should not be tracked into the same report suite. Example: the goals for your investor relations site are likely totally different from those for your B2C site. The tracking should follow the goals and because the configuration of the tracking is specific to the report suite, you should have different report suites here.

The people aspect is often overlooked, but I think it is the more important aspect here. Why? Because data only makes sense if the right people see it. And those people should see exactly the data that matters to them, no more, no less.

“Multi-Suite Tagging”

Very simply put, multi-suite tagging allows you to send the same tracking data to more than one report suite.

Why would you do that?

Again it comes down to people, and the right data for the right person.

If your company is structured hierarchically (chances are it is, unless you work for Zappos, of course), then there will be teams responsible for regions or other parts of the business. Those teams or individuals need data relevant for their remit.

There will also likely be someone responsible across regions or business units. That someone also needs relevant data, but that data obviously includes multiple regions or units.

So one web site (say the retail site for Belgium) may send tracking data into a specific report suite. But it may also send data into an over-arching report suite for EMEA, or maybe one for all retail.

That is called multi-suite tagging or sometimes multi-suite tracking.

How?

Real easy: just add the additional report suite ID (“rsid”) to the s_account variable in the configuration section of the s_code.js file, separated with comma.

Make sure you have no extra spaces!

That’s it.

Really.

You can check whether you’ve done it right by looking at the URL of the tracking call that your browser makes. If you can see your list of rsids then everything should be good.

[Screenshot]

Finding the Report Suite ID

Alternatives

If you don’t want multi-suite tracking or for some reason you can’t do it, there are 2 alternatives: rollups and VISTA Rules.

Let’s start with VISTA Rules, because the effect is pretty much the same as with multi-suite tagging.

The only difference, really, is that instead of putting multiple report suite IDs into s_account, you ask Adobe to do it for you in the back end.

Now the big drawback here is that you pay for creating that VISTA Rule, while doing it yourself only costs your time.

But depending on how development works in your team, it might be valid and/or faster to use the VISTA Rule rather than changing the s_code.js file.

The other alternative is to use rollup report suite(s).

They work slightly differently, so depending on what your friendly marketer needs they might or might not be the way to go.

A rollup is configured in the back end. It “contains” two or more report suites. Every day at midnight, all data from the previous day is “copied” over into the rollup.

The differences, from your marketers’ point of view are:

  • Data is one day behind in rollup vs. real-time with multi-suite tagging
  • Rollups are free, multi-suite incurs secondary server calls
  • Data in rollups is just added up whereas with multi-suite, metrics like Visits or Visitors are deduplicated

The last one needs some explanation, I think.

Imagine I read an article on “Blog A” and one on “Blog B”. Both are tracked and on both my interactions will show up as 1 Page View, 1 Visit and 1 Visitor. Per site, of course.

Now if both “Blog A” and “Blog B” are tagged to track into a common report suite, looking at this common data I would see 2 Page Views, but still 1 Visitor. We call that deduplication, and multi-suite tagging can do it, while rollups can not.

Whether deduplication is important for your marketer or not depends largely on the sites they are looking at and whether visitors are supposed or likely to hop between those sites.


Filed under: Principles Tagged: multi-suite, report suite, s_code.js

Internal URL Filters

$
0
0

Your friendly marketer is interested in the beginning and the end of a visitor’s visit. She wants to know where they came from, how long they were around, how many pages they saw and so on.

How do we technically determine those two important moments?

The Beginning of a Visit

Let’s look at the start first. (D’uh. Obviously.)

HTTP is a stateless protocol, so how do we know that a request for a specific page is the first in a visit?

Well, we sort of don’t. But we can use two mechanisms to help:

  1. Time — if there was a previous request from “the same person”, “not too long ago”, then we guess this is not the first request. More on time later when we look at the end of a visit.
  2. The HTTP Referer header — the HTTP Referer tells us where the browser came from, allowing us to see whether it was our own site or another.

Funny enough, those methods are anything but water-tight. But that doesn’t mean our friendly marketer wouldn’t want ot use them. She still wants to know where people came from when they enter your site, and the HTTP Referer is a good place to start.

One problem: since there is an HTTP Referer on every GET, we’d in most cases see our own site at the top of any list! So we need to add the concept of an “internal URL”, a URL that belogs to our site and should therefore not be considered an external link.

You can tell Adobe Analytics which URLs are considered internal. Go to the Report Suite Manager under Admin Tools. Select one or more report suite(s), then go to Edit Settings > General > Internal URL Filters.

[Screenshot]

Menu for Internal URL

You can now add one or more URLs that the system should treat as internal.

Note: those URLs can be complete URLs or just parts. The system will simply match what you typed to the URL in the HTTP Referer header.

[Screenshot]

Internal URL Settings

To make one thing perfectly clear: this setting only applies to visit starts! That means: reports like Referring Domains, Search, everything under Traffic Sources, basically.

Visit Endings

The end of a visit is even harder to detect than the beginning. Technically, nothing happens when a visit ends, at least nothing that our web server would get any wind of.

A visitor might close the tab or their browser. They might switch off their machine or close it. They might run out of battery or move into an area that has no network. They might even leave their machine at their desk and go for lunch or have a chat.

Some of that might be detectable, but web analytics vendors have at some point looked at all those scenarios and decided “nah, let’s work with a timeout. 30 minutes? Sounds great, let’s do it!” So it became an industry standard.

The actual timeout happens in the processing steps in the backend. The frontend (Javascript) has nothing to do with the timeout at all. Which makes sense, because why would you waste a server call?

So the timeout doesn’t really concern you as a developer, and that’s probably a good thing.

People clicking a link off site does, though. If on your site there are links that point to others, your marketer will want to know about visitors going there.

Fortunately, tracking this is really easy. In fact, it is almost out-of-the-box. All you have to do is configure it in the configuration section of the s_code.js file.

[Screenshot]

s_code – configuration section part 1

Citing from the original article:

Exit links are links on your site that transport the visitor off the site and somewhere else. Two variables configure how Adobe Analytics treats these links:

  • s.linkInternalFilters defines all URLs that are considered internal, therefore allowing the code to see which links are not.
  • s.trackExternalLinks controls whether the code should automatically track those or not.

The list in s.linkInternalFilters is a list of substrings of URLs which will be matched against the href parameter of any link clicked on the page. If the URL does not match, the system tracks the click as an “Exit Link”.

Fun fact: if you put a “.” into s.linkInternalFilters, the Javascript code will basically treat the whole Internet as internal. You will therefore not see any exit links in the reporting. Good for a development site with changing URLs, bad for production.

In essence, the decision about whether a link is external and should therefore be tracked has to be made in Javascript because if it should be tracked, well, it has to be tracked. It’s the browser that must send the tracking call, which means that the decision has to be made in the browser.

Notes

You might have noticed that the two settings are only loosely related to the beginning and the end of a visit. Bonus points for that.

As we said: your marketer likely doesn’t care that much. He might not even understand the difference. But he definitely wants to know where people came from and whether they clicked any off-site links. And that you can find out with the help of the two settings we discussed.

I think it goes without saying that the URLs in both places should be the same. There is only very few use cases for having different URLs, in fact I can think of none.

We should also mention a special case: off-site payment systems.

If in your checkout process, your site directs people to paypal or any other payment site before receiving them back for some confirmation page, make sure you add the URL of your payment provider to both places!


Filed under: Javascript, Principles Tagged: internal urls, javascript, s_code.js
Viewing all 46 articles
Browse latest View live