A fellow SiteCatalyst user recently asked me via Twitter how best to manage deployment on multiple sites. Many companies operate several distinct web sites; consider a firm that owns multiple brands. If I own BrandA and BrandB, the odds are that each of these brands will have its own site.

This can become problematic as the number of sites you’re managing increases. Let’s say Omniture introduces new functionality in the core JavaScript file (s_code.js). Now imagine that you’re managing 500 sites, each with its own implementation and JavaScript file. Suddenly, if you want to upgrade to the latest release, you may need to make 500 separate updates. This can ruin your entire month.

Generally speaking, with a few major exceptions (discussed below), we have found that using a single, global JavaScript file across all sites is tremendously advantageous in cases such as these.

As one Omniture consultant managing the implementation for a large international brand told me, “This is exactly what we did for [customer]. Now, if we release a new feature in the JavaScript code, I can have it up and running for [customer], worldwide, after testing, in about five minutes.” When you compare that to the amount of time required to roll out a similar change across dozens or hundreds of sites, each with its own s_code.js file, it’s utterly minuscule.

At the same time, using a single JavaScript file across sites may require significant forethought and a solid strategy during initial implementation (or re-implementation). A potential problem with using a single JavaScript file across multiple sites is that different sites may use variables differently. Certainly, the s_account variable (which stores the destination report suite ID), will likely change from one site to another. But the s.linkInternalFilters variable (which controls exit link tracking), s.trackingServer (first-party cookie data collection domains), and other variables may need to be populated dynamically based on the domain or some other site-specific criteria.

Many variables, such as those mentioned above, are common to all implementations and report suites; every site will need an s.linkInternalFilters value. But what happens when one report suite uses eVar1 to store internal search keywords and another suite uses eVar20 for this same purpose? How can you ensure that each site passes the data into the correct variable for that particular site?

The preferable option here is to standardize variable usage across sites and report suites as much as possible. Even though various sites may have diverse KPIs, there are likely items that you will want to track across all sites. Campaigns provides a common, if simplistic, example. Plan in advance so that all of your sites will use s.campaign to track external campaigns and, say, eVar7 to track internal campaigns. Where query parameters are involved, use the same query parameter to store tracking codes in your URLs across all sites (for example, “cid=”).

Where this isn’t possible, I’ll show in the example below how you can fairly easily ensure that variables are populated differently and correctly based on the domain (or some other criteria).

Example

Let’s consider BrandA.com and BrandB.com, both owned by the same company. It would be great if both brands used a single JavaScript file; that way, when you need to make a change, you can do it one place, one time, and then it’s done across all of your properties. To do this, you would have a single s_code.js file hosted somewhere accessible to both sites. Within the file, you would detect the domain that the user happens to be on (either branda.com or brandb.com), and then set s_account accordingly. For example:

// set report suite ID dynamically based on domain
if(document.domain.indexOf('branda.com') > -1) {
     var s_account = 'brandacom'
} else if(document.domain.indexOf('brandb.com' > -1) {
     var s_account = 'brandbcom'
}

And you can do similar things to set any other variables dynamically based on the domain of the site being accessed. For example, you would also need to set the s.linkInternalFilters variable in much the same manner.

// set s.linkInternalFilters dynamically based on domain
if(document.domain.indexOf('branda.com') > -1) {
     s.linkInternalFilters = 'javascript:,brandacom'
} else if(document.domain.indexOf('brandb.com' > -1) {
     s.linkInternalFilters = 'javascript:,brandbcom'
}

It may be that the sites you manage have already been implemented, and already use the same variables in different ways. In that case, you can use the same logic just described to change the way that these variables are used

// populate the internal search keywords into various eVars depending on report suite
if(s_account == 'brandacom') {
     s.eVar1=s.getQueryParam('kw');
} else if(s_account == 'brandbcom') {
     s.eVar23=s.getQueryParam('keyword');
     s.prop5=s.getQueryParam('keyword');
}

Where there is a large number of variables being used for different purposes across report suites, consider populating them on page itself, rather than in the global JavaScript file. Variables, once allocated for a specific reporting purpose, are not likely to be reapportioned frequently, so putting them on pages typically will not require a bunch of maintenance. This also helps to keep the size of the global JavaScript file under control.

Why you would not use a single JavaScript include

I’ve spoken to a number of members of the Omniture Consulting team, and all agreed that the solution described above is ideal in many cases. There are a couple of reasons why you might not want to handle multiple sites this way:

  • Imagine that you work for consultancy that manages the SiteCatalyst implementation and reporting for a wide array of its own customers. Since these customers are distinct entities, each will have its own site to manage. However, you may not want Customer A to see all of the specifics of Customer B’s implementation. In these cases, you may need to use separate JavaScript files for business reasons.
  • Hosting a global JavaScript file in one place means that all of your sites will be hitting a single server to retrieve it. This can dramatically increase the demands on that server, potentially affecting site performance if the number of page views across all sites is large enough. This will vary from company to company and from server to server, so unfortunately I can’t suggest a number of page views at which point this would become problematic.
  • If the number of sites that you are managing is small enough—say, two or three—it might be enough work to set up the dynamic population of variables that it’s easier just to maintain separate files.

Conclusion

For me to believe that a blog post could answer all of your questions on this topic would be presumptuous in the extreme, but I hope this discussion at least gets the wheels turning at your organization if you’re facing this sort of a situation and don’t know how to handle it. I hope it’s clear that the suggestion to use a single, global JavaScript file isn’t necessarily for everyone, but that in many cases it can make managing a SiteCatalyst implementation multiple sites much easier.

As always, please feel free to shoot any questions/tips/suggestions to me by leaving a comment on this post, via Twitter (@OmnitureCare), or by e-mail (omniturecare@omniture.com). I always enjoy hearing from you!

7 comments
Danielle Reisch
Danielle Reisch

The domain/account solution has a lot of flaws to it. There are several reasons why the document.domain may not be what you expected: -The user is using Google translate (document.domain is translate.google.com) -The user pulled a document via Google cache -The user is accessing your information via a url-based proxy that does not use your original document domain. (Libproxy typically preserves your domain and append's the library's proxy URL, but we've observed other proxies that do not.) What this could ultimately result in is the line var s=s_gi(s_account) causing a JavaScript error, since s_account is not defined. I believe that would also cause errors for any remaining lines that rely on s being defined. At the very least, I'd recommend setting s_account first to your global/rollup/development account and then trying to conditionally update its value.

Neil Evans
Neil Evans

We use Omniture on over 100 sites and now use similar solution and were required to for a number of reasons: - We wanted to move to 1st party cookies. This required a simultaneous JS update. - We wanted to upgrade to H code - We wanted to be able to update the code globally so we could introduce new functionality on all sites. The way we do it is each site uses a small Omniture configuration file which in turn calls a Master Omniture JS. The local JS will hold any site specific settings, while the Master JS contains all the common functionality that Omniture requires. So http://www.sun.com/js/s_code_remote.js is the local config file which calls the master JS file that resides on a content delivery network. http://www-cdn.sun.com/share/metrics/metrics_group1.js is the Master JS file. Some things that help: Populate a sprop with the version number in the Master JS file. This allows us to see the adoption & caching out of the previous version of the file. Install a reset function so that you can over-ride the common functionality such as page naming, channels that you have in the Master JS. Install pre & post plugin functions so you can over-ride the default functionality in the Master JS. Note: http://www.sun.com/js/s_code_remote.js actually quite a bit of code. To see the local JS file in its cleanest form look at: http://java.sun.com/js/omi/jsc/s_code_remote.js All we set is: 1) Data routing via sun_dynamicAccountList then passing that into s.dynamicAccountList in the Master JS by: s.dynamicAccountList=sun_dynamicAccountList; 2) A site ID. We use this as a prepend to the pageNames in the Master JS. 3) The call to Master JS file.

S.Hamel
S.Hamel

Thanks Ben for this timely post! I've been looking into the challenge of multi-site tagging. In a way, I think you might be oversimplifying the amount of work and all the implications of using a single JavaScript file. Take into account development or production environments for 500 websites are likely to be developed by different teams, using different technologies, with different levels of web analytics maturity and development cycles. You touches on standardization of props & evars, but this quickly becomes a nightmare considering the number of stakeholders involved. Also, what about naming conventions (for pageName, channel, props & evar values, etc.). Long story short, it's a nightmare that goes far beyond the technical difficulties of tagging. Personally, I prefer to keep s_code.js as close to the original code provided out of the box by SC and use my own per-site .js file. At best, I could potentially put s_code.js centrally, but because of the above considerations, the end result is usually a per-site approach. At least, having a centralized team to manage all site tags makes it a lot easier. I'm currently working on a concept called JITT: Just-In-Time Tagging, more info at http://immeria.net/jitt/ Stéphane

Yuhui
Yuhui

The s_account switcheroo was exactly what we used for one client -- but to identify whether the domain was on the staging or production site. So your example need not apply to multiple brands, but even the same brand with different hosting environments.

Ben Gaines
Ben Gaines

I can certainly agree with that. The principle holds, but your execution is far better.

Ben Gaines
Ben Gaines

Stephane: Great comment! As I suggested in the post, using a single JS file isn't for everyone. Certainly, there are plenty of organizations out there that will have sites too different (for the reasons you mentioned) to make this feasible. But others may operate several sites that have the same KPIs, and using a single JS file can be a tremendous boon for them. As with all of the recommendations I make on this blog, the reader shouldn't take it as doctrine but rather as food for thought.

Ben Gaines
Ben Gaines

Ooooooh, good point. It's a quick way to make sure you don't have to bother changing s_account when you move from environment to environment. I likes it!