A fel­low Site­Cat­a­lyst user recently asked me via Twit­ter how best to man­age deploy­ment on mul­ti­ple sites. Many com­pa­nies oper­ate sev­eral dis­tinct web sites; con­sider a firm that owns mul­ti­ple brands. If I own BrandA and BrandB, the odds are that each of these brands will have its own site.

This can become prob­lem­atic as the num­ber of sites you’re man­ag­ing increases. Let’s say Omni­ture intro­duces new func­tion­al­ity in the core JavaScript file (s_code.js). Now imag­ine that you’re man­ag­ing 500 sites, each with its own imple­men­ta­tion and JavaScript file. Sud­denly, if you want to upgrade to the lat­est release, you may need to make 500 sep­a­rate updates. This can ruin your entire month.

Gen­er­ally speak­ing, with a few major excep­tions (dis­cussed below), we have found that using a sin­gle, global JavaScript file across all sites is tremen­dously advan­ta­geous in cases such as these.

As one Omni­ture con­sul­tant man­ag­ing the imple­men­ta­tion for a large inter­na­tional brand told me, “This is exactly what we did for [cus­tomer]. Now, if we release a new fea­ture in the JavaScript code, I can have it up and run­ning for [cus­tomer], world­wide, after test­ing, in about five min­utes.” When you com­pare that to the amount of time required to roll out a sim­i­lar change across dozens or hun­dreds of sites, each with its own s_code.js file, it’s utterly minuscule.

At the same time, using a sin­gle JavaScript file across sites may require sig­nif­i­cant fore­thought and a solid strat­egy dur­ing ini­tial imple­men­ta­tion (or re-implementation). A poten­tial prob­lem with using a sin­gle JavaScript file across mul­ti­ple sites is that dif­fer­ent sites may use vari­ables dif­fer­ently. Cer­tainly, the s_account vari­able (which stores the des­ti­na­tion report suite ID), will likely change from one site to another. But the s.linkInternalFilters vari­able (which con­trols exit link track­ing), s.trackingServer (first-party cookie data col­lec­tion domains), and other vari­ables may need to be pop­u­lated dynam­i­cally based on the domain or some other site-specific criteria.

Many vari­ables, such as those men­tioned above, are com­mon to all imple­men­ta­tions and report suites; every site will need an s.linkInternalFilters value. But what hap­pens when one report suite uses eVar1 to store inter­nal search key­words and another suite uses eVar20 for this same pur­pose? How can you ensure that each site passes the data into the cor­rect vari­able for that par­tic­u­lar site?

The prefer­able option here is to stan­dard­ize vari­able usage across sites and report suites as much as pos­si­ble. Even though var­i­ous sites may have diverse KPIs, there are likely items that you will want to track across all sites. Cam­paigns pro­vides a com­mon, if sim­plis­tic, exam­ple. Plan in advance so that all of your sites will use s.campaign to track exter­nal cam­paigns and, say, eVar7 to track inter­nal cam­paigns. Where query para­me­ters are involved, use the same query para­me­ter to store track­ing codes in your URLs across all sites (for exam­ple, “cid=”).

Where this isn’t pos­si­ble, I’ll show in the exam­ple below how you can fairly eas­ily ensure that vari­ables are pop­u­lated dif­fer­ently and cor­rectly based on the domain (or some other criteria).

Exam­ple

Let’s con­sider BrandA​.com and BrandB​.com, both owned by the same com­pany. It would be great if both brands used a sin­gle 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 prop­er­ties. To do this, you would have a sin­gle s_code.js file hosted some­where acces­si­ble to both sites. Within the file, you would detect the domain that the user hap­pens to be on (either branda​.com or brandb​.com), and then set s_account accord­ingly. 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 sim­i­lar things to set any other vari­ables dynam­i­cally based on the domain of the site being accessed. For exam­ple, you would also need to set the s.linkInternalFilters vari­able 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 man­age have already been imple­mented, and already use the same vari­ables in dif­fer­ent ways. In that case, you can use the same logic just described to change the way that these vari­ables 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 num­ber of vari­ables being used for dif­fer­ent pur­poses across report suites, con­sider pop­u­lat­ing them on page itself, rather than in the global JavaScript file. Vari­ables, once allo­cated for a spe­cific report­ing pur­pose, are not likely to be reap­por­tioned fre­quently, so putting them on pages typ­i­cally will not require a bunch of main­te­nance. This also helps to keep the size of the global JavaScript file under control.

Why you would not use a sin­gle JavaScript include

I’ve spo­ken to a num­ber of mem­bers of the Omni­ture Con­sult­ing team, and all agreed that the solu­tion described above is ideal in many cases. There are a cou­ple of rea­sons why you might not want to han­dle mul­ti­ple sites this way:

  • Imag­ine that you work for con­sul­tancy that man­ages the Site­Cat­a­lyst imple­men­ta­tion and report­ing for a wide array of its own cus­tomers. Since these cus­tomers are dis­tinct enti­ties, each will have its own site to man­age. How­ever, you may not want Cus­tomer A to see all of the specifics of Cus­tomer B’s imple­men­ta­tion. In these cases, you may need to use sep­a­rate JavaScript files for busi­ness reasons.
  • Host­ing a global JavaScript file in one place means that all of your sites will be hit­ting a sin­gle server to retrieve it. This can dra­mat­i­cally increase the demands on that server, poten­tially affect­ing site per­for­mance if the num­ber of page views across all sites is large enough. This will vary from com­pany to com­pany and from server to server, so unfor­tu­nately I can’t sug­gest a num­ber of page views at which point this would become problematic.
  • If the num­ber of sites that you are man­ag­ing is small enough—say, two or three—it might be enough work to set up the dynamic pop­u­la­tion of vari­ables that it’s eas­ier just to main­tain sep­a­rate files.

Con­clu­sion

For me to believe that a blog post could answer all of your ques­tions on this topic would be pre­sump­tu­ous in the extreme, but I hope this dis­cus­sion at least gets the wheels turn­ing at your orga­ni­za­tion if you’re fac­ing this sort of a sit­u­a­tion and don’t know how to han­dle it. I hope it’s clear that the sug­ges­tion to use a sin­gle, global JavaScript file isn’t nec­es­sar­ily for every­one, but that in many cases it can make man­ag­ing a Site­Cat­a­lyst imple­men­ta­tion mul­ti­ple sites much easier.

As always, please feel free to shoot any questions/tips/suggestions to me by leav­ing a com­ment on this post, via Twit­ter (@OmnitureCare), or by e-mail (omniturecare@​omniture.​com). I always enjoy hear­ing 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!