Coder Social home page Coder Social logo

universal-analytics's Introduction

universal-analytics

Setting up a new property in Google Analytics? follow these instructions to get your UA-xxxx code.
https://support.google.com/analytics/answer/9304153#UA

A node module for Google's Universal Analytics tracking via the Measurement Protocol.

This module allows tracking data (or rather, users) from within a Node.js application. Tracking is initiated on the server side and, if required, does not require any more tracking in the browser.

npm version Build Status

Table of Contents

Getting started

universal-analytics is installed and included like any other node module:

$ npm install universal-analytics
var ua = require('universal-analytics');

// Or with ES6 import
import ua from 'universal-analytics'

Initialization expects at least your Google Analytics account ID:

var visitor = ua('UA-XXXX-XX');

This will create a universal-analytics Visitor instance that you can use and keep around to track a specific client (Not to be confused with the Google Analytics User ID, see Setting persistent parameters for more information on that). Since no client ID was specified in the constructor's arguments, a random UUID is generated. In case you have a client ID at hand, you can use that to create the visitor:

var visitor = ua('UA-XXXX-XX', '6a14abda-6b12-4578-bf66-43c754eaeda9');

Starting with Universal Analytics, a UUID v4 is the preferred client ID format. It is therefor necessary to provide a UUID of such type to universal-analytics. However you can force custom client ID, passing strictCidFormat: false in the options:

var visitor = ua('UA-XXXX-XX', 'CUSTOM_CLIENTID_1', { strictCidFormat: false });

If you want to force the HTTP protocol instead of HTTPS, include http: true in the options, by default this module will use https:

var visitor = ua('UA-XXXX-XX', { http: true });

If you want to set User Id you can add it into options:

var visitor = ua('UA-XXXX-XX', { uid: 'as8eknlll'});

see about User Id

Tracking a pageview without much else is now very simple:

visitor.pageview("/").send()

The first argument for the pageview method is the path of the page to be tracked. Simply calling pageview() will not initiate a tracking request. In order to send off tracking to the Google Analytics servers you have two options:

  1. You can append a send() call after pageview(). The tracking request is sent asynchronously. This means you will not receive any confirmation when and if it was successful.
  2. You can provide a callback function to pageview() as an additional, last argument. This callback will be invoked once the tracking request has finished. Any error that occured during the request will be provided to said callback. In that case send() is no longer necessary.

An example of the callback approach:

var visitor = ua('UA-XXXX-XX');
visitor.pageview("/", function (err) {
  // Handle the error if necessary.
  // In case no error is provided you can be sure
  // the request was successfully sent off to Google.
});

Tracking

Pageview tracking

The first argument for the pageview tracking call is the page path. Furthermore, pageview tracking can be improved with the additional parameters to provide the page's hostname and title to Google Analytics. The parameters are provided as arguments after the page path.

visitor.pageview("/", "http://peaksandpies.com", "Welcome").send();

The following snippet is the exact same tracking using a callback. It is always the last argument.

visitor.pageview("/", "http://peaksandpies.com", "Welcome", function (err) {
  // …
});

Depending on how you integrate tracking into your app, you might be more comfortable with providing all the tracking data via a params object to the pageview() method:

visitor.pageview({dp: "/", dt: "Welcome", dh: "http://peaksandpies.com"}).send();

This code has the exact same effect as the one above. dp, dt, and dh (as in 'document path', 'document title' and 'document hostname') are the attribute names used by the Measurement Protocol.

It's mandatory to specify either the page path (dp) or document location (dl). Google Analytics can not track a pageview without a path. To avoid such erroneous requests, universal-analytics will deny pageview() tracking if the required parameters are omitted.

var pagePath = null;

visitor.pageview(pagePath, function (err) {
  // This callback will receive an error
});

The following method signatures are available for the pageview() method of the Visitor instance:

  • Visitor#pageview(path)
  • Visitor#pageview(path, callback)
  • Visitor#pageview(params)
  • Visitor#pageview(params, callback)
  • Visitor#pageview(path, hostname)
  • Visitor#pageview(path, hostname, callback)
  • Visitor#pageview(path, hostname, title)
  • Visitor#pageview(path, hostname, title, callback)

See also: List of acceptable params.

Screenview tracking

Instead of pageviews app will want to track screenviews.

visitor.screenview("Home Screen", "App Name").send()

The following method signatures are available for #screenview:

  • Visitor#screenview(screenName, appName)
  • Visitor#screenview(screenName, appName, callback)
  • Visitor#screenview(screenName, appName, appVersion)
  • Visitor#screenview(screenName, appName, appVersion, callback)
  • Visitor#screenview(screenName, appName, appVersion, appId)
  • Visitor#screenview(screenName, appName, appVersion, appId, callback)
  • Visitor#screenview(screenName, appName, appVersion, appId, appInstallerId)
  • Visitor#screenview(screenName, appName, appVersion, appId, appInstallerId, callback)
  • Visitor#screenview(screenName, appName, appVersion, appId, appInstallerId, params)
  • Visitor#screenview(screenName, appName, appVersion, appId, appInstallerId, params, callback)
  • Visitor#screenview(params)
  • Visitor#screenview(params, callback)

See also: List of acceptable params.

Event tracking

Tracking events with universal-analytics works like pageview tracking, only you have to provide different arguments:

visitor.event("Event Category", "Event Action").send()

This is the most straightforward way to track an event. The event attributes label and value are optional and can be provided if necessary:

visitor.event("Event Category", "Event Action", "…and a label", 42).send()

Just like pageview tracking, event tracking supports a callback as the last argument:

visitor.event("Event Category", "Event Action", "…and a label", 42, function (err) {
  // …
})

An additional attribute for events is the path of the page they should be associated with in Google Analytics. You can provide this path via an additional params object:

visitor.event("Event Category", "Event Action", "…and a label", 42, {p: "/contact"}, function (err) {
  // …
})

Notice: The page path attribute for the event is called p which differs from the dp attribute used in the pageview tracking example. universal-analytics is smart enough to use the dp attribute should you provide it instead of p.

In case this argument list is getting a little long, event() also accepts a params object like pageview():

var params = {
  ec: "Event Category",
  ea: "Event Action",
  el: "…and a label",
  ev: 42,
  dp: "/contact"
}

visitor.event(params).send();

The category (ec) and the action (ea) are mandatory. Google Analytics will not track an event without them. To avoid such erroneous requests, universal-analytics will deny event() tracking if either attribute is omitted.

var action = null;

visitor.event("Navigation clicks", action, function (err) {
  // This callback will receive an error
});

The following method signatures are available for #event:

  • Visitor#event(category, action)
  • Visitor#event(category, action, callback)
  • Visitor#event(category, action, label)
  • Visitor#event(category, action, label, callback)
  • Visitor#event(category, action, label, value)
  • Visitor#event(category, action, label, value, callback)
  • Visitor#event(category, action, label, value, params, callback)
  • Visitor#event(params)
  • Visitor#event(params, callback)

See also: List of acceptable params.

E-commerce tracking

E-commerce tracking in general is a bit more complex. It requires a combination of one call to the transaction() method and one or more calls to the item() method.

visitor
  .transaction("trans-12345", 500)   // Create transaction trans-12345 worth 500 total.
  .item(300, 1, "item-54321")        // Add 1 unit the item item-54321 worth 300.
  .item(200, 2, "item-41325")        // Add 2 units the item item-41325 worth 200.
  .send()

Once again, daisy-chaining simplifies associating the items with the transaction. Officially, nothing but the transaction ID is a requirement for both the transaction and the items. However, providing a minimum set of information (revenue for the transaction, price, quantity and ID for the items) is recommended.

It is also possible to provide the params as an object to both methods:

visitor
  .transaction({ti: "trans-12345", tr: 500, ts: 50, tt: 100, ta: "Partner 13"})
  .item({ip: 300, iq: 1, ic: "item-54321", in: "Item 54321", iv: "Blue"})
  .item({ip: 200, iq: 2, ic: "item-41325", in: "Item 41325", iv: "XXL"})
  .send()

In case an additional item has to be added later on or daisy-chaining is not available for another reason, each item can be given an associated transaction ID via the params object as well:

visitor.item({ip: 100, iq: 1, ic: "item-41325", in: "Item 41325", iv: "XL", ti: "trans-12345"}).send()

The transaction ID (ti) is mandatory for both the transaction and the item. Google Analytics will not track e-commerce data without it. To avoid such erroneous requests, universal-analytics will deny transaction() and item() tracking if it is omitted.

var ti = null;

visitor.transaction(ti, function (err) {
  // This callback will receive an error
});

The following method signatures are available for #transaction:

  • Visitor#transaction(id)
  • Visitor#transaction(id, callback)
  • Visitor#transaction(id, revenue)
  • Visitor#transaction(id, revenue, callback)
  • Visitor#transaction(id, revenue, shipping)
  • Visitor#transaction(id, revenue, shipping, callback)
  • Visitor#transaction(id, revenue, shipping, tax)
  • Visitor#transaction(id, revenue, shipping, tax, callback)
  • Visitor#transaction(id, revenue, shipping, tax, affiliation)
  • Visitor#transaction(id, revenue, shipping, tax, affiliation, callback)
  • Visitor#transaction(params)
  • Visitor#transaction(params, callback)

The following method signatures are available for #item:

  • Visitor#item(price)
  • Visitor#item(price, callback)
  • Visitor#item(price, quantity)
  • Visitor#item(price, quantity, callback)
  • Visitor#item(price, quantity, sku)
  • Visitor#item(price, quantity, sku, callback)
  • Visitor#item(price, quantity, sku, name)
  • Visitor#item(price, quantity, sku, name, callback)
  • Visitor#item(price, quantity, sku, name, variation)
  • Visitor#item(price, quantity, sku, name, variation, callback)
  • Visitor#item(price, quantity, sku, name, variation, params)
  • Visitor#item(price, quantity, sku, name, variation, params, callback)
  • Visitor#item(params)
  • Visitor#item(params, callback)

See also: List of acceptable params.

Exception tracking

Exception tracking is a way to keep track of any sort of application errors and bugs with Google Analytics. Using it with this module is a way to capture server-side problems.

visitor.exception("StackOverflow Error").send()

As an additional information, the exception can be flagged as fatal if the error was exceptionally bad.

var fatal = true;
visitor.exception("StackOverflow Error", fatal, function () {
  // Finish handling this error
});

The following method signatures are available for #exception:

  • Visitor#exception(description)
  • Visitor#exception(description, callback)
  • Visitor#exception(description, fatal)
  • Visitor#exception(description, fatal, callback)
  • Visitor#exception(params)
  • Visitor#exception(params, callback)

See also: List of acceptable params.

User timing tracking

Tracking user timings is a way to capture time-based information similar to the page load speed data tracked automatically by Google Analytics. All arguments to this tracking method are optional, but a category, a variable and a time value should be provided. The time value should be provided in milliseconds.

visitor.timing("User interaction", "Time to open login overlay", 12547).send()

The following method signatures are available for #timing:

  • Visitor#timing(category)
  • Visitor#timing(category, callback)
  • Visitor#timing(category, variable)
  • Visitor#timing(category, variable, callback)
  • Visitor#timing(category, variable, time)
  • Visitor#timing(category, variable, time, callback)
  • Visitor#timing(category, variable, time, label)
  • Visitor#timing(category, variable, time, label, callback)
  • Visitor#timing(params)
  • Visitor#timing(params, callback)

See also: List of acceptable params.

Transaction tracking

Transactions are the main tracking calls for ecommerce tracking

visitor.transaction("123456", "449.99").send()

The following method signatures are available for #transaction:

  • Visitor#transaction(transactionId)
  • Visitor#transaction(transactionId, callback)
  • Visitor#transaction(transactionId, revenue)
  • Visitor#transaction(transactionId, revenue, callback)
  • Visitor#transaction(transactionId, revenue, shippingCost)
  • Visitor#transaction(transactionId, revenue, shippingCost, callback)
  • Visitor#transaction(transactionId, revenue, shippingCost, tax)
  • Visitor#transaction(transactionId, revenue, shippingCost, tax, callback)
  • Visitor#transaction(transactionId, revenue, shippingCost, tax, affiliation)
  • Visitor#transaction(transactionId, revenue, shippingCost, tax, affiliation, callback)
  • Visitor#transaction(transactionId, revenue, shippingCost, tax, affiliation, params)
  • Visitor#transaction(transactionId, revenue, shippingCost, tax, affiliation, params, callback)
  • Visitor#transaction(params)
  • Visitor#transaction(params, callback)

See also: List of acceptable params.

Transaction item tracking

Transaction consist of one or more items.

visitor.item(449.99, 1, "ID54321", "T-Shirt", {ti: "123456"}).send()

The following method signatures are available for #item:

  • Visitor#item(price)
  • Visitor#item(price, callback)
  • Visitor#item(price, quantity)
  • Visitor#item(price, quantity, callback)
  • Visitor#item(price, quantity, sku)
  • Visitor#item(price, quantity, sku, callback)
  • Visitor#item(price, quantity, sku, name)
  • Visitor#item(price, quantity, sku, name, callback)
  • Visitor#item(price, quantity, sku, name, variation)
  • Visitor#item(price, quantity, sku, name, variation, callback)
  • Visitor#item(price, quantity, sku, name, variation, params)
  • Visitor#item(price, quantity, sku, name, variation, params, callback)
  • Visitor#item(params)
  • Visitor#item(params, callback)

See also: List of acceptable params.

Daisy-chaining tracking calls

We have seen basic daisy-chaining above when calling send() right after pageview() and event():

visitor.pageview("/").send()

Every call of a tracking method returns a visitor instance you can re-use:

visitor.pageview("/").pageview("/contact").send()

Granted, the chance of this example actually happening in practice might be rather low.

However, universal-analytics is smart when it comes to daisy-chaining certain calls. In many cases, a pageview() call is instantly followed by an event() call to track some additional information about the current page. universal-analytics makes creating the connection between the two easy:

visitor.pageview("/landing-page-1").event("Testing", "Button color", "Blue").send()

This is the same as two distinct tracking calls.

visitor.pageview("/landing-page-1").send()
visitor.event("Testing", "Button color", "Blue", {p: "/landing-page-1"}).send()

Daisy-chaining is context-aware and in this case placing the event() call right after the pageview() call results in the event being associated with the page path tracking in the pageview() call. Even though the attributes (dp and p) are different internally.

It also works when using a callback since the this inside the callback will be the universal-analytics Visitor instance:

visitor.pageview("/landing-page-1", function (err) {
  if (!err) {
    this.event("Testing", "Button color", "Blue").send()
  }
});

More generally, the daisy-chaining context keeps all parameters from the previous call around. This means in a situation where similar tracking calls are necessary tracking is simplified:

visitor
  .event({ec: "Mail Server", ea: "New Team Member Notification sent"})
  .event({ea: "Invitation sent"})
  .send();

In this example the event category ("Mail Server") is not repeated in the second tracking call.

Setting persistent parameters

Some parameters should be in every tracking call, such as a user ID or custom dimensions that never or hardly change. For such situations a #set(key, value) method is available

  visitor.set("uid", "123456789");

The uid parameter will be part of every tracking request of that visitor from now on.

For custom dimensions, you will not pass dimension# rather cd#:

 visitor.set("cd[1-20]", "123456789"); // [1-20] will be the dimension number

Filter application tracking data

Set a persistent parameter for Data Source to app in order to mark tracking data as Application.

 visitor.set("ds", "app"); // Allows filtering by the 'Application?' field in GA

Then create a new view in Google Analytics of type 'Application'. You will then need to filter the data for that view by creating a new filter that either includes or excludes Application? Yes (depending on if you want to show(includes) or hide(excludes) application analytics in a given view).

Google Analytics Setup

Session-based identification

In order to make session-based apps easier to work with, universal-analytics also provides a middleware that works in an Expressjs-style fashion. It will try to detect a client ID based on the _ga cookie used by the analytics.js client-side tracking. Additionally it will store the detected client ID in the current session to recognize the visitor later.

var ua = require("universal-analytics");
var express = require("express");

var app = express()

express.use(ua.middleware("UA-XXXX-Y", {cookieName: '_ga'}));

The middleware will attach the universal analytics visitor instance to every request with the default name of req.visitor. The name of the instance on the req object can be overridden to avoid name conflicts by passing in instanceName on the options object:

express.use(ua.middleware("UA-XXXX-Y", {instanceName: 'uaVisitor'}));

Additionally, the module also exposes a createFromSession method to create a visitor instance simply based on a session, which is helpful when working with Socket.io, etc. where the middleware is not used.

var visitor = ua.createFromSession(socket.handshake.session);

Debug mode

universal-analytics is using the debug library. It can be instructed to output information during tracking by setting the DEBUG environment variable:

DEBUG=universal-analytics

Request Options

Due to the removal of the request package, request options are no longer available as of 0.5.

Shortcuts

The tracking methods have shortcuts:

  • Visitor#pv as an alias for Visitor#pageview
  • Visitor#e as an alias for Visitor#event
  • Visitor#t as an alias for Visitor#transaction
  • Visitor#i as an alias for Visitor#item

Tests

The tests are written with mocha using should and Sinon.JS.

Run them by executing the following commands in the universal-analytics directory:

$ npm install
$ make test

License

(The MIT License)

Copyright (c) 2017 Peaks & Pies GmbH <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

universal-analytics's People

Contributors

adityapatadia avatar aesopwolf avatar ahmadibrahiim avatar armsteadj1 avatar atkit avatar bbruneau avatar beeman avatar cadwmaster avatar cannawen avatar cheeaun avatar claudebossy avatar davidgwking avatar devsnek avatar dominykas avatar eragonj avatar gfitzy123 avatar johndpope avatar jtillmann avatar lekoaf avatar lukehaas avatar macrauder avatar marcbachmann avatar marto83 avatar maxbbn avatar nayrudin avatar octalmage avatar pioug avatar pirxpilot avatar standy avatar xanderluciano avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

universal-analytics's Issues

fs, net, and tls error

I installed this on my project and have been getting this weird random error. I have verified that removing this npm module is what fixes it. Here's the errors I get.

screen shot 2016-01-24 at 9 37 33 pm

I assume this has to do with some peer dependencies. Any ideas?

Initial Setup

We've been trying to experiment tracking events on an application instead of on a web server. Our first thought was to setup a Mobile Application in Google Analytics. But that didn't seem to work at all. No page view/events were tracked.

After this we simply tried to track using universal-analytics on a fake site created in Google Analytics. This didn't work either until we created a dummy web page with the standard Google Analytics script attached and ran it once in browser after this our tracking events were being tracked in our Node Application.

Is there something obvious we're missing?

User ID not working

The User ID parameter is not working. If I send different events with the same User ID, Google Analytics does not capture the user, even though I configured GA correctly. Any ideas on what is happening?

suggestion: add support for setting custom dimensions?

Hi, I've been trying to implement analytics in my node-webkit module and I noticed that this lib is missing the custom dimension handling.
I was wondering if it is possible to implement this ?
Thanks,
great job with the module!!

Reverse proxy

Does this work even though your server is behind a reverse proxy?

Location detection

For the moment the location in Google analytics doesn't seem to work.
Is there a parameter or some other option to pass the client IP so that the location detection does work?

Counting visitors twice

We're using your library for server side event tracking, and are really enjoying it!

One problem were seeing is "real time" users being counted multiple times. After adding the server side analytics tracking, we're at 3-4x the users we were seeing before adding it.

On the client, we do the standard analytics.js integration:

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXX-Y', 'auto');

And then send events like so:

window.ga('send', {
  hitType: 'event',
  eventCategory: eventName,
  eventAction: eventProperties.interactionType,
});

On the server, we use the middleware like so

app.use(ua.middleware('UA-XXX-Y', { cookieName: '_ga' }));

and then track events via:

req.visitor
  .event({
     ec: event,
     ea: properties.interactionType,
   })
   .send();

One thing we're doing on the client with plans for the future is window.ga('set', 'userId', userId);... but I don't think this should effect the unique visitor count, which I believe is determined by the clientId

User_ID not being set

Hello,

I'm using universal-analytics in my app in Node where I need to track the events by user. I'm using my own unique ID (var visitor = ua('UA-XXXXXXXX-XX', req.user.id, {strictCidFormat: false});) but in my User ID reporting view does not appear any event (not working) nad I can't figure out why...

Thanks for your help ;)

Not accepting full name params in `pageview`

So I'm trying this:

const gaEvent = {
  documentPath: '/',
  documentTitle: 'Welcome',
  documentHostName: 'http://peaksandpies.com' 
};
visitor.pageview(gaEvent, function(err) {
  if (err) console.log('Failed...', err);
});

... and I get Please provide either a page path (dp) or a document location (dl).

It seems the "translation" of the keys is not happening in the pageview method (I see it does in the event).

Is it a known issue, or am I missing something?

Thanks!

Sending Custom Metrics

Hey

I'm trying to send custom metrics to Google Analytics. I set up the metrics on Google Analytics, but the data doesn't show up. I'm trying to send the custom metric data together with an event like this:

var totalUsers = 410;
visitor.event({
    ec: 'Users',
    ea: 'User Signed Up',
    cm1: totalUsers
}, function (err) {
// …
});

cm1 would be my metric with index 1. Is this the correct syntax? Do I need to consider anything else?

Thanks for your help.

Best,
Sandro

Traffic being sent doesn't make sense

I have a node http proxy that redirects all traffic for my APIs, after each call it is sending the data off to google analytics via UA. The problem is that according to Google Analytics, I'm sitting out 600,000 active users in one day. While I would like to believe that my APIs are that popular, I think there is something wrong.

Here is what I am sending:

var visitor = ua(process.env.GOOGLE_ANALYTICS, options.parsedToken.userId, {strictCidFormat: false}); visitor.pageview(options.pageView).send();

Server-side rendering

Hi,

I'm trying to use this lib into an isomorphic React app that is being rendered in the server-side, and when I import the lib with:

import ua from 'universal-analytics'

I get an error in the cookie.js file:

Uncaught Error: Cannot find module "../package.json"

Is it on the roadmap of this lib to make it work on isomorphic environments?

Thanks!

Active users on site always grows

Hey,

I'm using UA to track activity on socket.io.

io.on('connection', function(socket) {
  var visitor = ua(analyticsCode).debug();
  visitor.event("navigation", "connect").send();

  socket.on('CSomeEvent', function(data) {
    visitor.event("navigation", "CSomeEvent");
  });

  socket.on('disconnect', function() {
    visitor.event("navigation", "disconnect").send();
  });
});

Whenever I refresh the page in google analytics real time, I see the number of "active users on site" grow. I'm only getting exactly as many events as I expect, but the total users continues to grow.

How do I tell GA that my user session is done? Do I need to, or is this an artifact of me not using some sort of session - showing 3 unique users in that time slice...

I just want to be sure that I'm not missing something here.

Doesn't seem to work for browsers?

I tried to bundle this into a client-side .js file using webpack but it didn't work. Does this work for browsers, and if not, is there plans to support using this lib in browsers?

Drop redundant underscore and async

I see there is underscore dependency only for _.extend, wich could be replaced with Object.assign. Works since node 4, so its pretty safe
And there is async dependency only for one method: async.whilst, that could be replaced with recursive call

I know that dependencies not so large, but still loads some memory and disk space without any profit. So if you not mind I could make a PR with that

Proxy Support

It would be great if this module would support HTTP proxies.

Since it uses internally the request library this should be possible (by providing a 'proxy' or 'agent' option to the request object). But I don't see the possibility to set it.

There is a requestOptions parameter, but I don't see the location where it is actually used.

Currently the only way to set the proxy is via an environment variable. However, in this case all requests would use the proxy. And in my case only external requests (i.e. requests to servers outside of the farm (like GA)) need the HTTP proxy. Internal requests don't need (and don't work) with the HTTP proxy.

Any suggestions if it is already somehow possible to set the proxy configuration? If not... it would be great if such functionality would be exposed.

Enhanced ecommerce

Starting a discussion sooner, rather than later... We (https://github.com/insidewarehouse) need to have enhanced ecommerce support and so we're going to build it, but I'd also like some input/agreement before we make a PR :)

Google's documentation:

For the most of it, I think we might be able to just copy the ecommerce.js API, i.e. activities and impressions are usually trackable only with event and pageview hit types, so I think it's OK to just create addProduct, addImpression and setAction as methods. Discussion topics:

  • Passing the currency (cu param) - normally it's set on the hit (i.e. via options event or pageview), but I have a feel it should go together with ecommerce data :)
  • Should the 3 new methods live directly as public, or should there be some sort of a namespace? Opt-in in constructor? What if data is added, send() is called, but there are no actual hits set up to be sent?
  • The protocol does allow to track some of the params with all hit types, so an alternative approach would be to add the ecommerce info to the options of the hit itself, e.g. impressionData, productData, actionData properties on the object.

The bigger problem is the transaction type. Documentation says that one should not be sending both - "regular" ecommerce and "enhanced" ecommerce requests (see "Important" section under "Overview"). Enhanced ecommerce also requires an explicit opt-in via admin/settings of the analytics property. Under the "regular" approach, multiple hits with item and one with transaction is sent. Under the enhanced - transaction data can be sent with any hit type, but it can also include "Product data" and "Action data" (with action type purchase I presume). The params for transaction data are the same, though. To summarize:

  • Regular ecommerce sends a transaction hit with multiple optional item hits
  • Enhanced ecommerce can send transaction related params (ID, amounts, currency) with any hit (e.g. pageview, event or transaction itself), but the products are sent as "product data" and also need an "action data" (with purchase action type, albeit there are other action types).

The two approaches are mutually exclusive. Discussion topics:

  • Should there be an exclusive opt-in into "enhanced" ecommerce via constructor? When enhanced=true, the item hit should be disabled, otherwise - any "enhanced" data logging should be disabled.
  • Should we just leave the decision on the consumer itself? The implementation would certainly be easier if all hit methods (event(), pageview(), etc) would just accept the ecommerce data and transform it into correct params (pr0cd0=Member for the custom dimension "0" of the first product) and not care about anything else.

I'll see if I can find out what other libraries in other languages do, but for now - just opening up the discussion.

Errors when running webpack on universal-analytics

Hello,

I have installed universal-analytics correctly, however when I run webpack via npm to build my app, I get the following errors:

./~/universal-analytics/~/request/~/forever-agent/index.js
Module not found: Error: Cannot resolve module 'net' in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/forever-agent
resolve module net in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/forever-agent
  looking for modules in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules
    /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net doesn't exist (module as directory)
    resolve 'file' net in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules
      resolve file
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.json doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.js doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.jsx doesn't exist
  looking for modules in /Users/username/myapp/node_modules/universal-analytics/node_modules
    /Users/username/myapp/node_modules/universal-analytics/node_modules/net doesn't exist (module as directory)
    resolve 'file' net in /Users/username/myapp/node_modules/universal-analytics/node_modules
      resolve file
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net.json doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net.js doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net.jsx doesn't exist
  looking for modules in /Users/username/myapp/src
    /Users/username/myapp/src/net doesn't exist (module as directory)
    resolve 'file' net in /Users/username/myapp/src
      resolve file
        /Users/username/myapp/src/net doesn't exist
        /Users/username/myapp/src/net.json doesn't exist
        /Users/username/myapp/src/net.js doesn't exist
        /Users/username/myapp/src/net.jsx doesn't exist
  looking for modules in /Users/username/myapp/node_modules
    /Users/username/myapp/node_modules/net doesn't exist (module as directory)
    resolve 'file' net in /Users/username/myapp/node_modules
      resolve file
        /Users/username/myapp/node_modules/net doesn't exist
        /Users/username/myapp/node_modules/net.json doesn't exist
        /Users/username/myapp/node_modules/net.js doesn't exist
        /Users/username/myapp/node_modules/net.jsx doesn't exist
  looking for modules in /Users/username/node_modules
    /Users/username/node_modules/net doesn't exist (module as directory)
    resolve 'file' net in /Users/username/node_modules
      resolve file
        /Users/username/node_modules/net doesn't exist
        /Users/username/node_modules/net.json doesn't exist
        /Users/username/node_modules/net.js doesn't exist
        /Users/username/node_modules/net.jsx doesn't exist
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.json]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.js]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.jsx]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net.json]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net.js]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net.jsx]
[/Users/username/myapp/src/net]
[/Users/username/myapp/src/net]
[/Users/username/myapp/src/net.json]
[/Users/username/myapp/src/net.js]
[/Users/username/myapp/src/net.jsx]
[/Users/username/myapp/node_modules/net]
[/Users/username/myapp/node_modules/net]
[/Users/username/myapp/node_modules/net.json]
[/Users/username/myapp/node_modules/net.js]
[/Users/username/myapp/node_modules/net.jsx]
[/Users/username/node_modules/net]
[/Users/username/node_modules/net]
[/Users/username/node_modules/net.json]
[/Users/username/node_modules/net.js]
[/Users/username/node_modules/net.jsx]
 @ ./~/universal-analytics/~/request/~/forever-agent/index.js 6:10-24
./~/universal-analytics/~/request/~/forever-agent/index.js
Module not found: Error: Cannot resolve module 'tls' in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/forever-agent
resolve module tls in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/forever-agent
  looking for modules in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules
    /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls doesn't exist (module as directory)
    resolve 'file' tls in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules
      resolve file
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.json doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.js doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.jsx doesn't exist
  looking for modules in /Users/username/myapp/node_modules/universal-analytics/node_modules
    /Users/username/myapp/node_modules/universal-analytics/node_modules/tls doesn't exist (module as directory)
    resolve 'file' tls in /Users/username/myapp/node_modules/universal-analytics/node_modules
      resolve file
        /Users/username/myapp/node_modules/universal-analytics/node_modules/tls doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/tls.json doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/tls.js doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/tls.jsx doesn't exist
  looking for modules in /Users/username/myapp/src
    /Users/username/myapp/src/tls doesn't exist (module as directory)
    resolve 'file' tls in /Users/username/myapp/src
      resolve file
        /Users/username/myapp/src/tls doesn't exist
        /Users/username/myapp/src/tls.json doesn't exist
        /Users/username/myapp/src/tls.js doesn't exist
        /Users/username/myapp/src/tls.jsx doesn't exist
  looking for modules in /Users/username/myapp/node_modules
    /Users/username/myapp/node_modules/tls doesn't exist (module as directory)
    resolve 'file' tls in /Users/username/myapp/node_modules
      resolve file
        /Users/username/myapp/node_modules/tls doesn't exist
        /Users/username/myapp/node_modules/tls.json doesn't exist
        /Users/username/myapp/node_modules/tls.js doesn't exist
        /Users/username/myapp/node_modules/tls.jsx doesn't exist
  looking for modules in /Users/username/node_modules
    /Users/username/node_modules/tls doesn't exist (module as directory)
    resolve 'file' tls in /Users/username/node_modules
      resolve file
        /Users/username/node_modules/tls doesn't exist
        /Users/username/node_modules/tls.json doesn't exist
        /Users/username/node_modules/tls.js doesn't exist
        /Users/username/node_modules/tls.jsx doesn't exist
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.json]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.js]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.jsx]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/tls]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/tls]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/tls.json]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/tls.js]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/tls.jsx]
[/Users/username/myapp/src/tls]
[/Users/username/myapp/src/tls]
[/Users/username/myapp/src/tls.json]
[/Users/username/myapp/src/tls.js]
[/Users/username/myapp/src/tls.jsx]
[/Users/username/myapp/node_modules/tls]
[/Users/username/myapp/node_modules/tls]
[/Users/username/myapp/node_modules/tls.json]
[/Users/username/myapp/node_modules/tls.js]
[/Users/username/myapp/node_modules/tls.jsx]
[/Users/username/node_modules/tls]
[/Users/username/node_modules/tls]
[/Users/username/node_modules/tls.json]
[/Users/username/node_modules/tls.js]
[/Users/username/node_modules/tls.jsx]
 @ ./~/universal-analytics/~/request/~/forever-agent/index.js 7:10-24
./~/universal-analytics/~/request/~/tough-cookie/lib/cookie.js
Module not found: Error: Cannot resolve module 'net' in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tough-cookie/lib
resolve module net in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tough-cookie/lib
  looking for modules in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules
    resolve 'file' net in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules
      resolve file
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.json doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.js doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.jsx doesn't exist
    /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net doesn't exist (module as directory)
  looking for modules in /Users/username/myapp/node_modules/universal-analytics/node_modules
    resolve 'file' net in /Users/username/myapp/node_modules/universal-analytics/node_modules
      resolve file
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net.json doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net.js doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net.jsx doesn't exist
    /Users/username/myapp/node_modules/universal-analytics/node_modules/net doesn't exist (module as directory)
  looking for modules in /Users/username/myapp/src
    resolve 'file' net in /Users/username/myapp/src
      resolve file
        /Users/username/myapp/src/net doesn't exist
        /Users/username/myapp/src/net.json doesn't exist
        /Users/username/myapp/src/net.js doesn't exist
        /Users/username/myapp/src/net.jsx doesn't exist
    /Users/username/myapp/src/net doesn't exist (module as directory)
  looking for modules in /Users/username/myapp/node_modules
    resolve 'file' net in /Users/username/myapp/node_modules
      resolve file
        /Users/username/myapp/node_modules/net doesn't exist
        /Users/username/myapp/node_modules/net.json doesn't exist
        /Users/username/myapp/node_modules/net.js doesn't exist
        /Users/username/myapp/node_modules/net.jsx doesn't exist
    /Users/username/myapp/node_modules/net doesn't exist (module as directory)
  looking for modules in /Users/username/node_modules
    resolve 'file' net in /Users/username/node_modules
      resolve file
        /Users/username/node_modules/net doesn't exist
        /Users/username/node_modules/net.json doesn't exist
        /Users/username/node_modules/net.js doesn't exist
        /Users/username/node_modules/net.jsx doesn't exist
    /Users/username/node_modules/net doesn't exist (module as directory)
[/Users/username/lots
a/node_modules/universal-analytics/node_modules/request/node_modules/net]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.json]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.js]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.jsx]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net.json]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net.js]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net.jsx]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net]
[/Users/username/myapp/src/net]
[/Users/username/myapp/src/net.json]
[/Users/username/myapp/src/net.js]
[/Users/username/myapp/src/net.jsx]
[/Users/username/myapp/src/net]
[/Users/username/myapp/node_modules/net]
[/Users/username/myapp/node_modules/net.json]
[/Users/username/myapp/node_modules/net.js]
[/Users/username/myapp/node_modules/net.jsx]
[/Users/username/myapp/node_modules/net]
[/Users/username/node_modules/net]
[/Users/username/node_modules/net.json]
[/Users/username/node_modules/net.js]
[/Users/username/node_modules/net.jsx]
[/Users/username/node_modules/net]
 @ ./~/universal-analytics/~/request/~/tough-cookie/lib/cookie.js 32:10-24
./~/universal-analytics/~/request/~/tunnel-agent/index.js
Module not found: Error: Cannot resolve module 'net' in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tunnel-agent
resolve module net in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tunnel-agent
  looking for modules in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules
    resolve 'file' net in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules
      resolve file
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.json doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.js doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.jsx doesn't exist
    /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net doesn't exist (module as directory)
  looking for modules in /Users/username/myapp/node_modules/universal-analytics/node_modules
    resolve 'file' net in /Users/username/myapp/node_modules/universal-analytics/node_modules
      resolve file
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net.json doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net.js doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/net.jsx doesn't exist
    /Users/username/myapp/node_modules/universal-analytics/node_modules/net doesn't exist (module as directory)
  looking for modules in /Users/username/myapp/src
    resolve 'file' net in /Users/username/myapp/src
      resolve file
        /Users/username/myapp/src/net doesn't exist
        /Users/username/myapp/src/net.json doesn't exist
        /Users/username/myapp/src/net.js doesn't exist
        /Users/username/myapp/src/net.jsx doesn't exist
    /Users/username/myapp/src/net doesn't exist (module as directory)
  looking for modules in /Users/username/myapp/node_modules
    resolve 'file' net in /Users/username/myapp/node_modules
      resolve file
        /Users/username/myapp/node_modules/net doesn't exist
        /Users/username/myapp/node_modules/net.json doesn't exist
        /Users/username/myapp/node_modules/net.js doesn't exist
        /Users/username/myapp/node_modules/net.jsx doesn't exist
    /Users/username/myapp/node_modules/net doesn't exist (module as directory)
  looking for modules in /Users/username/node_modules
    resolve 'file' net in /Users/username/node_modules
      resolve file
        /Users/username/node_modules/net doesn't exist
        /Users/username/node_modules/net.json doesn't exist
        /Users/username/node_modules/net.js doesn't exist
        /Users/username/node_modules/net.jsx doesn't exist
    /Users/username/node_modules/net doesn't exist (module as directory)
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.json]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.js]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net.jsx]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/net]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net.json]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net.js]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net.jsx]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/net]
[/Users/username/myapp/src/net]
[/Users/username/myapp/src/net.json]
[/Users/username/myapp/src/net.js]
[/Users/username/myapp/src/net.jsx]
[/Users/username/myapp/src/net]
[/Users/username/myapp/node_modules/net]
[/Users/username/myapp/node_modules/net.json]
[/Users/username/myapp/node_modules/net.js]
[/Users/username/myapp/node_modules/net.jsx]
[/Users/username/myapp/node_modules/net]
[/Users/username/node_modules/net]
[/Users/username/node_modules/net.json]
[/Users/username/node_modules/net.js]
[/Users/username/node_modules/net.jsx]
[/Users/username/node_modules/net]
 @ ./~/universal-analytics/~/request/~/tunnel-agent/index.js 3:10-24
./~/universal-analytics/~/request/~/tunnel-agent/index.js
Module not found: Error: Cannot resolve module 'tls' in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tunnel-agent
resolve module tls in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tunnel-agent
  looking for modules in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules
    resolve 'file' tls in /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules
      resolve file
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.json doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.js doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.jsx doesn't exist
    /Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls doesn't exist (module as directory)
  looking for modules in /Users/username/myapp/node_modules/universal-analytics/node_modules
    resolve 'file' tls in /Users/username/myapp/node_modules/universal-analytics/node_modules
      resolve file
        /Users/username/myapp/node_modules/universal-analytics/node_modules/tls doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/tls.json doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/tls.js doesn't exist
        /Users/username/myapp/node_modules/universal-analytics/node_modules/tls.jsx doesn't exist
    /Users/username/myapp/node_modules/universal-analytics/node_modules/tls doesn't exist (module as directory)
  looking for modules in /Users/username/myapp/src
    resolve 'file' tls in /Users/username/myapp/src
      resolve file
        /Users/username/myapp/src/tls doesn't exist
        /Users/username/myapp/src/tls.json doesn't exist
        /Users/username/myapp/src/tls.js doesn't exist
        /Users/username/myapp/src/tls.jsx doesn't exist
    /Users/username/myapp/src/tls doesn't exist (module as directory)
  looking for modules in /Users/username/myapp/node_modules
    resolve 'file' tls in /Users/username/myapp/node_modules
      resolve file
        /Users/username/myapp/node_modules/tls doesn't exist
        /Users/username/myapp/node_modules/tls.json doesn't exist
        /Users/username/myapp/node_modules/tls.js doesn't exist
        /Users/username/myapp/node_modules/tls.jsx doesn't exist
    /Users/username/myapp/node_modules/tls doesn't exist (module as directory)
  looking for modules in /Users/username/node_modules
    resolve 'file' tls in /Users/username/node_modules
      resolve file
        /Users/username/node_modules/tls doesn't exist
        /Users/username/node_modules/tls.json doesn't exist
        /Users/username/node_modules/tls.js doesn't exist
        /Users/username/node_modules/tls.jsx doesn't exist
    /Users/username/node_modules/tls doesn't exist (module as directory)
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.json]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.js]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls.jsx]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/request/node_modules/tls]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/tls]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/tls.json]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/tls.js]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/tls.jsx]
[/Users/username/myapp/node_modules/universal-analytics/node_modules/tls]
[/Users/username/myapp/src/tls]
[/Users/username/myapp/src/tls.json]
[/Users/username/myapp/src/tls.js]
[/Users/username/myapp/src/tls.jsx]
[/Users/username/myapp/src/tls]
[/Users/username/myapp/node_modules/tls]
[/Users/username/myapp/node_modules/tls.json]
[/Users/username/myapp/node_modules/tls.js]
[/Users/username/myapp/node_modules/tls.jsx]
[/Users/username/myapp/node_modules/tls]
[/Users/username/node_modules/tls]
[/Users/username/node_modules/tls.json]
[/Users/username/node_modules/tls.js]
[/Users/username/node_modules/tls.jsx]
[/Users/username/node_modules/tls]
 @ ./~/universal-analytics/~/request/~/tunnel-agent/index.js 4:10-24

It seems like it's not finding all of the supporting packages. Any ideas why I might be getting these?

Google Analytics is interpreting a single session as new sessions

Hi,

I'm using this lib in my React project to track page views and components events.

In resume this is how I'm using it:

import ua from 'universal-analytics'

// inside the component constructor
ua(GOOGLE_ANALYTICS_CODE, {https: true}).pageview("/").send()

The problem is that, when I refresh the page that runs this code, Google Analytics seems to count my refresh as a new session. Take a look at this recording:

session issue

Is it a bug of universal-analytics lib? Or am I doing something wrong?

Why is 'p' parameter used for events, not 'dp'?

UA currently converts a passed 'dp' parameter to 'p', before sending the event to GA. As far as I can tell from reading the measurement protocol reference, the 'p' parameter means nothing to Google Analytics but 'dp' can be applied to any pageview, event etc as the page path where the pageview, event etc occurred. Why is UA changing this and throwing out useful data? Because of this, all events in GA that are created with UA appear to have come from '(not set)' path, rather than the path provided when calling visitor.event(...).

Like my previous issue report, I can change this in a pull request if desired, but I'm interested why the choice was made to send an apparently nonsense parameter to GA at the expense of a legitimate parameter?

Express & universal-analytics

Hi,

I found a few "wierd thing" when trying to use universal analytics with express. Please be aware that i'm am not a pro dev, just a student.

First doc :

In the doc you say :

express.use(ua.middleware("UA-XXXX-Y", {cookieName: '_ga'}));

But i think the correct way is (according to the sample in readme) :

app.use(ua.middleware("UA-XXXX-Y", {cookieName: '_ga'}));

Second :

I had a very wierd behavior where the CID was not taken from the cookie (_ga). In the end i realized that it was working only when the initialization line was just before my routes

ex :

var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
/*Tracking*/
app.use(ua.middleware(config.ga.key, {
  cookieName: '_ga'
}));
app.use('/', routes);

works

var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
/*Tracking*/
app.use(ua.middleware(config.ga.key, {
  cookieName: '_ga'
}));

and

var app = express();
/*Tracking*/
app.use(ua.middleware(config.ga.key, {
  cookieName: '_ga'
}));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);

do not work.

In this 2 cases the function is unable to find the req.cookies and because of that a new cid is created everytime which means you will get a new session everytime a user refresh or change page.

I have no idea why and maybe it's because i have done something wrong but i just wanted to let you know about it.

Thanks for the great work :)

ps : Your code is really easy to read and understand GJ !

send source/medium to Google analytics

Hi,

i am using this universal analytics module to send transactions and items data to google analytics, that is working fine though. But the source/medium is showing as (direct/none) is the GA admin panel. So i want to send the source/medium to google analytics.
Please let me know as how to send source/medium to GA through this universal analytics module?

persistent params

I would like to be able to set some params independent of individual calls.
For example, setting the userId property, or other custom variables.

Tracking from the browser, this is possible via
ga('set', 'userId', 'my-custom-user-id')
and it will be applied to all later tracking calls.

making uuid format optional

I know it says in the docs that a user define cid SHOULD be a v4 uuid, but that doesn't mean it must. :-)

Any chance in just warning when the format is not a uuid but still allowing it through? I am pretty sure this is what analytics.js is doing.

Meh?

Getting started - newbie question

Hello All,

I followed the instructions on the README and have the following simple code.

var ua = require('universal-analytics');
var visitor = ua('UA-XXXXXXXX-X');
visitor.pageview("/test" , function(err , other ){
  console.log(err);
  console.log(other);
}).send();

I tested this on localhost and on my server on Heroku.
I watch the Real Time panel of GA and nothing happens.

I run the same code on the test link https://tonicdev.com/npm/universal-analytics
And then the GA page registers and shows a pagevisit as expected.

How can I solve that? Am I missing something while setting it up?
Any suggestions?

Cheers,
Doruk

Get OS and Version

Is there a solution to get the OS and Version tracked in UA?
Would this be an option?

visitor.set('ua', process.platform +' '+ require('os').release());

Handling intermittent connectivity

I'm using the module to do event tracking on a machine which may not always have internet connectivity. I find that if I call send() in a disconnected state, the error handler is called appropriately and the event queue is emptied. I'd rather that the event queue not be emptied and be sent again next time instead.

The code below seems to achieve my goal, but there is likely a better way, and it would be cleaner if this were included in the library.

this._google.event(category, action, label, value);
var queue = _.clone(this._google._queue);
this._google.send(_.bind(function(error) {
    if (!error) {
        return;
    }

    if (error.code === 'ENOTFOUND') {
        // Couldn't connect -- replace the queue and try next time.
        this._google._queue = queue;
    } else {
        // Something else bad happened.
        logger.warning('Error with Google Analytics', error);
    }
}, this));

Incorrect CID caching behaviour in middleware

When using the Express middleware to find the CID from the cookie, you are caching the CID in the session. Whilst this makes sense to improve performance, this gives rise to a frustrating edge case that submits incorrect analytics data.

When a visitor first hits your site, the _ga cookie is unassigned. On this page load, the middleware will therefore assign a random CID to the user with uuid.v4() and save it in the session. Once the page is loaded, the client side Google Analytics code runs, assigns a proper CID to the user and sets the _ga cookie.

On the second page load, the user now has the _ga cookie populated, but the middleware ignores this and uses the cached CID in the session. This gives rise to an apparent doubling of the number of sessions in Google Analytics as the user appears to have two CIDs, one for client side and one for server side.

I am using the client side to track page views and sending events through universal-analytics. This bug causes user's events to become decoupled from their respective page views, making events appear to pop out of nowhere.

The way I have fixed this is to avoid your middleware and directly get the CID from the cookie on every page load, but obviously I've now got months of analytics data that is incorrect because of this bug. Not caching the CID is my suggested solution, but you'll have to test how this affects the performance (my hunch is not significantly, looking at the code).

I can submit a pull request to remove CID caching in the session (or make it optional), but thought I'd get your input on it first.

Thanks.

Edit: Looks like it was introduced in #4, so it's been around a while!

Analytics shows server location traffic instead of customer location

Hi folks, this is just a question.

I deployed an application with universal-analytics and the application was deployed into a cloud server, however when accessing the site from Costa Rica, I can see in Google Analytics that the location of the traffic is the on from server, not my remote location.

I used the same samples from this repository and I was wondering if i need to pass somehow the remote ip so it can use my location instead of the server's one.

Thanks.

Visitor always as new active user

Hello, I've managed to make this work on my application using nodejs, I've set my app as a website in google analytics and its working fine most of it.

But when I go to my analytics the visitor (currently only me) is recognised as a new user everytime, even after a simple refresh of the page.

I have this in my coffeescript code:

getClientID = ->
    clientID = localStorage[ 'clientid' ]
    if typeof clientID is "undefined" or not clientID? or clientID is ""
        localStorage.setItem 'clientid', uuid()
        clientID = localStorage[ 'clientid' ]

        clientID = null if typeof clientID is "undefined" or not clientID? or clientID is ""

    clientID

clientID = getClientID()
console.log clientID

And in my console I always receive the same clientID, as is supposed to, then I use :

clientTracker = ua 'UA-XXXX-Y', clientID

But when I go to my google analytics I have each amount of sessions as refresh I make, so I can have like 5 active users, and all those 5 are only me, one single clientID, what have I done wrong?

Thank you for your help.

Country reporting incorrect

I think I might have an issue where the location recorded in GA is incorrect. The reason I say this is it's showing a lot of visits in Germany and in particular e commerce sales which I know is definitely not right right. The only thing I can think of is the server is hosted in Germany so wondering if it recording the server location rather than the user somehow.

Could this be the case and if so how do I prevent this happening?

Support for tvJS (Apple tvOS platform)

Hi, thanks for the great library!
We're trying to use it in a tvJS environment and we've hit some showstoppers. This is mainly not the fault of your lib, but a problem with webpack. It doesn't have a special tvOS target and thus we're stuck with the default browser target. This leads to all kinds of problems (for example window isn't defined etc). So to make your library work, I had to patch it and replace the requests dependency with something linke this:

const request = new XMLHttpRequest();
request.open('POST', path);
for (var header in self.options.headers) {
  request.setRequestHeader(header, self.options.headers[header]);
}
request.onload = fn;
request.send(getBody(params));

I've just wanted to share this, if somebody else is having these problems. And also it might be useful for a future version to remove the requests dependency and allow the developer to choose/provide their own transport/HTTP POST function.

Start new session

Looking for some help please. I am using this within AWS Lambda and passing my unique uuid into creation:

const visitor = ua(trackingId, uuid);

My problem is that GA seems to think it's one big session rather than new sessions. Can I pass anything extra to indicate a new session for an existing user?

Docs for method signatures of Visitor#pageview

The docs list the following as valid method signatures:

Visitor#pageview(path)
Visitor#pageview(path, callback)
Visitor#pageview(params)
Visitor#pageview(params, callback)
Visitor#pageview(path, hostname)
Visitor#pageview(path, hostname, callback)
Visitor#pageview(path, title, hostname)
Visitor#pageview(path, title, hostname, callback)

Reading through the code (https://github.com/peaksandpies/universal-analytics/blob/master/lib/index.js#L98-L113) I'm pretty sure that title and hostname are accidentally swapped in the last two overloads. I think it also supports:

Visitor#pageview(path, hostname, title, params)
Visitor#pageview(path, hostname, title, params, callback)

So I would expect the full list of signatures to read:

Visitor#pageview(path)
Visitor#pageview(path, callback)
Visitor#pageview(params)
Visitor#pageview(params, callback)
Visitor#pageview(path, hostname)
Visitor#pageview(path, hostname, callback)
Visitor#pageview(path, hostname, title)
Visitor#pageview(path, hostname, title, callback)
Visitor#pageview(path, hostname, title, params)
Visitor#pageview(path, hostname, title, params, callback)

Is this right?

help with Refund

I'm trying to make the refund of an item, but I can not accomplish. I would like to know how to perform this action, through an event or a transaction?
If possible put an example of code.

And I tried this:

visitor
      .event({
        ec: 'Ecommerce',
        ea: 'Refund',
        ni: 1,
        ti: data.transactionId,
        pa: 'refund',
        pr1id: data.itemCode,
        pr1qt: -1,
        })
      .send();

Failing test suite due to Error: listen EADDRINUSE :::49000

I have created a function using your library (which is awesome, thanks!)

module.exports = ({ googleAnalyticsID }: Props) => {
    function visitor(headers: headerType) {
        const v = ua(googleAnalyticsID, headers['x-device-id'], {
            debug: false,
        });
        return v;
    }

    return {
        googleAnalyticsID,
        environment: process.env.ENVIRONMENT,
        authentication: authentication({ visitor }),
        resetPassword: resetPassword({ visitor }),
        ui: ui({ visitor }),
    };
};

In our test suite, we keep getting a complete undefined when attempting to reference ui from this function. The error that keeps popping up for every test is shown below.

TypeError: Cannot read property 'ui' of undefined

At the end of the test suite running, this error is dumped from our main test.

events.js:163
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE :::49000
    at Object.exports._errnoException (util.js:1050:11)
    at exports._exceptionWithHostPort (util.js:1073:20)
    at Server.setupListenHandle [as _listen2] (net.js:1259:14)
    at listenInCluster (net.js:1307:12)
    at Server.listen (net.js:1406:7)
    at Object.before (xxx/lib/clients/events/index-test.js:17:50)
    at resolve (xxx/node_modules/jest-jasmine2/build/queueRunner.js:38:12)
    at mapper (xxx/node_modules/jest-jasmine2/build/queueRunner.js:31:21)
    at Promise.resolve.then.el (xxx/node_modules/p-map/index.js:42:16)

Would it be possible to change the address for the test suite?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.