Hi,
We have a Drupal site spanning quite a few domains (http://www.vetspace.org.nz). The content on each site is different, but it's the same Drupal instance powering them.
Your module doesn't seem to support clicking across to other domains while preserving the GA session (http://www.google.com/support/analytics/bin/answer.py?hl=en&answer=55503), so I've provided a patch against the latest development copy of the Drupal 5 version. It should be trivial to port it forward to D6 too if you want.
It works by providing an optional config item to specify a list of domains that are still local, and if this is set, it turns off cross-domain cookie setting and captures link click requests and passed them to the pageTracker object (via _link()) for handling.
This is also closely related to #132650: Ability to track multiple domains that resolve to the same site, a D6 version of this issue that you marked wontfix. I believe that issue was going in a slightly different direction though.
My patch also fixes a bug on your current development copy that prevents the link event handler from being attached, as jQuery.ready() passes an instance of jQuery as the 'context' argument to gaTrackerAttach, which gets used as the context, and doesn't work.
Feedback on how I've accomplished this is welcome.
Thanks
| Comment | File | Size | Author |
|---|---|---|---|
| #50 | ga_D7_cross_domain3.patch | 11.56 KB | hass |
| googleanalytics-multidomain.patch | 4.11 KB | neilnz |
Comments
Comment #1
hass commentedI've already thought about this functionality, but I think it should have no configuration options. I thought this should work as google analytics themself does. If someone adds
_setDomainName()to the custom JS field we should make sure this works automatically. If this is the case I see no real need to add another UI config option.Also don't forget that we could have a wildcard domain like:
This seems to be wrong:
Comment #2
neilnz commentedThe javascript still somehow needs to know a list of domains that are local to call _link() the links for. That's all the UI does. This could also be implemented by offering up a hook in the module so another module can provide a domain list, eg. using the domain module, which is already integrated with singlesignon.
And yes, if you're just using subdomains, something like pageTracker._setDomainName(".example.com") would work nicely, but in my case the domains are .com's, .org's, .org.nz's etc, for different organisations. They just happen to be served up by a single Drupal instance. This patch would also be applicable if you had another site that wasn't powered by Drupal (or was powered by a different Drupal), as you could still list the domains in the settings and it would link out to those other site with the correct tracking code.
I would've just used the custom javascript box if the requirements were as simple as those two lines, but it needs proper support in googleanalytics.js to call _link(), which is the whole point of this patch.
As for patching the ready() function, I'd welcome suggestions on a better way to do it. By passing null to gaTrackerAttach, it defaults to using document, which is correct for the initial load. If you just let jQuery.ready() call it, it gets passed a function reference for jQuery as the context, and no events get bound at all.
Comment #3
hass commentedYour code hardcodes the _setDomainName() value to "none". This is incorrect. It needs to be dynamic to be general for the module code. For example, if you add
pageTracker._setDomainName("none");to before code snippet, the googleanalytics.js can see this variables and do appropriate actions, Maybe one action is to addpageTracker._setAllowLinker(true);dynamically - not sure. Otherwise if someone configurespageTracker._setDomainName(".example.com");the JS code in googleanalytics.js may do other actions, but this needs to be dynamic from what the user configures in "before" snippet textarea. Hope this makes the requirements clear.The ready() function and how it attaches events is taken from other modules and all looking the same like today. Take a look to project, and others. Aside it works for me - not sure what should be wrong here.
Comment #4
neilnz commentedSure, I agree it makes good sense to set the automatic code before the manual overrides, because someone may want a hybrid approach (subdomains and external domains). I can make that change. It's possible I shouldn't mess with the default 'auto' value at all, since I don't think it would make a different to linking out to other domains. I just put it there because that's what the GA help page said, and because it made sense for my situation of entirely external domains.
The _setAllowLinker(true) is required to accept incoming tracker codes from other domains, so is a bit more important to set. It should possibly be manually configurable on its own though, as there may be cases where a site should accept incoming tracker codes from other domains but will not be making any outgoing tracked links. How about we make it a checkbox "Allow incoming tracking sessions from other domains" and make it automatically select if multiple domains are somehow specified?
Comment #5
hass commentedIf possible I don't like to add more configurable options to the UI... if not possible without UI - ok, but every UI change adds new strings and needs to be translated and supported and let me say - what you are doing seems not very common for the masses, but otherwise it cannot be wrong to have it implemented and I also need this in near future! For such special requirements we have build the "before" code snippet. Only to note - over 15.000 known installations and you are the first who request this functionality... :-)
I would be happy if this feature would be implemented such easy to configure like google allows you to configure this functionality - with only two static configuration lines. All other stuff should automatically be done - that's great and I think we can also do this based on the two config lines.
Comment #6
neilnz commentedI understand that... It is an advanced feature, but I thought that was what the "advanced" section of the UI was for ;)
If you like, this functionality could be provided by an additional "contrib" module (either distributed with or without the googleanalytics module). All that would be required is maybe a hook to add more GA javascript, although that could also be done simply using drupal_add_js() and ensuring the contrib module is weighted after googleanalytics.module (since it requires the pageTracker object to exist)... Using this approach a second javascript file would need to be included that also listens for link clicks and does the _link() call where appropriate.
If it was a separate module, it may not need to have a UI, since installing it would activate it, and it could then use a hook to the domains module to discover the list of domains.
I'm not the first person to request the exact functionality my patch performs though - ArjanLikesDrupal was asking for it over on #132650: Ability to track multiple domains that resolve to the same site just last month. So that's at least 2 out of 15,000 people that want it - 0.01%! I believe that if you have a feature, people will use it, if you don't, not many would bother to ask for it, especially if they can't write patches.
Comment #7
hass commentedNo, I wouldn't add it into an extra module. That would be totally overkill. Try to integrate it as written above. Make the integration as easy as possible and reuse google analytics api configuration options. I'm not refusing your request... I'd only like to integrate it such EASY as google does this themself. That's all what we should do here. Don't overcomplicate things for users... no idea why you need an UI if google don't need this.
Comment #8
neilnz commentedGoogle don't specify how you decide which domains. From their page:
Of course in Drupal with jQuery we have a better way than adding onclick= to every link.
I'd be happy to automate this so it just "discovers" the list of domains and doesn't present a UI at all. The only case where this would cause complications is if they have a non-Drupal site (or a site under a different Drupal) that they would like to persist tracking sessions to. For instance if someone has a Drupal site and a Moodle site, and they want to use the same GA code on both, and they're on different domains, this isn't possible using just domains module integration, as domains module wouldn't know about the Moodle domain. This applies to my situation (I do have a Moodle on a different domain with the same GA code), and my patch allows for that with a manually configurable domains list. If I create this patch to use the domains module, I'll still have to run a custom-patched GA module to keep this functionality. Maybe it should call both the domains module hook and a custom hook, eg. hook_googleanalytics_domains(), so another module could provide additional domains as well?
So in terms of configuring pageTracker, have we decided that it shouldn't apply the
_setDomainName()call at all (leave this as an option for the user to paste into the custom JS box), but we should apply_setAllowLinker(true)by default before the custom script is applied (and hence overridable)? Or did you want that as a UI checkbox option to allow external tracking codes? We shouldn't make the user manually paste that into the JS box, as they wouldn't know they need to when using multiple domains...Comment #9
clint.davis commentedIm also interested that some movement goes ahead with this as well.
Subscribing.
Comment #10
hass commentedMarked #373262: Wrong position of pageTracker = _gat._getTracker as a duplicate.
Comment #11
hass commentedMarked #376166: Tracking multiple domains as a duplicate.
Comment #12
hass commentedComment #13
hass commented@neilnz: We should get the remaining bugs in the patch fixed and get this in soon...
Comment #14
neilnz commentedI'm not working on this at the moment - I was waiting on some confirmation of how you'd like this done before I changed my patch... I'm happy to spend some time working on this though.
My question again:
Note that approach would require an FAQ on how to enable this kind of behaviour, including instructions on making inter-site links call the _link function (as my jQuery did in the original pach).
Comment #15
hass commentedSorry, but I do not really understand you... :-(.
From my review of the gaAPI docs I think we need to implement the following:
1. Catch click on links and execute
_link().2. Catch form submits and execute
_linkByPost().3.
_setDomainName()should allow "auto" | "none" | [domain]. Maybe add a selectbox with "auto", "none" and "domain list" item and the "domain list" makes a input field visible where users are able to add the domain name - or we detect this from current hostname!? I expect that we are not able to solve this detection in 100% of all cases correctly. Some people like to add a full hostname and others a wildcard domain name. So this needs to be a free text field or we add items like "current domain as wildcard (.example.com)" and "current hostname (www.example.com)". For sure this needs a good description text and some basic validation.4.
_setAllowLinker()needs to be implemented.5. Use as few setting as possible and try to make it nerd save by using good validation :-). I don't like to get any question about this feature in the issue queue... it need to be absolutely self explanatory.
All this needs to be as easy as possible to configure... I'm not yet sure how
_setDomainName('auto')works... I need to investigate.Comment #16
aaron1234nz commentedHi Guys,
Take a look at this thread,
http://www.google.com/support/forum/p/Google+Analytics/thread?tid=2069ea...
this is the behavior experienced using the patch supplied by neilnz. It makes for a lot of pretty awful looking URLS. I'm not too familiar with the gaAPI but I expect that if cookie information is transferred between domains then this behavior cant be avoided.
Comment #17
owen barton commentedI think http://code.google.com/apis/analytics/docs/tracking/gaTrackingSite.html has some good examples for how this can be done cleanly.
Comment #18
krlucas commentedNote that if you have segmentation enabled, pageTracker._setVar() still runs before "Code Before".
Therefore, if you include pageTracker._setDomainName("none"); in Code Before it will essentially be ignored--the setVar method call apparently initializes the cookie domain for all subsequent pageTracker method calls in that pageView.
To test:
Enable segmentation for user roles.
Add
to Code Before
Visit the site as an anonymous user. The setVar call for segmentation won't happen because you're not logged in. The GA cookies are set with the FQDN (www.mydomain.com) -- expected behavior for cross domain tracking.
Log in. A new set of GA cookies is set with the wild card DN (.mydomain.com) -- as if pageTracker._setDomainName("none"); had not been called.
Calling _setVar after the _setDomainName call seems to solve this.
Comment #19
hass commentedWhy should the domain of your cookies change if you log in? Sounds like your site is not configured properly.
Comment #20
icenogle commentedkrlucas is right. I just tried his experiment and looked at the page source.
Comment #21
hass commentedSomeone interested in providing a patch for the next release?
Comment #22
webdrips commentedSubscribing
Comment #23
turadg commented+1 subscribe
Comment #24
hass commentedComment #25
sittard commentedSubscribing +1
Comment #26
jaxpax commentedSubscribing +1
Comment #27
csc4 commentedSubscribing
Comment #28
jaxpax commentedHave somebody done any work on this lately?
Comment #29
bleen commentedSubscribing
Comment #30
sanderc commentedHow is the status on this? I face the same problem: multiple domains using one Drupal installation. The Google Analytics code seems to track only one of the domains. Am I right that tracking of multiple domains is not implemented yet?
Comment #31
bleen commentedIn case this helps anyone ...
under admin/settings/googleanalytics we added the following under "Advanced Settings"->"Custom JavaScript Code"...
BEFORE
AFTER
note: I'm actually using a slight variation of this on my site (relying on some site-specific stuff) so test this thoroughly..
IMPORTANT UPDATE: if you use this code AND have any links on your site that load content AJAXically you need to make sure that those links are accounted for. If you dont, the AJAXically loaded content will suddenly take over your whole page. Example: if you use quicktabs then this line:
if(this.href.match(domain)){will need to be something like this:
if(this.href.match(domain) && !this.href.match('quicktabs')){ANOTHER UPDATE:
Suggestion from #48 below... you might want the "AFTER" js to read:
Comment #32
jaxpax commented@Bleen18 You're da bomb! =)
Comment #33
guysaban commentedGoogle now offers the option of multi-domain tracking [which is also useful for i18n websites that use sub-domains for languages (see that option in the i18n module) like en.example.com, de.example.com, etc.].
Google tracker:
Comment #34
hass commented@bleen18: Thank you for sharing your example. Hopefully it helps someone. I believe the Ajax stuff can be solved by binding to body. See latest DEV.
Something like this (fully untested)
For now I'm moving this to D7 as it seems easier to solve as in D6. I guess it will never backported. I wonder that your code works as I thought from the google docs that all tracker code need to be added into the header and we are not able to do this in D6 from hook_footer().
Comment #35
bleen commented@hass
can you point me to the google documentation that you're referring to?
Comment #36
hass commentedIn past the google docs said you can add the normal tracker code to the header and footer (recommended), but if _link() is used you must add it to the header or at least before the first _link() call.
Comment #37
hass commentedFound it http://www.google.com/support/googleanalytics/bin/answer.py?hl=en&answer...
Comment #38
bleen commented@hass .. In #31 my analytics code is above my link() calls. I have my link() calls in the "after" section, meaning "after the analytics code"
right?
Comment #39
Jay Adan commentedWould this go in the settings for the top level domain and all sub-domains - or just the top-level domain settings?
Comment #40
bleen commented@jayaden .. all domains
Comment #41
AlexisWilke commentedHi guys,
There is an option in Google Analytics, when you create a new entry for a domain, that says "multiple top-level domains"
When you select that option, you get the following JavaScript:
So it looks like this is correct as hass mentioned in an earlier post. From what I can tell, that code should never be a problem for users with multiple domains.
Thank you.
Alexis
Comment #42
johnpitcairn commentedsubscribe
Comment #43
bleen commentedre #41 ... take a look at steps 2 & 3 here: http://www.google.com/support/analytics/bin/answer.py?hl=en&answer=55503
... this needs some love too for multi-domain analytics to work correctly
Comment #44
AlexisWilke commentedAh! That would explain why I saw no difference...
I'm testing point 4. of http://www.google.com/support/analytics/bin/answer.py?hl=en&answer=55503
I'll see whether the filter has an effect, so far it changed nothing to the output...
That filtering system is quite powerful!
Thank you.
Alexis
Comment #45
AlexisWilke commentedBtw,
I added the following:
to the Code snippet (before): in the Advanced settings / Custom JavaScript code.
Hope that helps. If you make it work, let us know! 8-)
Thank you.
Alexis
Comment #46
bleen commentedAlexisWilke ... check out #31
Comment #47
AlexisWilke commentedHi guys,
Good news! It works. Just did not have time to check back here for a little while.
If you had the old method first, you will still see the old entries and they won't be merged... So that means you will have counts that go a bit funky for a month or so.
My setup on my website is simply to add the following in the Code snippet (before) text area (in field set Advanced settings » Custom JavaScript code)
Then, as mentioned by bleen18 in #43 and me in #44, I followed step 4 to create the perfect filter on GoogleAnalytics:
http://www.google.com/support/analytics/bin/answer.py?hl=en&answer=55503
That part is rather complicated, to my point of view. You have to go to the main screen and click "edit" on the domain you're interested in. There click on "Add Filter". Give it a name and choose "Advanced".
For Field A, choose Hostname and enter (.*) as the pattern.
For Field B, choose Request URI and enter (.*) as the pattern.
For Output, choose Request URI and enter $A1$B1
Say Yes to everything except case insensitive if you're on Linux.
Wait a few days, then go to your analytics report and enter a domain name in the search below, for me I entered www.m2osw.com and secure.m2osw.com to see each separate (and I'm happy to see I don't get very many hits on the secure side which means I don't use that much processing time to encrypt data.)
Hope this helps.
Thank you.
Alexis Wilke
Comment #48
chrisdfeld commentedThanks for this. One important correction to the JavaScript in comment #31 above:
AFTER
Comment #49
hass commentedCommitted completely reworked code to D7.
Comment #50
hass commentedHere is the committed D7 patch.
The above shared code for BEFORE and AFTER have some real issues. I strongly suggest you to add at least a
break;into the "for" or the loop will not end after a match (waste of time of you have many cross domains) and only after the list has been looped to the end. I guess it is much faster to change to a regex, like I've done in D7. Additionally there is currently no regex escaping in place what will cause matches for "a.com" if the URL have something inside like "aXcom". Every char will match for the dot. It would also be better if there would be a no protocol check in the beginning. Maybe some of you have an URL like "http://example.com?ref=a.com". This will currently cause a false match, as this is not a cross domain of your sites.This may be some edge cases, but keep this in mind as the code is not stable.
Comment #51
hass commentedI guess we are not able to backport this D7 patch. As documented in http://www.google.com/support/analytics/bin/answer.py?answer=55503 we cannot do the
_linkthis stuff reliable from footer for the reason ofTherefore it get's a WON'T FIX for D6. :-(
Comment #52
hass commentedLet's show the D7 issue in queue for the next 2 weeks.
Comment #53
nvanhove commentedThis method gives a error on every page when clicking on a link
Error: text is undefined
Source File: http://nsh.cad.drupaldev/sites/default/modules/contrib/google_analytics/...
Line: 11
Fixed the errormsg by using
Comment #54
nvanhove commentedComment #55
hass commentedDo you know how to repro?
Comment #56
magnusk commentedI have the same problem as nvanhove, Firefox reporting that "text is undefined". (Not sure this belongs in this issue?)
I've set the JS to be included in the footer, no header. Single domain tracking. I think all other settings left as they come by default.
Comment #57
hass commentedChanged the line for now to: