Понимание доставки сообщений

For troubleshooting ongoing message delivery failures, use the FCM troubleshooter and see this blog post to understand the different reasons why you may not see your message. You can also visit the FCM status dashboard to identify if there are any ongoing service disruptions affecting FCM.

FCM также предоставляет три набора инструментов, которые помогут вам получить представление о всесторонней оценке успеха и стратегии обмена сообщениями:

  • Отчеты о доставке сообщений в консоли Firebase
  • Сводные метрики доставки Android SDK из Firebase Cloud Messaging Data API
  • Комплексный экспорт данных в Google BigQuery

Для экспорта данных в BigQuery и работы вкладки «Отчеты» в консоли Firebase требуется Google Analytics . Вы можете включить Google Analytics в настройках. > Вкладка «Интеграции» в консоли Firebase . Для работы функции «Агрегированные данные доставки » Google Analytics не требуется.

Учтите, что отображение многих статистических данных на этой странице может задерживаться до 24 часов из-за пакетной обработки аналитических данных.

Отчеты о доставке сообщений

In the Firebase console, go to the DevOps & Engagement > Messaging > Reports tab to view the following data for messages sent to Android or Apple platform FCM SDKs, including those sent using the Notifications composer and the FCM APIs:

  • Отправлено — Сообщение данных или уведомление поставлено в очередь на доставку или успешно передано стороннему сервису, например, APNs, для доставки. Обратите внимание, что статистика отправленных сообщений может отображаться с задержкой в ​​несколько часов. Дополнительную информацию см. в разделе «Срок жизни сообщения» .
  • Получено (доступно только на устройствах Android) — Приложение получило сообщение с данными или уведомление. Эти данные доступны, если на принимающем устройстве Android установлен FCM SDK версии 18.0.1 или выше.
  • Показы (доступно только для уведомлений на устройствах Android) — Уведомление отображалось на устройстве, пока приложение работало в фоновом режиме.
  • Открытие — Пользователь открыл уведомление. Сообщается только об уведомлениях, полученных, когда приложение находится в фоновом режиме.

This data is available for all messages with a notification payload and all labeled data messages . To learn more about labels, see Adding analytics labels to messages .

When viewing message reports, you can set a date range for the data displayed, with the option to export to CSV. You can also filter by these criteria:

  • Платформа (iOS или Android)
  • Приложение
  • Пользовательские аналитические метки

Добавление аналитических меток к сообщениям

Добавление меток к сообщениям очень полезно для пользовательского анализа, позволяя фильтровать статистику доставки по меткам или наборам меток. Вы можете добавить метку к любому сообщению, отправленному с использованием API HTTP v1, установив поле fcmOptions.analyticsLabel в объекте сообщения или в полях AndroidFcmOptions или ApnsFcmOptions , специфичных для платформы.

Analytics labels are text strings in the format ^[a-zA-Z0-9-_.~%]{1,50}$ . Labels can include lower and upper case letters, numbers, and the following symbols:

  • -
  • ~
  • %

Максимальная длина — 50 символов. Вы можете указать до 100 уникальных меток в день; сообщения с метками, добавленными сверх этого лимита, не отображаются в результатах поиска.

In the Firebase console messaging Reports tab, you can search a list of all existing labels and apply them singly or in combination to filter the statistics displayed.

Агрегированные данные о доставке с использованием API данных FCM

API данных Firebase Cloud Messaging позволяет получать информацию, которая поможет вам понять результаты запросов сообщений, предназначенных для приложений Android. API предоставляет агрегированные данные по всем устройствам Android в проекте, поддерживающим сбор данных. Это включает в себя подробную информацию о проценте сообщений, доставленных без задержек, а также о количестве сообщений, задержанных или потерянных на уровне транспортного уровня Android . Анализ этих данных может выявить общие тенденции в доставке сообщений и помочь вам найти эффективные способы повышения производительности ваших запросов на отправку. См. раздел «Агрегированные временные шкалы данных» для получения информации о доступных диапазонах дат в отчетах.

The API provides all data available for a given application. See the API reference documentation .

Как структурированы данные?

Данные о доставке разбиты по приложению, дате и метке аналитики . Вызов API вернет данные для любой комбинации даты, приложения и метки аналитики. Например, один объект JSON androidDeliveryData будет выглядеть так:

 {
  "appId": "1:23456789:android:a93a5mb1234efe56",
  "date": {
    "year": 2021,
    "month": 1,
    "day": 1
  },
  "analyticsLabel": "foo",
  "data": {
    "countMessagesAccepted": "314159",
    "messageOutcomePercents": {
      "delivered": 71,
      "pending": 15
    },
   "deliveryPerformancePercents": {
      "deliveredNoDelay": 45,
      "delayedDeviceOffline": 11
    }
  }

Как интерпретировать метрики

Delivery data outlines the percentage of messages that fit each of the following metrics. It is possible that a single message fits multiple metrics. Due to limitations in how we collect the data and the level of granularity at which we aggregated the metrics, some message outcomes are not represented in the metrics at all, so the percentages below will not sum to 100%.

Подсчет принятых сообщений

The only count included in the dataset is the count of messages that were accepted by FCM for delivery to Android devices. All percentages use this value as the denominator. Keep in mind that this count won't include messages targeted to users who have disabled the collection of usage and diagnostic information on their devices.

Процент результатов сообщения

The fields included in the MessageOutcomePercents object provide information on the outcomes of message requests. The categories are all mutually exclusive. It can answer questions such as "Are my messages being delivered?" and "What is causing messages to be dropped?"

Например, высокое значение поля droppedTooManyPendingMessages может сигнализировать о том, что экземпляры приложения получают объемы несворачиваемых сообщений, превышающие лимит FCM в 100 ожидающих сообщений. Чтобы это предотвратить, убедитесь, что ваше приложение обрабатывает вызовы onDeletedMessages , и рассмотрите возможность отправки сворачиваемых сообщений. Аналогично, высокие значения поля droppedDeviceInactive могут сигнализировать о необходимости обновления токенов регистрации на вашем сервере, удаления устаревших токенов и отмены подписки на них. См. раздел «Управление токенами регистрации FCM для получения рекомендаций по этой теме.

Процент выполнения доставки

Поля объекта DeliveryPerformancePercents предоставляют информацию об успешно доставленных сообщениях. Они могут ответить на такие вопросы, как «Были ли мои сообщения задержаны?» и «Почему сообщения задерживаются?». Например, высокое значение параметра delayedMessageThrottled явно указывает на превышение максимальных лимитов для каждого устройства , и следует скорректировать скорость отправки сообщений.

Процентное соотношение анализа сообщений

Этот объект предоставляет дополнительную информацию обо всех отправленных сообщениях. Поле priorityLowered показывает процент принятых сообщений, приоритет которых был понижен с HIGH до NORMAL . Если это значение высокое, попробуйте отправлять меньше сообщений с высоким приоритетом или убедитесь, что вы всегда отображаете уведомление при отправке сообщения с высоким приоритетом. Дополнительную информацию см. в нашей документации по приоритетам сообщений.

How does this data differ from data exported to BigQuery?

The BigQuery export provides individual message logs about message acceptance by the FCM backend and message delivery in the SDK on the device (Steps 2 and 4 of the FCM Architecture ). This data is useful for ensuring individual messages were accepted and delivered. Read more about BigQuery data export in the next section.

В отличие от этого, API данных Firebase Cloud Messaging предоставляет агрегированные сведения о том, что происходит конкретно на транспортном уровне Android (или на шаге 3 архитектуры FCM ). Эти данные позволяют получить представление о доставке сообщений от бэкэндов FCM к Android SDK. Они особенно полезны для выявления тенденций, объясняющих, почему сообщения задерживались или отбрасывались во время этой передачи.

In some cases, it is possible that the two data sets might not match precisely due to the following:

  • The aggregated metrics only sample a portion of all messages
  • Сводные показатели округлены.
  • We don't present metrics below a privacy threshold
  • A portion of message outcomes are missing due to optimizations in how we manage the large volume of traffic.

Ограничения API

Сводные временные шкалы данных

API возвращает исторические данные за 7 дней; однако данные, возвращаемые этим API, могут быть задержаны на срок до 5 дней. Например, 20 января данные за период с 9 по 15 января будут доступны, но данные за 16 января и позже будут недоступны. Кроме того, данные предоставляются по мере возможности. В случае сбоя в предоставлении данных FCM будет работать над устранением проблемы и не будет заполнять данные после ее решения. При более масштабных сбоях данные могут быть недоступны в течение недели или более.

Покрытие данных

Метрики, предоставляемые API данных Firebase Cloud Messaging, призваны дать представление об общих тенденциях доставки сообщений. Однако они не обеспечивают 100% охвата всех сценариев обмена сообщениями. Следующие сценарии представляют собой известные результаты, не отраженные в метриках.

Устаревшие сообщения

If the Time To Live (TTL) expires after the end of the given log date, the message won't be counted as droppedTtlExpired on this date.

Сообщения на неактивные устройства

Сообщения, отправленные на неактивные устройства, могут отображаться или не отображаться в наборе данных в зависимости от выбранного пути передачи данных. Это может привести к ошибкам в подсчете в полях droppedDeviceInactive и pending .

Messages to devices with certain user preferences

Users who have disabled the collection of usage and diagnostic information on their devices won't have their messages included in our counting, in keeping with their preferences.

Округление и минимальные значения

Компания FCM намеренно округляет и исключает данные, где объемы недостаточно велики.

экспорт данных BigQuery

You can export your message data into BigQuery for further analysis. BigQuery lets you analyze the data using BigQuery SQL, export it to another cloud provider, or use the data for your custom ML models. An export to BigQuery includes all available data for messages, regardless of message type or whether the message is sent using the API or the Notifications composer.

For messages sent to devices with the following FCM SDK minimum versions, you have the additional option to enable the export of message delivery data for your app:

  • Android 20.1.0 или выше.
  • iOS 8.6.0 или выше
  • Firebase Web SDK 9.0.0 или выше

Для начала свяжите свой проект с BigQuery с помощью консоли Firebase :

  1. Выберите один из следующих вариантов:

    • Go to the DevOps & Engagement > Messaging > the Notifications composer , then click Access BigQuery at the bottom of the page.

    • Перейдите в > Вкладка «Интеграции» . Затем в BigQuery нажмите «Связать» .

      This page displays FCM export options for all FCM -enabled apps in the project.

  2. Follow the on-screen instructions to enable BigQuery .

Refer to Link Firebase to BigQuery for more information.

When you enable BigQuery export for Cloud Messaging :

  • Firebase exports your data to BigQuery . Note that the initial propagation of data for export may take up to 48 hours to complete.

  • After the dataset is created, the location can't be changed, but you can copy the dataset to a different location or manually move (recreate) the dataset in a different location. To learn more, see Change dataset location .

  • Firebase sets up regular syncs of your data from your Firebase project to BigQuery . These daily export operations begin at 4:00 AM Pacific Time and usually finish in 24 hours.

  • By default, all apps in your project are linked to BigQuery and any apps that you later add to the project are automatically linked to BigQuery . You can manage which apps send data .

To deactivate BigQuery export, unlink your project in the Firebase console.

Включить экспорт данных о доставке сообщений

iOS+

Устройства iOS с установленным FCM SDK версии 8.6.0 или выше могут включить экспорт данных о доставке сообщений из своего приложения. FCM поддерживает экспорт данных как для оповещений, так и для фоновых уведомлений. Экспорт данных по умолчанию отключен на уровне приложения . Программное включение его на уровне экземпляра приложения позволяет запрашивать у конечных пользователей разрешение на анализ данных о доставке их сообщений (рекомендуется). Если оба параметра заданы, значение на уровне экземпляра приложения переопределяет значение на уровне приложения.

Before enabling these options, you must first create the FCM -BiqQuery link for your project as described in BigQuery data export .

Enable delivery data export for alert notifications

Because only alert notifications can trigger notification service app extensions, you must add a notification service extension to your app and call this API inside a service extension to enable display message tracking. See Apple's documentation on Modifying Content in Newly Delivered Notifications

The following call must be made for every notification received:

Быстрый

// For alert notifications, call the API inside the service extension:
class NotificationService: UNNotificationServiceExtension {
  override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
  Messaging.extensionHelper()
      .exportDeliveryMetricsToBigQuery(withMessageInfo:request.content.userInfo)
  }
}

Objective-C

// For alert notifications, call the API inside the service extension:
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request
                   withContentHandler:(void (^)(UNNotificationContent *_Nonnull))contentHandler {
  [[FIRMessaging extensionHelper] exportDeliveryMetricsToBigQueryWithMessageInfo:request.content.userInfo];
}
@end

If you are building send requests using the HTTP v1 API, make sure to specify `mutable-content = 1` in the payload object .

Включите экспорт данных о доставке для фоновых уведомлений.

For background messages received when the app is in the foreground or background, you can call the data export API inside the main app's data message handler. This call must be made for every notification received:

Быстрый

// For background notifications, call the API inside the
// UIApplicationDelegate or NSApplicationDelegate method:
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
  Messaging.extensionHelper().exportDeliveryMetricsToBigQuery(withMessageInfo:userInfo)
}

Objective-C

// For background notifications, call the API inside the
// UIApplicationDelegate or NSApplicationDelegate method:
@implementation AppDelegate
- (void)application:(UIApplication *)application
    didReceiveRemoteNotification:(NSDictionary *)userInfo
          fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  [[FIRMessaging extensionHelper] exportDeliveryMetricsToBigQueryWithMessageInfo:userInfo];
}
@end

Android

Android devices with the FCM SDK 20.1.0 or higher can enable their app's message delivery data export. Data export is disabled by default at the app level . Programmatically enabling it at the app instance level lets you ask end users for permission to analyze their message delivery data (recommended). When both are set, the app instance level value overrides the app level value.

Прежде чем включить эти параметры, необходимо сначала создать связь FCM -BiqQuery для вашего проекта, как описано в разделе «Экспорт данных BigQuery» .

Включить экспорт данных о доставке для экземпляров приложения

For most cases, we recommend that you enable message delivery data export only at the app instance level and leave it disabled at the app level.

FirebaseMessaging.getInstance().setDeliveryMetricsExportToBigQuery(true);

Включить экспорт данных о доставке для приложения

Если вы предпочитаете включить экспорт на уровне приложения, убедитесь, что не вызываете метод setDeliveryMetricsExportToBigQuery , и добавьте следующее свойство в объект приложения в манифесте вашего приложения:

<application>
  <meta-data android:name="delivery_metrics_exported_to_big_query_enabled"
      android:value="true" />
</application>

Веб

FCM SDK для веб-приложений версии 9.0.0 предоставляет альфа-версию экспорта данных о доставке сообщений. Экспорт данных по умолчанию отключен на уровне приложения . Программное включение его на уровне экземпляра приложения позволяет запрашивать у конечных пользователей разрешение на анализ данных о доставке их сообщений (рекомендуется). Если оба параметра заданы, значение на уровне экземпляра приложения переопределяет значение на уровне приложения. Когда конечный пользователь дает согласие или отклоняет сбор данных, приложение должно установить экспериментальный флаг включения или отключения для каждого экземпляра приложения, как показано ниже:

// userConsent holds the decision of the user to give big query export consent.
const userConsent = ...;

const messaging = getMessagingInSw(app);

experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, userConsent);

Какие данные экспортируются в BigQuery?

Следует отметить, что таргетирование устаревших токенов или неактивных регистраций может завышать некоторые из этих статистических данных.

Схема экспортируемой таблицы следующая:

_ВРЕМЯ РАЗДЕЛЕНИЯ ОТМЕТКА ВРЕМЕНИ Этот псевдостолбец содержит метку времени начала дня (в формате UTC), в который были загружены данные. Для раздела YYYYMMDD этот псевдостолбец содержит значение TIMESTAMP('YYYY-MM-DD').
event_timestamp ОТМЕТКА ВРЕМЕНИ Отметка времени события, записанная сервером.
номер_проекта ЦЕЛОЕ The project number identifies the project that sent the message
message_id НИТЬ Идентификатор сообщения (message ID) определяет сообщение. Созданный на основе идентификатора приложения (App ID) и метки времени, идентификатор сообщения в некоторых случаях может быть не уникальным в глобальном масштабе.
instance_id НИТЬ Уникальный идентификатор приложения, которому отправляется сообщение (если доступен). Это может быть идентификатор экземпляра или идентификатор установки Firebase .
message_type НИТЬ Тип сообщения. Может быть уведомлением или сообщением с данными. Тема используется для идентификации исходного сообщения для темы или рассылки кампании; последующие сообщения могут быть либо уведомлением, либо сообщением с данными.
sdk_platform НИТЬ Платформа приложения получателя
имя_приложения НИТЬ Имя пакета для приложений Android или идентификатор пакета для приложений iOS.
collapse_key НИТЬ The collapse key identifies a group of messages that can be collapsed. When a device is not connected, only the last message with a given collapse key is queued for eventual delivery
приоритет ЦЕЛОЕ The priority of the message. 5 is "normal" priority and 10 is "high" priority.
ттл ЦЕЛОЕ Этот параметр определяет, как долго (в секундах) сообщение должно храниться в памяти FCM, если устройство находится в автономном режиме.
тема НИТЬ Название темы, по которой было отправлено сообщение (если применимо).
bulk_id ЦЕЛОЕ Идентификатор группы сообщений (bulk ID) определяет группу связанных сообщений, например, конкретную отправку в определенную тему.
событие НИТЬ Тип события. Возможные значения:
  • MESSAGE_ACCEPTED: the message was received by the FCM server and the request is valid;
  • MESSAGE_DELIVERED: сообщение доставлено в SDK FCM приложения на устройстве. По умолчанию это поле не передается. Чтобы включить его, следуйте инструкциям, приведенным в setDeliveryMetricsExportToBigQuery(boolean) .
  • MISSING_REGISTRATIONS: the request was rejected due to a missing registration;
  • UNAUTHORIZED_REGISTRATION: сообщение было отклонено, поскольку отправитель не имеет права отправлять его на регистрацию;
  • MESSAGE_RECEIVED_INTERNAL_ERROR: при обработке запроса сообщения произошла неуказанная ошибка;
  • MISMATCH_SENDER_ID: the request to send a message was rejected due to a mismatch between the sender id sending the message, and the one declared for the end-point;
  • QUOTA_EXCEEDED: запрос на отправку сообщения был отклонен из-за недостаточной квоты;
  • INVALID_REGISTRATION: запрос на отправку сообщения был отклонен из-за недействительной регистрации;
  • INVALID_PACKAGE_NAME: запрос на отправку сообщения был отклонен из-за недопустимого имени пакета;
  • INVALID_APNS_CREDENTIAL: запрос на отправку сообщения был отклонен из-за недействительного сертификата APNS;
  • INVALID_PARAMETERS: запрос на отправку сообщения был отклонен из-за недопустимых параметров;
  • PAYLOAD_TOO_LARGE: запрос на отправку сообщения был отклонен из-за превышения лимита полезной нагрузки;
  • AUTHENTICATION_ERROR: запрос на отправку сообщения был отклонен из-за ошибки аутентификации (проверьте ключ API, использованный для отправки сообщения);
  • INVALID_TTL: запрос на отправку сообщения был отклонен из-за недопустимого значения TTL.
analytics_label НИТЬ С помощью API HTTP v1 можно установить метку аналитики при отправке сообщения, чтобы пометить его для целей аналитики.

Что можно сделать с экспортированными данными?

В следующих разделах приведены примеры запросов, которые можно выполнить в BigQuery к экспортированным данным FCM .

Подсчет отправленных сообщений приложением

SELECT app_name, COUNT(1)
FROM `project ID.firebase_messaging.data`
WHERE
  _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
  AND event = 'MESSAGE_ACCEPTED'
  AND message_id != ''
GROUP BY 1;

Подсчитайте количество уникальных экземпляров приложения, на которые были направлены сообщения.

SELECT COUNT(DISTINCT instance_id)
FROM `project ID.firebase_messaging.data`
WHERE
  _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
  AND event = 'MESSAGE_ACCEPTED';

Подсчет отправленных уведомлений

SELECT COUNT(1)
FROM `project ID.firebase_messaging.data`
WHERE
  _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
  AND event = 'MESSAGE_ACCEPTED'
  AND message_type = 'DISPLAY_NOTIFICATION';

Подсчет отправленных сообщений с данными

SELECT COUNT(1)
FROM `project ID.firebase_messaging.data`
WHERE
  _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
  AND event = 'MESSAGE_ACCEPTED'
  AND message_type = 'DATA_MESSAGE';

Подсчитайте количество сообщений, отправленных по определенной теме или в рамках кампании.

SELECT COUNT(1)
FROM `project ID.firebase_messaging.data`
WHERE
  _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
  AND event = 'MESSAGE_ACCEPTED'
  AND bulk_id = your bulk id AND message_id != '';

Чтобы отслеживать события, связанные с сообщением, отправленным в определенную тему, измените этот запрос, заменив AND message_id != '' на AND message_id = <your message id>; .

Вычислите продолжительность распространения информации по заданной теме или кампании.

Время начала распространения запроса — это момент получения исходного запроса, а время окончания — это момент создания последнего отдельного сообщения, предназначенного для конкретного экземпляра.

SELECT
  TIMESTAMP_DIFF(
    end_timestamp, start_timestamp, MILLISECOND
  ) AS fanout_duration_ms,
  end_timestamp,
  start_timestamp
FROM (
    SELECT MAX(event_timestamp) AS end_timestamp
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
      AND event = 'MESSAGE_ACCEPTED'
      AND bulk_id = your bulk id
  ) sent
  CROSS JOIN (
    SELECT event_timestamp AS start_timestamp
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
      AND event = 'MESSAGE_ACCEPTED'
      AND bulk_id = your bulk id
      AND message_type = 'TOPIC'
  ) initial_message;

Подсчитайте процент доставленных сообщений

SELECT
  messages_sent,
  messages_delivered,
  messages_delivered / messages_sent * 100 AS percent_delivered
FROM (
    SELECT COUNT(DISTINCT CONCAT(message_id, instance_id)) AS messages_sent
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
      AND event = 'MESSAGE_ACCEPTED'
  ) sent
  CROSS JOIN (
    SELECT COUNT(DISTINCT CONCAT(message_id, instance_id)) AS messages_delivered
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
      AND (event = 'MESSAGE_DELIVERED'
      AND message_id
      IN (
        SELECT message_id FROM `project ID.firebase_messaging.data`
        WHERE
          _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
          AND event = 'MESSAGE_ACCEPTED'
        GROUP BY 1
      )
  ) delivered;

Отслеживайте все события для заданного идентификатора сообщения и идентификатора экземпляра.

SELECT *
FROM `project ID.firebase_messaging.data`
WHERE
    _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
    AND message_id = 'your message id'
    AND instance_id = 'your instance id'
ORDER BY event_timestamp;

Вычислите задержку для заданного идентификатора сообщения и идентификатора экземпляра.

SELECT
  TIMESTAMP_DIFF(
    MAX(delivered_time), MIN(accepted_time), MILLISECOND
  ) AS latency_ms
FROM (
    SELECT event_timestamp AS accepted_time
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
      AND message_id = 'your message id'
      AND instance_id = 'your instance id'
      AND event = 'MESSAGE_ACCEPTED'
  ) sent
  CROSS JOIN (
    SELECT event_timestamp AS delivered_time
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD') AND
      message_id = 'your message id' AND instance_id = 'your instance id'
      AND (event = 'MESSAGE_DELIVERED'
  ) delivered;