5

I am trying to post an event to google analytics using Measurement Protocol from my Google App Engine (Java) web app.

I have tested the URL by submitting the URL directly, and it immediately shows up (realtime) in Google Analytics. But when I try to post it in the app nothing shows up.

So I assumed to start with my Java code was flawed (perhaps was), so I replaced my code with Google's example code to integrate from Google App Engine to Google Analytics here. I changed it a bit, but here are the key bits...

private static final URL GA_URL_ENDPOINT = getGoogleAnalyticsEndpoint();

private static URL getGoogleAnalyticsEndpoint() {
    try {
        return new URL("http", "www.google-analytics.com", "/collect");
    } catch (MalformedURLException e) {
        throw new RuntimeException(e);
    }
}

public boolean trackEvent(
        String category, String action, String label, String value) {

    try {

    Map<String, String> map = new LinkedHashMap<>();
    map.put("v", "1");             // Version.
    map.put("tid", gaTrackingId);
    map.put("cid", "555");
    map.put("t", "event");         // Event hit type.
    map.put("ec", encode(category, true));
    map.put("ea", encode(action, true));
    map.put("el", encode(label, false));
    map.put("ev", encode(value, false));

    HTTPRequest request = new HTTPRequest(GA_URL_ENDPOINT, HTTPMethod.POST);
    request.addHeader(CONTENT_TYPE_HEADER);
    request.setPayload(getPostData(map));

    HTTPResponse httpResponse = urlFetchService.fetch(request);

    // Return True if the call was successful.
    log.info("Response code for GA event is: " + httpResponse.getResponseCode());
    return httpResponse.getResponseCode() >= 200;

    } catch ( Exception e ) {
        //HANDLE EXCEPTION
        return false;
    }
}

private static byte[] getPostData(Map<String, String> map) {
    StringBuilder sb = new StringBuilder();
    for (Map.Entry<String, String> entry : map.entrySet()) {
        sb.append(entry.getKey());
        sb.append('=');
        sb.append(entry.getValue());
        sb.append('&');
    }
    if (sb.length() > 0) {
        sb.setLength(sb.length() - 1); // Remove the trailing &.
    }
    log.info("GA event string is: " + sb.toString());
    return sb.toString().getBytes(StandardCharsets.UTF_8);
}

private static String encode(String value, boolean required)
        throws UnsupportedEncodingException {
    if (value == null) {
        if (required) {
            throw new IllegalArgumentException("Required parameter not set.");
        }
        return "";
    }
    return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
}

When this bit of code is called, I get the parameter string out of my log file:

v=1&tid=UA-XXXXXXXX-1&cid=555&t=event&ec=settings&ea=autopost-on&el=rkAutoPost&ev=5

I also see that I get a 2xx response code from the call to google. But nothing shows up in GA interface (realtime or otherwise).

So then I try just doing a GET from inside my browser...

http://www.google-analytics.com/collect?v=1&tid=UA-XXXXXXXX-1&cid=555&t=event&ec=settings&ea=autopost-on&el=rkAutoPost&ev=5

... and that immediately hits GA realtime. So this tells me it isn't a problem with the content of the message.

Note I also created a brand new clean view to make sure nothing was being filtered out... did't help.

Any ideas please? Thank you!

Dawson
  • 4,391
  • 2
  • 24
  • 33
nickpharris
  • 385
  • 5
  • 17

3 Answers3

4

TL:DR; GA filters events from GAE via the User Agent request header. Override the User Agent via the measurement protocol's ua parameter.


Google Analytics (GA) is filtering Google App Engine (GAE) traffic based on the User Agent header containing the string "AppEngine-Google; (+http://code.google.com/appengine; appid: APPID)". I attempted to set the User Agent to a custom string, though as stated here, GAE appends the aforementioned string to any custom User Agent string and that is enough for GA to filter the events.

It is suggested in other answers that updating the view settings by unchecking the "Exclude all hits from known bots and spiders" Bot Filtering option would permit events from GAE though this did not work for me. Filtering bot traffic seems useful anyways so I wasn't too eager to uncheck this option anyways.

The solution was to override the User Agent via the measurement protocol's ua option which is not updated by GAE. The resulting parameter string from the example provided in the question would then be :

v=1&t=event&tid=UA-XXXXXXXX-1&cid=555&ec=settings&ea=autopost-on&el=rkAutoPost&ev=5&ua=Custom%20User%20Agent

Where my ua parameter is set to Custom User Agent.

Hope this saves someone some time in the future :)

Dawson
  • 4,391
  • 2
  • 24
  • 33
1

As with all the other questions I have read on similar subject, it was a stupid mistake: problem was that I did indeed create a new, clean view in GA, but when I created it I checked...

Exclude all hits from known bots and spiders

... so all events being generated by calls on Google App Engine were being filtered out. Ugh.

nickpharris
  • 385
  • 5
  • 17
  • that's why my implementation originally worked but suddenly not working anymore.... ugh! perhaps can try to play with the user-agent string to work around? – user7180 May 20 '15 at 02:09
  • I have the same problem, but I never have this exclude option enabled. – honcheng Aug 18 '15 at 10:12
0

TL;DR Disable privacy tracking extensions on the browser

In my case the POST requests to GA were not being issued from the deployed web app but I could be seen when I executed the app in dev, i.e locallhost.

The browser network tab showed calls to https://www.google-analytics.com locally, but not on the deployed app.

I had some privacy tracking extensions enabled on the browser that blocked the bots!

If you need analytics to work with an add blocker you'll need to fetch your analytics javascript resource through a first party proxy.

intotecho
  • 4,925
  • 3
  • 39
  • 54