Integrating with Google Analytics

The Google Analytics Platform lets you measure user interactions with your business across various devices and environments. The platform provides all the computing resources to collect, store, process, and report on these user-interactions.

Analytics collection can take place on both the client and server side. Google Analytics provides easy to use APIs and SDKs to send data to Google Analytics. In addition to those, we have developed code that you can use in your App Engine applications to easily send server-side analytics to Google Analytics.

Client-side analytics collection

With the collection APIs and SDKs, you can measure how users interact with your content and marketing initiatives. Once implemented, you will be able to view user-interaction data within Google Analytics or through the Reporting APIs. For more details on client-side analytics collection select the link below based on the type of your client:

  • Web Tracking (analytics.js) - Measure user interaction with websites or web applications.
  • Android - Measure user interaction with Android applications.
  • iOS - Measure user interaction with iOS applications.
  • Measurement Protocol - Measure user interaction in any environment with this low-level protocol.

App Engine server-side analytics collection

Although App Engine already provides a mechanism for logging events in your application, it may be advantageous to track specific server-side events in Google Analytics. Some of the benefits are as follows:

  • Historical data analysis - App Engine allows you to configure the maximum number of days, or size of your log file. After that time has passed you no longer have access to those log files. Tracking events in Google Analytics provides you a much longer lifespan into the visibility of past events.
  • Track key events - Log files can be verbose with various components of your application writing data to them. By using event tracking you can pinpoint just the key events that you are interested in monitoring and track those along with some additional metadata.
  • Powerful user interface - Take advantage of the rich user interface that Google Analytics provides to visualize, report and export these server side events.

This can be accomplished easily by integrating the sample source code below into your App Engine application. For additional information on this approach consult the Google Analytics developers guide for Event Tracking.

Sample source code




import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;

public class GoogleAnalyticsTracking {

  private static final URL GA_URL_ENDPOINT = getGoogleAnalyticsEndpoint();
  private static final HTTPHeader CONTENT_TYPE_HEADER =
      new HTTPHeader("Content-Type", "application/x-www-form-urlencoded");

  private final String gaTrackingId;  // Tracking ID / Web property / Property ID
  private String gaClientId = "555";  // Anonymous Client ID.
  // Used to override the existing factory with perhaps a mock one for testing.
  private URLFetchService urlFetchService = URLFetchServiceFactory.getURLFetchService();

  private static URL getGoogleAnalyticsEndpoint() {
    try {
      return new URL("http", "", "/collect");
    } catch (MalformedURLException e) {
      throw new RuntimeException(e);

  public GoogleAnalyticsTracking(String gaTrackingId) throws IOException {
    if (gaTrackingId == null) {
      throw new IllegalArgumentException("Can't set gaTrackingId to a null value.");
    this.gaTrackingId = gaTrackingId;

  public GoogleAnalyticsTracking setGoogleAnalyticsClientId(String gaClientId)
      throws IOException {
    if (gaClientId == null) {
      throw new IllegalArgumentException("Can't set gaClientId to a null value.");
    this.gaClientId = gaClientId;
    return this;

  public GoogleAnalyticsTracking setUrlFetchService(URLFetchService urlFetchService)
      throws IOException {
    if (urlFetchService == null) {
      throw new IllegalArgumentException("Can't set urlFetchService to a null value.");
    this.urlFetchService = urlFetchService;
    return this;

   * Posts an Event Tracking message to Google Analytics.
   * @param category the required event category
   * @param action the required event action
   * @param label the optional event label
   * @param value the optional value
   * @return true if the call succeeded, otherwise false
   * @exception IOException if the URL could not be posted to
  public int trackEventToGoogleAnalytics(
      String category, String action, String label, String value) throws IOException {
    Map<String, String> map = new LinkedHashMap<>();
    map.put("v", "1");             // Version.
    map.put("tid", gaTrackingId);
    map.put("cid", gaClientId);
    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);

    HTTPResponse httpResponse = urlFetchService.fetch(request);
    // Return True if the call was successful.
    return httpResponse.getResponseCode();

  private static byte[] getPostData(Map<String, String> map) {
    StringBuilder sb = new StringBuilder();
    for (Map.Entry<String, String> entry : map.entrySet()) {
    if (sb.length() > 0) {
      sb.setLength(sb.length() - 1); // Remove the trailing &.
    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,;


def track_event(category, action, label=None, value=0):
    data = {
        'v': '1',  # API Version.
        'tid': GA_TRACKING_ID,  # Tracking ID / Property ID.
        # Anonymous Client Identifier. Ideally, this should be a UUID that
        # is associated with particular user, device, or browser instance.
        'cid': '555',
        't': 'event',  # Event hit type.
        'ec': category,  # Event category.
        'ea': action,  # Event action.
        'el': label,  # Event label.
        'ev': value,  # Event value, must be an integer

    response =
        '', data=data)

    # If the request fails, this will raise a RequestException. Depending
    # on your application's needs, this may be a non-error and can be caught
    # by the caller.

def track_example():
        action='test action')
    return 'Event tracked.'