How to Use the Google Analytics 4 Measurement Protocol - Python Client [Updated 2022]

Subscribe to our monthly newsletter to get the latest updates in your inbox


The GA4 Measurement Protocol (GA4MP) is essentially an API that allows developers to make POST HTTP requests to send Google Analytics (GA) events directly to the GA server. This allows any device that can make HTTP calls to interact with GA, making the possibilities virtually endless. Primarily, though, this also empowers the sending of data collected offline to GA that can be post-dated up to 48 hours to align with online events. 

Today, we’ll focus on Adswerve’s Python client for the GA4MP, but because the protocol simply leverages an HTTP request, the protocol can be called through any language that is able to interact with an API. You can learn more about the API here.

Please note: our Python client was in alpha the last time we talked about it, but since Google has put development work in on their side, we have, too. If you're already using our client, you'll need to make some code updates in order to take advantage of new features. And if you're new to the client, you may also be excited by new features like passing required Session ID and Engagement Time parameters, memory storage, Firebase support, and optional classes to help reduce the guesswork of creating event objects.


Yes! Google recently added `session_id` and `engagement_time_msec` parameters that can be passed to GA4 along with events. It is required to include these in order for events to appear in the Real Time and other standard reports in the GA4 interface, so we've enabled default collection of these values in the library. The Session ID will be the UNIX timestamp for the time the client was initialized, and the engagement time will be the number of milliseconds since the last event was sent. Of course, you're welcome to overwrite either value, but if you don't want to worry about them, you don't have to! And by including this data in the hits being passed to GA4, you'll see improved reporting and analysis options on the BigQuery side as well. 


The GA4MP Python library is hosted on PyPi and therefore installing the client is as simple as using pip in your favorite virtual environment:

pip install ga4mp


In order to use the GA4MP, you'll need property and user-specific credentials to be validated by GA. The required credentials are:

1. api_secret: Generated through the Google Analytics UI. To create a new secret, navigate in the Google Analytics UI to: Admin > Data Streams > choose your stream > Measurement Protocol API secrets > Create.

2. measurement_id: The identifier for a Data Stream. Found in the Google Analytics UI under: Admin > Data Streams > choose your stream > Measurement ID.

3. client_id: A unique identifier for a client, representing a specific browser/device.

Once you have the required credentials, they are simply strings that can either be stored in a json file or passed directly to the Python client to follow.


The purpose of the GA4MP is to get events that occur outside of GA into GA; however, this can take a few different forms:

  1. When events occur, we want them sent to GA in real-time.
  2. We may be currently collecting events but are either not able to send them immediately (e.g., we are offline) or for some reason do not wish to.
  3. We have collected events that we want to appear as hits that occurred prior to our collecting them.

We'll show how to perform each of the above in the following sections.


To send events in general, but specifically events in real-time, we start by importing the `GtagMP` class and instantiating the class with the credentials that we collected above. We read our credentials from a deserialized json dictionary, but you can choose your own method:

from ga4mp import GtagMP
API_SECRET = credentials['API_SECRET']
CLIENT_ID = credentials['CLIENT_ID']
ga = GtagMP(measurement_id = "MEASUREMENT_ID", api_secret = "API_SECRET", client_id="CLIENT_ID")

To send an event to GA, the client expects a list of events where each event is a Python dictionary. Each event dictionary should at a minimum contain a `name` key and a `params` dictionary. The following shows an example of constructing a single event, using the optional Event class:

example_event = ga.create_name_event(name="custom_event")

# Event parameters can be set one at a time...
example_event.set_event_param(name="param_key_1", value="param_1")

# ...or via a loop.
for key, value in my_dict.items():
    example_event.set_event_param(name=key, value=value)

After creating one or more events, we can put them in a list, then pass them to GA using the `send` method:

# More than one can be sent in the same list.
events = [example_event, some_other_event]

>>> INFO:ga4mp.ga4mp:Sending POST to:
>>> INFO:ga4mp.ga4mp:Batch Number: 1
>>> INFO:ga4mp.ga4mp:Status code: 204

As you can see in the output, the client sends a POST request to the GA server and sends the data in batches. There is a limit of 25 events per request, but the client collects any number of events and sends them sequentially in batches of 25. You can learn about further limitations here.

Lastly, as status code is printed out to indicate if the request was successful or not. One of the following codes is deemed as acceptable: 200, 201, 204.

After sending your event, you can go to the Real Time overview in GA and see the hit!

Validating Events

To ensure that your events are sent successfully, the Python client checks the event names against any reserved event names; however, the GA4MP also has the functionality to validate whether the event list is adequately structured by sending an HTTP request to Google's validation server. To send a validation hit, simply set the `validation_hit` argument to `True` to the `send` method as follows:

ga.send(events, validation_hit=True)
>>> INFO:ga4mp.ga4mp:Sending POST to:
>>> INFO:ga4mp.ga4mp:Batch Number: 1
>>> INFO:ga4mp.ga4mp:Status code: 200

Where you will see that the POST target has changed to the validation server.


Addressing our second scenario of sending events at a time after they were collected, we can send events using the `postpone` argument, which simply stores the events in a list, and that list can be sent at an appropriate time:


This is useful as it is possible that we may be collecting event hits in real-time and do not want to write code to manage the collection of the events along with their timestamp to be implemented later. After adding the events using the above method, the stored list can be sent as follows:

>>> INFO:ga4mp.ga4mp:Sending POST to:
>>> INFO:ga4mp.ga4mp:Batch Number: 1
>>> INFO:ga4mp.ga4mp:Status code: 204


Lastly, we may want to back-date events that have just been collected but are relevant in the past. The Python client supports backdating events up to 48 hours by providing a Python `datetime` object to the `date` parameter of the `send` method:

import datetime
dt = - datetime.timedelta(hours=48)
ga.send(events, date=dt)
>>> INFO:ga4mp.ga4mp:Sending POST to:
>>> INFO:ga4mp.ga4mp:Setting event timestamp to: 2021-03-10 16:20:41.722364
>>> INFO:ga4mp.ga4mp:Timestamp of request is: 1615386041000000
>>> INFO:ga4mp.ga4mp:Batch Number: 1
>>> INFO:ga4mp.ga4mp:Status code: 204


At this time, the GA4 Measurement Protocol does not support the passing of campaign information. If you're sending events through the GA4MP to supplement a session on your users' desktop or mobile devices, then this is a non-issue. Unfortunately, the same can't be said for a full server-side implementation, such as on an OTT device.

If you're leveraging BigQuery for your analytics and reporting, you could work around this by passing campaign parameters as event parameters, then clean up the data after collection, but the GA4 interface itself is just going to show the traffic as Direct. If and when Google updates the GA4MP to support Source, Medium, Campaign, and other attribution parameters, we'll update the Python library accordingly.


We can now send our custom events to GA! If you want to take the GA4MP Python client a little further, try out one of the following:

  • View the README to learn more about the new memory storage functionality, built-in methods, and other usages
  • Star the repo on Github to be notified when features are added
  • Contribute! The GA4MP is open source under a BSD-3 License and is open to Issues and Pull Requests

If you have questions about GA4 Measurement Protocol or GA4, please don’t hesitate to reach out.