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!

  • http://www.xm-asia.com Yuhui

    The s_account switcheroo was exactly what we used for one client — but to iden­tify whether the domain was on the stag­ing or pro­duc­tion site. So your exam­ple need not apply to mul­ti­ple brands, but even the same brand with dif­fer­ent host­ing environments.

    • http://blogs.omniture.com/author/bgaines Ben Gaines

      Ooooooh, good point. It’s a quick way to make sure you don’t have to bother chang­ing s_account when you move from envi­ron­ment to envi­ron­ment. I likes it!

  • http://immeria.net S.Hamel

    Thanks Ben for this timely post! I’ve been look­ing into the chal­lenge of multi-site tag­ging. In a way, I think you might be over­sim­pli­fy­ing the amount of work and all the impli­ca­tions of using a sin­gle JavaScript file. Take into account devel­op­ment or pro­duc­tion envi­ron­ments for 500 web­sites are likely to be devel­oped by dif­fer­ent teams, using dif­fer­ent tech­nolo­gies, with dif­fer­ent lev­els of web ana­lyt­ics matu­rity and devel­op­ment cycles. You touches on stan­dard­iza­tion of props & evars, but this quickly becomes a night­mare con­sid­er­ing the num­ber of stake­hold­ers involved. Also, what about nam­ing con­ven­tions (for page­Name, chan­nel, props & evar val­ues, etc.). Long story short, it’s a night­mare that goes far beyond the tech­ni­cal dif­fi­cul­ties of tagging.

    Per­son­ally, I pre­fer to keep s_code.js as close to the orig­i­nal code pro­vided out of the box by SC and use my own per-site .js file. At best, I could poten­tially put s_code.js cen­trally, but because of the above con­sid­er­a­tions, the end result is usu­ally a per-site approach. At least, hav­ing a cen­tral­ized team to man­age all site tags makes it a lot easier.

    I’m cur­rently work­ing on a con­cept called JITT: Just-In-Time Tag­ging, more info at http://​imme​ria​.net/​j​i​tt/

    Stéphane

    • http://blogs.omniture.com/author/bgaines Ben Gaines

      Stephane: Great com­ment! As I sug­gested in the post, using a sin­gle JS file isn’t for every­one. Cer­tainly, there are plenty of orga­ni­za­tions out there that will have sites too dif­fer­ent (for the rea­sons you men­tioned) to make this fea­si­ble. But oth­ers may oper­ate sev­eral sites that have the same KPIs, and using a sin­gle JS file can be a tremen­dous boon for them. As with all of the rec­om­men­da­tions I make on this blog, the reader shouldn’t take it as doc­trine but rather as food for thought.

  • http://sun.comx100 Neil Evans

    We use Omni­ture on over 100 sites and now use sim­i­lar solu­tion and were required to for a num­ber of rea­sons:
    – We wanted to move to 1st party cook­ies. This required a simul­ta­ne­ous JS update.
    – We wanted to upgrade to H code
    – We wanted to be able to update the code glob­ally so we could intro­duce new func­tion­al­ity on all sites.

    The way we do it is each site uses a small Omni­ture con­fig­u­ra­tion file which in turn calls a Mas­ter Omni­ture JS.

    The local JS will hold any site spe­cific set­tings, while the Mas­ter JS con­tains all the com­mon func­tion­al­ity that Omni­ture requires.

    So http://​www​.sun​.com/​j​s​/​s​_​c​o​d​e​_​r​e​m​o​t​e​.js is the local con­fig file which calls the mas­ter JS file that resides on a con­tent deliv­ery network.

    http://​www​-cdn​.sun​.com/​s​h​a​r​e​/​m​e​t​r​i​c​s​/​m​e​t​r​i​c​s​_​g​r​o​u​p​1​.js is the Mas­ter JS file.

    Some things that help:
    Pop­u­late a sprop with the ver­sion num­ber in the Mas­ter JS file. This allows us to see the adop­tion & caching out of the pre­vi­ous ver­sion of the file.

    Install a reset func­tion so that you can over-ride the com­mon func­tion­al­ity such as page nam­ing, chan­nels that you have in the Mas­ter JS.

    Install pre & post plu­gin func­tions so you can over-ride the default func­tion­al­ity in the Mas­ter JS.

    Note: http://​www​.sun​.com/​j​s​/​s​_​c​o​d​e​_​r​e​m​o​t​e​.js actu­ally quite a bit of code. To see the local JS file in its clean­est form look at: http://​java​.sun​.com/​j​s​/​o​m​i​/​j​s​c​/​s​_​c​o​d​e​_​r​e​m​o​t​e​.js

    All we set is:
    1) Data rout­ing via sun_dynamicAccountList then pass­ing that into s.dynamicAccountList in the Mas­ter JS by:

    s.dynamicAccountList=sun_dynamicAccountList;

    2) A site ID. We use this as a prepend to the page­Names in the Mas­ter JS.

    3) The call to Mas­ter JS file.

  • Danielle Reisch

    The domain/account solu­tion has a lot of flaws to it. There are sev­eral rea­sons why the document.domain may not be what you expected:
    –The user is using Google trans­late (document.domain is trans​late​.google​.com)
    –The user pulled a doc­u­ment via Google cache
    –The user is access­ing your infor­ma­tion via a url-based proxy that does not use your orig­i­nal doc­u­ment domain. (Libproxy typ­i­cally pre­serves your domain and append’s the library’s proxy URL, but we’ve observed other prox­ies that do not.)

    What this could ulti­mately result in is the line
    var s=s_gi(s_account)
    caus­ing a JavaScript error, since s_account is not defined. I believe that would also cause errors for any remain­ing lines that rely on s being defined.

    At the very least, I’d rec­om­mend set­ting s_account first to your global/rollup/development account and then try­ing to con­di­tion­ally update its value.

    • http://blogs.omniture.com/author/bgaines Ben Gaines

      I can cer­tainly agree with that. The prin­ci­ple holds, but your exe­cu­tion is far better.