First big project commit as pull request #4
Conversation
- make it a mobile app, not a website | ||
- go into 'real-time', then 'events', to see pings trickle in as you click the toolbar button: | ||
|
||
![GA dashboard screenshot](https://www.dropbox.com/s/2i0e206q2qwcpx1/Screen%20Shot%202017-01-22%20at%209.35.39%20PM.png?dl=0&raw=true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add this image to this repo instead of pointing out to Dropboxen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
"main": "index.js", | ||
"scripts": { | ||
"test": "./node_modules/.bin/mocha test/*", | ||
"build-docs": "./node_modules/.bin/documentation build testpilot-metrics.js -f md -o API.md" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Techically, ./node_modules/.bin/
should be added to the $PATH
when using npm run ...
, so you should be able to simplify these to mocha test/*
and documentation build ...
(without the node_modules prefixes).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -0,0 +1,15 @@ | |||
const TRACKING_ID = 'UA-XXXXXXXX-YY'; | |||
|
|||
const { sendEvent } = new Metrics({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% familiar w/ web extension background scripts, but do we need to import Metrics
class/object before using it here? Or do we automatically get it in-scope since it's defined in the manifest.json's background.scripts[]
array?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great question. WebExtensions background scripts seem to just get loaded into the auto-generated background page, script tag style (implicit global binding). Trying to require() the file threw an error. ES6 modules might work, but I didn't try that: I didn't want to lock experiment authors into dealing with ES6 in their build scripts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, AFAIK, there is no module system built into WebExtensions. We're using rollup & babel to build Snooze Tabs - but it is good not to assume that will be the case.
Some experiments (min-vid for example) send extra fields to metrics. We should add another parameter to handle this data. example data in progress branch to integrate testpilot-metrics on min-vid |
|
||
const { sendEvent } = new Metrics({ | ||
id: '@my-addon', | ||
cid: 'some-non-PII-user-ID', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be nice to add an example of how to get this cid, in the testpilot addon we are currently setting this in a simple-storage store. and sending it along with each metric event.
initialization in exports.main
// set our unique identifier for metrics
if (!store.clientUUID) {
store.clientUUID = require('sdk/util/uuid').uuid().toString().slice(1, -1);
}
sendEvent
call
const { sendEvent } = new Metrics({
id: '@'+manifest.name,
cid: store.clientUUID
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Thanks for the suggestion. I've gone back and forth on this point; not having node-style module support in WebExtensions makes it really, really hard to find an off-the-shelf library that's easy to use. But I guess I could roll my own, using window.crypto
to get pseudorandom data, and resort to the hidden window trick to get the crypto
API for SDK/bootstrapped add-ons. I'll add that now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than add a uid generator, I'll just file a bug to document suggestions for generating the user id.
Good point. The simplest solution here seems to be: let experiments pass extra key/value pairs in the object. This works fine for Firefox client metrics, but GA doesn't support random extra named parameters. GA does support custom dimensions, though they are just named Maybe the best thing is to let fancy experiment authors solve their own problems: I'll add support for a |
@6a68 That sounds like a good compromise, thanks Jared |
}; | ||
if (study && variant) { | ||
data.xid = study; | ||
data.xvar = variant; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may want to use custom dimensions here as these seem like environment variables which maps well to dimensions I think (technical docs, and more information on dimensions and metrics).
FWIW I think the measurement protocol is definitely the way to go, and it's worked fine in the Test Pilot implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. I didn't realize how involved GA Content Experiments were: https://support.google.com/analytics/answer/1745154?hl=en&ref_topic=1745208. I don't think that's what we want for our A/B tests.
|
||
## installation | ||
|
||
- Edit `background.js`, set the value of the `TRACKING_ID` const to your GA tracking ID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RE: Mozilla ID vs. personal ID
- If we're making Firefox-y decisions based on this, maybe Mozilla ID
- Mozilla ID adds another dependency on the analytics team (filing a bug)
- Personal ID has bus factor/SPOF risks
- Personal ID could also reduce overhead on graduation (e.g. don't have to transfer things, although transferring ownership doesn't seem like a huge deal)
Maybe we suggest starting up with personal for quickness, then require a transfer to Mozilla before launch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I'll add this to the top-level README docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ckprice Actually, Wil's metrics PR suggested leaving the author as owner throughout, but granting Mozilla access while it's in Test Pilot
_initTransports: function() { | ||
if (this.type === 'webextension') { | ||
try { | ||
this._channel = new BroadcastChannel(this.topic); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential problem in WebExtension land here: The BroadcastChannel has to be named testpilot-telemetry
, but it looks like it will be named just testpilot
because this.topic
gets set to that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doh. great catch, thank you
// pings to Telemetry. If the add-on ID matches the test pilot add-on, use | ||
// the special nsIObserver topic. Otherwise, use the topic shared by all | ||
// experiments. | ||
this.topic = (id === '@testpilot-addon') ? 'testpilot' : 'testpilottest'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe change this to:
if (type === 'webextension') {
this.topic = 'testpilot-telemetry'
} else if (id === '@testpilot-addon') {
this.topic = 'testpilot';
} else {
this.topic = 'testpilottest';
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Does that mean, conversely, that whatever object gets passed in to (Also guessing a transform function would resolve my confusion about the GA params too, if I'm assembling them in my own code.) |
cid: this.cid, | ||
t: 'event', | ||
ec: category, | ||
ea: object, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mapping seems a little confusing. In the GA docs and in the realtime view, this ea
param is called "Event Action" - but it's mapped here from object
. And the el
is "Event Label" - mapped here from event
.
Confused me a little bit, because I was trying to send events like this:
{ event: 'panel-opened', object: 'snooze-tabs' }
{ event: 'snoozed', object: 'snooze-tabs' }
{ event: 'woke', object: 'snooze-tabs' }
And all I was getting were snooze-tabs
under "Event Action" - and "Event Label" is not even listed on the realtime table.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing this out. I've switched the code to make the event the 'event action'. That real-time event graph is the place to be.
FWIW, I've got a hacky start at integrating this into Snooze Tabs. The parameters seem a little confusing to me, but I was able to get some data flowing to GA in the realtime view: |
Yup! That's the idea...excluding the transform function, of course ;-) |
Made some changes, just about to squash, push, and merge. Just FYI for those who reviewed:
|
I've added the whole team as admins on this repo. Comments and questions very welcome.
Take a look at my branch to see the formatted README and API docs: https://github.com/6a68/testpilot-metrics/tree/test
I'll plan to land this EOD Tuesday, unless there are major concerns :-)