APP + WEB: Google Analytics Measurement Protocol version 2
The Google Analytics Measurement Protocol allows users and developers to make HTTP requests directly to Google Analytics endpoint in order to measure how users interact from any enviroment/platform.
Since Google announced the new APP+WEB Properties back in summer, we noticed that the &v parameter that used to hold a fixed 1 value turned to be a =2 value in our hit requests. Which implicitily means that at some point a new version of the Measurement Protocol is going to be released.
I tried to reverse-engineer all the details I could about the parameters used on this new upcoming protocol.
Please have in mind that the , and I'm publishing all the info I was able to gather.
Introduction
The new Measurement Protocol cames with some great new improvements over the version 1 that we're used to see in our Universal Analytics hits.
I'd try to think about this new protocol as an enhanced version of the previous one. They even share some parameters.
What's new on the version 2 protocol
This new measurement protocol seems to had been designed having some performance optimizations in mind.
First thing we need to have in mind is that APP+WEB doesn't longer have "hit types", everything we may end sending to APP+WEB is an "event" that may (or may not) be accompanied with parameters.
There 2 groups of parameters in the APP+WEB Measurement Protocol .
Let's think about them as the event parameters "scope".
- Event Related Parameters ( ep.* , epn.* )
- User Related Parameters ( up.* , upn.* )
Also the parameters accepts 2 diferente values types:
Batched Events
Now by default APP+WEB Protocol allows to send batched events, meaning that with a single hit request we'll be able to send multiple events. I know this is not new at all, and we ever needed to debug an APP implemention we'd have noticed that version 1 protocol allowed us to send batched hits ( via /batch endpoint ).
In any case v2, comes with some extra enhanced comparted with the legacy version,
Events
within a single hit request share parameters. So the hits payload will the smaller. for example won't make much sense sending the &dl document.location for all the events if that's a shared value across all event within the current hit.POST
is now the only accept Method. This will bypass the oldGET
1082 bytes limit.
Debugging
Debugging the new measurument protocol v2 has became even easier, since the new properties offer a Debug View.
In order to have our hits showing up here, we'll need to add a _dbg=1 parameter to our hits.
&_dbg=1
Then our hits will show up in the DebugView
report in real time, making our debugging efforts much easier that they actual are.
Turning on the debug on the web based library
If you're working on a website based implementation you can turn on the "oficial" debugging logs just loading the GTAG container with the &dbg={{randomNumber}} parameter:
https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX&l=dataLayer&cx=c&dbg=918
This will turn on the debug output into our browser, giving us a log of detailed info about what's happening.
Building a request
APP+WEB hits need to go to a new endpoint that is located on the following URL:
https://www.google-analytics.com/g/collect
As we mentioned in our technical overview for the new APP+WEB Properties now the hits al built in 2 separate parts:
URL QueryString
will hold the common parametersRequest Payload
( POST ), this will hold the events related data.
The Request Payload will only be available when there're more than 1 event on the current hit request. If the hit only contains one event, the parameter will be attached to the QueryString as the rest of the common shared parameters
The following code will help us to understand how should be build a hit, and also how to send it to APP+WEB Endpoint using the navigator.sendBeacon
function.
// APP+WEB Endpoint
var endPoint = 'https://www.google-analytics.com/g/collect';
// Base Event Model for Web Hit
var eventModel = {
v: 2,
tid: 'G-XXXXXXXX-0',
_p: Math.round(2147483647 * Math.random()),
sr: screen.width + 'x' + screen.height,
_dbg: 1,
ul: (navigator.language || "").toLowerCase(),
cid: '1908161148.1586721292',
dl: 'https://appweb.thyngster.com/',
dr: '',
dt: 'APP + WEB Measurement Protocol version2 DEMO',
sid: new Date() * 1,
_s: 1
}
// A queue to batch our events
var events = [];
var requestQueryString;
var requestBody;
// Let's push some events
events.push({
'en': 'pageview'
});
// Second Event
events.push({
'en': 'scroll',
'_et': '5000',
'epn.percent_scrolled': '90'
});
// Another more event
events.push({
'en': 'useless_no_bounce_event',
'_et': '5000',
'ep.no_bounce_time': '5sec'
});
// Is there any event in our queue?
if (events.length > 0) {
// If there's only one event, we'll not pushing a body within our request
if (events.length === 1) {
Object.assign(eventModel, events[0]);
} else {
requestBody = events.map(function(e) {
return (Object.keys(e).map(key=>key + '=' + e[key]).join('&'));
}).join("\n");
}
requestQueryString = Object.keys(eventModel).map(key=>key + '=' + encodeURIComponent(eventModel[key])).join('&');
navigator.sendBeacon(endPoint + '?' + requestQueryString, requestBody);
}
Parameters Reference
Request Parameters
These parameters are available across all hits. There are related to the current hit.
Parameter | Value Type | Value |
---|---|---|
v | int | Protocol Version |
tid | string | Stream ID ( G-XXXXXXXXX ) |
cid | string | Client ID Value |
sid | string | Session ID . ( current session start TimeStamp ) |
sr | string | Screen Resolution |
_dbg | bool | Debug Switch |
ul | string | User Language |
_fid | ||
_uci | bool | |
_p | ||
gtm | string | Container Hash |
_s | integer | Session Hits Count |
Shared Parameters
Parameter | Value Type | Value |
---|---|---|
dl | string (url) | Document Location |
dr | string (url) | Document Referer |
dt | string | Document Title |
sid | string | Session ID |
sct | integer | Session Count |
seg | boolean | Session Engagement |
_fv | bool | First Visit |
_nsi | bool | New Session Id |
_ss | bool | Session Start |
cu | string | Currency Code |
_c |
Event Parameters
Parameter | Value Type | Value |
---|---|---|
en | string | Event Name |
_et | integer | Event Time |
up.* | string | User Parameter String |
upn.* | number | User Parameter Number |
ep.* | string | Event Parameter String |
epn.* | number | Event Parameter Number |
Ecommerce
NOTE: I want to add that this was live on the latest gtag version one week ago, and that it seems it has been removed. In any case I wouldn't expect to have changes on the final release.
We're splitting the parameters related to the Ecommerce on 3 categories. We need to have in mind that APP+WEB have 2 main groups of models for the Enhanced Ecommerce, the Products Model and the Promotions Model.
Products Model, is used in every single ecommerce event that is sent to Google Analytics . Which includes product listings, products clicks, product details views, products adds to cart, products remove from cart, product checkout, products purchases and products refunds.
Promotions Model, this is the second model, this is for the promotions tracking in the Enhanced Ecommerce, since they're not directly related to a product this is a total aside model used on APP+WEB
- Product Items ( Shared Product Related data )
- Product List Details ( Product Lists Related data , this goes along with Product Items )
- Promotions
Product Items
Products Items are send under it's own incremental key, &pr1
, &pr2
... &prN
. Then each of these parameters will hold all the product model info.
Example:
&pr1': 'idP12345~nmAndroid Warhol T-Shirt~lnSearch Results~brGoogle~caApparel/T-Shirts~vaBlack~lp1~qt2~pr2.0',
As you can see we can split the data within this parameter key by the tilde character ( ~ ) to be able to see a proper Product Model
id: P12345
nm: Android Warhol T-Shirt
ln: Search Results
br: Google
ca: Apparel/T-Shirts
va: Black
qt: 2
pr: 2.0
Parameter | Value Type | Value | |
---|---|---|---|
pr[0-9] | id | string | Product ID/Sku |
nm | string | Product Name | |
br | string | Product Brand | |
ca | string | Product Category Hierarchy Level 1 | |
ca2 | string | Product Category Hierarchy Level 2 | |
ca3 | string | Product Category Hierarchy Level 3 | |
ca4 | string | Product Category Hierarchy Level 4 | |
ca5 | string | Product Category Hierarchy Level 5 | |
va | string | Product Variant | |
pr | number | Product Unit Price | |
qt | integer | Product Quantity | |
cp | string | Product Coupon | |
ds | number | Product Discount |
Product Impressions
These are the Measurement Protocol related parameters to the products Impressions. They are complimentary to the product items. Expect these on the product impressions and product clicks events
Parameter | Value Type | Value |
---|---|---|
ln | string | List Name |
li | string | List ID |
lp | string | List Position |
Transaction Related Data
The next table shows the parameters related to the transacion info.
Parameter | Value Type | Value |
---|---|---|
ep.transaction_id | string | Transaction ID |
ep.affiliation | string | Transactionm Affiliation |
epn.value | number | Transaction Revenue |
epn.tax | number | Transaction Tax |
epn.shipping | number | Transaction Shipping |
ep.coupon | string | Transaction Coupon |
Promotions
And finally the next table shows the parameters related to the promotions tracking. We should expect these parematers to be showing up into the promotion views and promotion clicks events
Parameter | Value Type | Value |
---|---|---|
pi | string | Promotion ID |
pn | string | Promotion Name |
cn | string | Creative Name |
cs | string | Creative Slot (Position ) |
lo | string | Locationo ID |