This guide explains how you can send
[Google Analytics Measurement Protocol](https://developers.google.com/analytics/devguides/collection/protocol/ga4) web and app stream
[events](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events) to a
Google Analytics server, so that you can view Measurement Protocol events in your
[Google Analytics reports](https://developers.google.com/analytics/devguides/reporting/data/v1/basics).

The identifiers and parameters required for Measurement Protocol requests depend
on whether you are sending events to a **Web stream** or an **App stream**.

- For **Web streams** (typically instrumented with gtag.js or Google Tag Manager), you use the `measurement_id` in the request URL and the `client_id` in the JSON body to identify the user instance. The `client_id` should match the ID generated by the Google Analytics tag on your website.
- For **App streams** (instrumented with the Firebase SDK), you use the `firebase_app_id` in the request URL and the `app_instance_id` in the JSON body, which are provided by the Google Analytics for Firebase SDK.

This guide provides examples for both scenarios.

### Key request components by stream type

| Component | Web stream (gtag.js/GTM) | App stream (Firebase) |
|---|---|---|
| **Data stream URL parameter** | `measurement_id` | `firebase_app_id` |
| **API secret URL parameter** | Required | Required |
| **Device ID JSON body field** | `client_id` | `app_instance_id` |

Choose the platform you want to see in this guide:
<button value="firebase" default="">Firebase</button> <button value="gtag">gtag.js</button>

This tab shows instructions for sending events from your server that correlate
with user activity in an **App stream** using the Google Analytics for Firebase
SDK. Keep in mind that these requests use `firebase_app_id` and
`app_instance_id`.


## Prerequisites

To send events using the Measurement Protocol, you need specific identifiers
from your Google Analytics property or Firebase project.

### API secret

The `api_secret` is used to authenticate your requests. It is crucial to keep
this secret confidential.

To create a new secret:

1. Go to [Google Analytics](https://analytics.google.com/) and navigate to your account and property.
2. Click **Admin** in the lower left.
3. Under **Data collection and modification** , click **Data streams**.
4. Select your Web or App data stream.
5. Click **Measurement Protocol API secrets**.
6. Click **Create**.
7. Enter a nickname for the secret and click **Create**.
8. Copy the **Secret value**.

   <br />

   <br />

   **Important:** The `api_secret` is private. Don't expose it in the
   client-side code of your website or app.
   - **Security risk:** Exposing the `api_secret` allows unauthorized parties to send arbitrary or spam data to your Google Analytics property, which can corrupt your reporting.
   - **Correct usage:** The Measurement Protocol is primarily designed for **server-side** or trusted environments (like offline systems or server-to-server communication).
   - **Client-side tracking:** If you need to send events directly from a web browser, use the [Google tag (gtag.js)](https://developers.google.com/analytics/devguides/collection/ga4/events?client_type=gtag) or [Google Tag Manager](https://developers.google.com/analytics/devguides/collection/ga4/events?client_type=gtm).
   - **Chrome Extensions:** For Manifest V3 Chrome Extensions, you cannot load remote code like `gtag.js`. In this case, the Measurement Protocol is the recommended approach. See [Use Google Analytics in Chrome extensions](https://developer.chrome.com/docs/extensions/how-to/integrate/google-analytics-4).

   <br />

   <br />

### Firebase app ID

The `firebase_app_id` identifies your Firebase app. It is not the same as the
`app_instance_id`.

To find your Firebase App ID:

1. Open your project in the [Firebase console](https://console.firebase.google.com/).
2. Click the settings gear icon next to **Project Overview** and select **Project settings**.
3. Under the **General** tab, go to the **Your apps** section.
4. Select the specific iOS or Android app.
5. Copy the **App ID** value.


## Format the request

The Google Analytics Measurement Protocol only supports HTTP `POST` requests.

To send an event, use the following format:

    POST /mp/collect?firebase_app_id=<var>FIREBASE_APP_ID</var>&api_secret=<var>API_SECRET</var> HTTP/1.1
    HOST: www.google-analytics.com
    Content-Type: application/json

    PAYLOAD_DATA

> [!TIP]
> **Tip:** If you want your data to be collected in the EU, change the `HOST` in the example to `region1.google-analytics.com`.

You must provide the following in the request URL query parameters (see
[Prerequisites](https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events#prerequisites) for details on how to find or create these
values):

- `api_secret`: The API secret to authenticate the request.
- `firebase_app_id`: The Firebase App ID of your application.

You must provide a request body in the [JSON POST body](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference#payload_post_body) format for
the Measurement Protocol. Here's an example:

      {
       "app_instance_id": "APP_INSTANCE_ID",
       "events": [
          {
            "name": "login",
            "params": {
              "method": "Google",
              "session_id": "SESSION_ID",
              "engagement_time_msec": 100
            }
          }
       ]
      }


You must provide `app_instance_id` in the request body to identify a unique
installation of your mobile app. Note that this is different from the
`firebase_app_id` which identifies the app itself. For more information on the
`app_instance_id` and how to retrieve it using the Firebase SDK, see the
[app_instance_id reference documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?client_type=firebase#app_instance_id).


While `session_start` is a [reserved event
name](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference#reserved_names),
creating a new `session_id` creates a new session without the need to send
`session_start`. Understand how [sessions are
counted](https://support.google.com/analytics/answer/9191807).

## Try it

> [!NOTE]
> **Note:** The following examples use the `fetch` API and are intended for use in server-side or trusted environments (for example, Node.js or a backend server). They should **not** be used in client-side (browser) code as that would expose your `api_secret`.

Here's an example you can use to send multiple events at once. This example
sends a [`tutorial_begin`](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events?tech=aw_measurement_protocol#tutorial_begin) event and a
[`join_group`](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events?tech=aw_measurement_protocol#join_group) event to your Google Analytics server, includes [geographic
information](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference#payload_geo_info) using the `user_location` field, and includes [device information](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference#payload_device_info)
using the `device` field.

    const firebaseAppId = "FIREBASE_APP_ID";
    const apiSecret = "API_SECRET";

    fetch(`https://www.google-analytics.com/mp/collect?firebase_app_id=${firebaseAppId}&api_secret=${apiSecret}`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        app_instance_id: "APP_INSTANCE_ID",
        events: [
          {
            name: "tutorial_begin",
            params: {
              "session_id": "SESSION_ID",
              "engagement_time_msec": 100
            }
          },
          {
            name: "join_group",
            params: {
              "group_id": "G_12345",
              "session_id": "SESSION_ID",
              "engagement_time_msec": 150
            }
          }
        ],
        user_location: {
          city: "Mountain View",
          region_id: "US-CA",
          country_id: "US",
          subcontinent_id: "021",
          continent_id: "019"
        },
        device: {
          category: "mobile",
          language: "en",
          screen_resolution: "1280x2856",
          operating_system: "Android",
          operating_system_version: "14",
          model: "Pixel 9 Pro",
          brand: "Google",
          browser: "Chrome",
          browser_version: "136.0.7103.60"
        }
      })
    });

The format of `firebase_app_id` is platform specific. See **Application ID**
under [Firebase config files and objects](https://firebase.google.com/docs/projects/learn-more#config-files-objects).


## Override timestamp

The Measurement Protocol uses the *first* timestamp it finds in the following list
for each event and user property in the request:

1. The `timestamp_micros` of the event or user property.
2. The `timestamp_micros` of the request.
3. The time that the Measurement Protocol receives the request.

The following example sends a request-level timestamp that applies to all of the
events and [user
properties](https://developers.google.com/analytics/devguides/collection/protocol/ga4/user-properties) in the
request. As a result, the Measurement Protocol assigns a timestamp of
`requestUnixEpochTimeInMicros` to the `tutorial_begin` and `join_group` events
and the `customer_tier` user property.

    {
      "timestamp_micros": requestUnixEpochTimeInMicros,
      "events": [
        {
          "name": "tutorial_begin"
        },
        {
          "name": "join_group",
          "params": {
            "group_id": "G_12345",
          }
        }
      ],
      "user_properties": {
        "customer_tier": {
          "value": "PREMIUM"
        }
      }
    }

The following example sends a request-level timestamp, an event-level
timestamp, and a user property-level timestamp. As a result, the
Measurement Protocol assigns the following timestamps:

- `tutorialBeginUnixEpochTimeInMicros` for the `tutorial_begin` event
- `customerTierUnixEpochTimeInMicros` for the `customer_tier` user property
- `requestUnixEpochTimeInMicros` for the `join_group` event and the `newsletter_reader` user property.

    {
      "timestamp_micros": requestUnixEpochTimeInMicros,
      "events": [
        {
          "name": "tutorial_begin",
          "timestamp_micros": tutorialBeginUnixEpochTimeInMicros
        },
        {
          "name": "join_group",
          "params": {
            "group_id": "G_12345",
          }
        }
      ],
      "user_properties": {
        "customer_tier": {
          "value": "PREMIUM",
          "timestamp_micros": customerTierUnixEpochTimeInMicros
        },
        "newsletter_reader": {
          "value": "true"
        }
      }
    }

### Validation behavior for past events and user properties

Events and user properties can be backdated up to 72 hours. If the
`timestamp_micros` value is earlier than 72 hours ago, the Measurement Protocol
accepts or rejects the event or user property as follows:

- If the `validation_behavior` is not set or is set to `RELAXED`, the Measurement Protocol accepts the event or user property but overrides its timestamp to 72 hours ago.
- If the `validation_behavior` is set to `ENFORCE_RECOMMENDATIONS`, the Measurement Protocol rejects the event or user property.

Events sent using the Measurement Protocol that are intended to be joined or
processed in conjunction with events collected by the Google Analytics for Firebase SDK
or gtag.js should be received by Google Analytics within **48 hours** of the original
client-side event timestamp. Events received later than this may not be
processed as expected, particularly for purposes like conversion attribution.

## Limitations

The following limitations apply to sending Measurement Protocol events to Google
Analytics:

> [!NOTE]
> **Note:** For information on the limitations of 360 features, see [Google Analytics
> 360](https://support.google.com/analytics/answer/11202874).

- You can send at most 100 million non-conversion requests per hour for each
  property. A request is a non-conversion request if none of the events in the
  request is a key event for which there is a
  [conversion in Google Ads](https://support.google.com/analytics/answer/13965727). If you exceed this limit, the
  Measurement Protocol silently ignores all non-conversion requests for the
  property for the remainder of the hour.

  > [!IMPORTANT]
  > **Key Point:** This limit doesn't apply to Google Analytics 360 properties.

- Requests can have a maximum of 25 events.

- Events can have a maximum of 25 parameters.

- Events can have a maximum of 25 user properties.

- User property names must be 24 characters or fewer.

- User property values must be 36 characters or fewer.

- Event names must be 40 characters or fewer, can only contain alphanumeric
  characters and underscores, and must start with an alphabetic character.

- Parameter names including item parameters must be 40 characters or fewer,
  can only contain alphanumeric characters and underscores, and must start
  with an alphabetic character.

- Parameter values including item parameter values must be 100 characters or
  fewer for a standard Google Analytics property, and 500 characters or fewer
  for a Google Analytics 360 property.

  This limit doesn't apply to the `session_id` and `session_number` parameters
  when their values are provided by the corresponding [Analytics Session ID](https://support.google.com/tagmanager/answer/7182738#utilities)
  and [Analytics Session Number](https://support.google.com/tagmanager/answer/7182738#utilities)
  built-in variables in Google Tag Manager.
- Item parameters can have a maximum of 10 custom parameters.

- The post body must be smaller than 130kB.

- App Measurement Protocol events sent to Google Analytics don't populate Search
  audiences in Google Ads for app users.

- Some event, parameter, and user property names are reserved and
  cannot be used. See [Reserved names](https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events#reserved_names) for
  details.

### Reserved names

The Measurement Protocol has several [reserved names](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference#reserved_names) that
cannot be used for events, parameters, or user properties.

The following event names are common points of confusion:

- `screen_view`: This event is [only allowed for App
  streams](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference#reserved_names). For web streams, use `page_view` instead.
- `ad_impression`: This event is [only allowed for App
  streams](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference#reserved_names).
- `in_app_purchase`: This event is [only allowed for App
  streams](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference#reserved_names). For web streams, use the [`purchase`](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#purchase) event instead.

For additional requirements of each use case, see [common use cases](https://developers.google.com/analytics/devguides/collection/protocol/ga4/use-cases).