Vue d'ensemble

L'API Data de Google Analytics v1 vous permet de générer des rapports sur les entonnoirs. L'exploration de l'entonnoir vous permet de visualiser les étapes suivies par vos utilisateurs pour effectuer une tâche. Vous pouvez ainsi voir rapidement s'ils réussissent ou s'ils échouent à chaque étape.

Fonctionnalités partagées avec les rapports principaux

Les requêtes de reporting sur les entonnoirs ont la même sémantique que les demandes de rapports Core pour de nombreuses fonctionnalités partagées. Par exemple, la pagination, les filtres de dimensions et les propriétés utilisateur se comportent de la même manière dans les rapports sur les entonnoirs que dans les rapports principaux. Ce guide est consacré aux fonctionnalités de création de rapports sur les entonnoirs. Pour vous familiariser avec les fonctionnalités principales de création de rapports de la version 1 de l'API Data, consultez les principes de base des rapports, ainsi que le guide des cas d'utilisation avancés.

Méthode de reporting sur les entonnoirs

Data API v1 est compatible avec la fonctionnalité de création de rapports sur les entonnoirs via la méthode runFunnelReport. Cette méthode renvoie un rapport personnalisé sur l'entonnoir contenant vos données d'événement Google Analytics.

Sélection d'une entité à l'origine du signalement

Toutes les méthodes de l'API Data v1 nécessitent que l'identifiant de propriété Google Analytics 4 soit spécifié dans un chemin de requête d'URL au format properties/GA4_PROPERTY_ID, par exemple:

  POST  https://analyticsdata.googleapis.com/v1alpha/properties/GA4_PROPERTY_ID:runFunnelReport

Le rapport obtenu sera généré en fonction des données d'événement Google Analytics collectées dans la propriété Google Analytics 4 spécifiée.

Si vous utilisez l'une des bibliothèques clientes des API Data, il n'est pas nécessaire de manipuler manuellement le chemin de l'URL de la requête. La plupart des clients d'API fournissent un paramètre property qui attend une chaîne au format properties/GA4_PROPERTY_ID. Consultez le guide de démarrage rapide pour obtenir des exemples d'utilisation des bibliothèques clientes.

Demande de rapport sur les entonnoirs

Pour demander un rapport sur les entonnoirs, vous pouvez créer un objet RunFunnelReportRequest. Nous vous recommandons de commencer par les paramètres de requête suivants:

  • Une entrée valide dans le champ dateRanges.

  • Une spécification d'entonnoir valide dans le champ funnel

Spécifications de l'entonnoir

Une spécification d'entonnoir dans le champ funnel d'un objet RunFunnelReportRequest définit le parcours utilisateur que vous souhaitez mesurer en décrivant le steps de cet entonnoir.

Les étapes de l'entonnoir contiennent une ou plusieurs conditions que les utilisateurs doivent remplir pour être inclus dans cette étape du parcours de l'entonnoir. Les conditions d'inclusion dans chaque étape peuvent être décrites dans le champ filterExpression de chaque étape.

Chaque expression de filtre d'entonnoir est une combinaison de deux types de filtres:

  • funnelFieldFilter crée un filtre pour une dimension ou une métrique.

  • funnelEventFilter crée un filtre qui correspond aux événements d'un seul nom d'événement. Si un champ funnelParameterFilterExpression facultatif est spécifié, seul le sous-ensemble d'événements qui correspond à la fois au nom d'événement unique et aux expressions de filtre de paramètre correspond à ce filtre d'événement.

Les filtres peuvent être combinés à l'aide de groupes AND et OR, et écartés à l'aide d'une expression NOT.

Les résultats de chaque étape de l'entonnoir de conversion sont ventilés en fonction de la dimension et spécifiés dans le champ funnelBreakdown.

Exemple de rapport sur les entonnoirs

Utilisons l'API Google Analytics Data v1 pour reproduire le rapport sur les entonnoirs par défaut fourni dans le modèle Exploration de l'entonnoir de l'interface utilisateur Google Analytics:

Exemple d'interface utilisateur de rapport sur les entonnoirs

Étapes de l'entonnoir de conversion

La configuration de l'entonnoir ci-dessus comprend les étapes suivantes:

# Nom de l'étape Condition
1 Première ouverture/visite Le nom de l'événement est first_open ou first_visit.
2 Visiteurs naturels La dimension firstUserMedium contient le terme "résultats naturels".
3 Ouverture de session Nom de l'événement : session_start.
4 Vue d'écran/Page vue Le nom de l'événement est screen_view ou page_view.
5 Acheter Le nom de l'événement est purchase ou in_app_purchase.

L'étape 1 (Première ouverture/visite) de l'entonnoir inclut tous les utilisateurs après leur première interaction avec un site Web ou une application (c'est-à-dire les utilisateurs qui ont déclenché des événements first_open ou first_visit).

Pour implémenter ce comportement, l'extrait ci-dessous spécifie un objet FunnelStep avec un champ filterExpression. Le champ d'expression de filtre est un objet FunnelFilterExpression construit en combinant deux entités FunnelEventFilter à l'aide d'un groupe OR.

  {
    "name": "Purchase",
    "filterExpression": {
      "orGroup": {
        "expressions": [
          {
            "funnelEventFilter": {
              "eventName": "first_open"
            }
          },
          {
            "funnelEventFilter": {
              "eventName": "first_visit"
            }
          }
        ]
      }
    }
  }

L'Étape 2 (Visiteurs naturels) de l'entonnoir inclut les utilisateurs dont le premier support inclut le terme "naturel". Dans l'extrait ci-dessous, le champ fieldName de FunnelFieldFilter indique au filtre de correspondre à la dimension firstUserMedium. Le champ stringFilter contient une condition pour n'inclure que les valeurs de la dimension contenant le terme "résultats naturels".

  {
    "name": "Organic visitors",
    "filterExpression": {
      "funnelFieldFilter": {
        "fieldName": "firstUserMedium",
        "stringFilter": {
          "matchType": "CONTAINS",
          "caseSensitive": false,
          "value": "organic"
        }
      }
    }
  }

Vous pouvez spécifier les étapes restantes de l'entonnoir de la même manière.

Dimension "Répartition"

Une dimension de répartition facultative (deviceCategory dans cet exemple) peut être spécifiée à l'aide d'un objet FunnelBreakdown:

  "funnelBreakdown": {
    "breakdownDimension": {
      "name": "deviceCategory"
    }
  }

Par défaut, seules les cinq premières valeurs distinctes de la dimension "Répartition" sont incluses dans le rapport. Vous pouvez utiliser le champ limit de l'objet FunnelBreakdown pour ignorer ce comportement.

Requête de rapport complète sur les entonnoirs

Voici une requête complète qui génère un rapport sur les entonnoirs en utilisant toutes les étapes décrites ci-dessus:

HTTP

POST https://analyticsdata.googleapis.com/v1alpha/properties/GA4_PROPERTY_ID:runFunnelReport
{
  "dateRanges": [
    {
      "startDate": "30daysAgo",
      "endDate": "today"
    }
  ],
  "funnelBreakdown": {
    "breakdownDimension": {
      "name": "deviceCategory"
    }
  },
  "funnel": {
    "steps": [
      {
        "name": "First open/visit",
        "filterExpression": {
          "orGroup": {
            "expressions": [
              {
                "funnelEventFilter": {
                  "eventName": "first_open"
                }
              },
              {
                "funnelEventFilter": {
                  "eventName": "first_visit"
                }
              }
            ]
          }
        }
      },
      {
        "name": "Organic visitors",
        "filterExpression": {
          "funnelFieldFilter": {
            "fieldName": "firstUserMedium",
            "stringFilter": {
              "matchType": "CONTAINS",
              "caseSensitive": false,
              "value": "organic"
            }
          }
        }
      },
      {
        "name": "Session start",
        "filterExpression": {
          "funnelEventFilter": {
            "eventName": "session_start"
          }
        }
      },
      {
        "name": "Screen/Page view",
        "filterExpression": {
          "orGroup": {
            "expressions": [
              {
                "funnelEventFilter": {
                  "eventName": "screen_view"
                }
              },
              {
                "funnelEventFilter": {
                  "eventName": "page_view"
                }
              }
            ]
          }
        }
      },
      {
        "name": "Purchase",
        "filterExpression": {
          "orGroup": {
            "expressions": [
              {
                "funnelEventFilter": {
                  "eventName": "purchase"
                }
              },
              {
                "funnelEventFilter": {
                  "eventName": "in_app_purchase"
                }
              }
            ]
          }
        }
      }
    ]
  }
}

Signaler la réponse

La réponse de rapport sur les entonnoirs d'une requête d'API de rapport sur les entonnoirs se compose des deux parties principales, toutes deux renvoyées sous la forme d'un objet FunnelSubReport: Schéma de l'entonnoir et Tableau de l'entonnoir.

Schéma de l'entonnoir de conversion

Le schéma de l'entonnoir, affiché dans le champ funnelVisualization de la réponse au rapport sur les entonnoirs, contient une vue d'ensemble du rapport sur les entonnoirs. Comme son nom l'indique, cette fonctionnalité est utile pour visualiser rapidement le rapport sur les entonnoirs généré.

Chaque ligne du tableau de visualisation de l'entonnoir contient tout ou partie des champs suivants:

  • Nom de l'étape de l'entonnoir (dimension funnelStepName).

  • Nombre d'utilisateurs actifs (métrique : activeUsers).

  • Segmenter (segment dimension). Présent uniquement si Segment est spécifié dans la requête de l'entonnoir.

  • Date (dimension date). Présent uniquement si le type de visualisation TRENDED_FUNNEL a été spécifié dans la requête.

  • Dimension d'action suivante (dimension funnelStepNextAction). Présent uniquement si FunnelNextAction est spécifié dans la requête de l'entonnoir.

Voici comment l'interface utilisateur Google Analytics affiche la section "Schéma de l'entonnoir" de l'exemple de rapport décrit ci-dessus:

En-têtes de rapport sur les entonnoirs: exemple

Tableau de l'entonnoir

Le tableau d'entonnoir, renvoyé dans le champ funnelTable de la réponse au rapport sur les entonnoirs, représente la partie principale du rapport. Chaque ligne de la table contient tout ou partie des champs suivants:

  • Nom de l'étape de l'entonnoir (dimension funnelStepName).

  • Dimension "Répartition".

  • Nombre d'utilisateurs actifs (métrique : activeUsers).

  • Taux d'achèvement des étapes (métrique : funnelStepCompletionRate).

  • Nombre d'abandons d'étape (métrique funnelStepAbandonments).

  • Taux d'abandon des étapes (métrique funnelStepAbandonmentRate).

  • Nom du segment (segment dimension). Présent uniquement si Segment est spécifié dans la requête de l'entonnoir.

Comme pour la fonctionnalité principale de reporting, les valeurs totales sont renvoyées dans une ligne distincte, avec RESERVED_TOTAL comme valeur de la dimension "Répartition".

Vous trouverez ci-dessous un exemple de tableau d'entonnoir affiché dans l'interface utilisateur Google Analytics : Tableau du rapport sur les entonnoirs de conversion: exemple

Réponse brute

L'extrait ci-dessous illustre un exemple de données brutes renvoyées en réponse à la requête runFunnelReport.

En fonction des données collectées par votre propriété, l'exemple de rapport ci-dessus renverrait le rapport suivant, qui indique le nombre d'utilisateurs actifs inclus dans chaque étape de l'entonnoir de conversion.

{
  "funnelTable": {
    "dimensionHeaders": [
      {
        "name": "funnelStepName"
      },
      {
        "name": "deviceCategory"
      }
    ],
    "metricHeaders": [
      {
        "name": "activeUsers",
        "type": "TYPE_INTEGER"
      },
      {
        "name": "funnelStepCompletionRate",
        "type": "TYPE_INTEGER"
      },
      {
        "name": "funnelStepAbandonments",
        "type": "TYPE_INTEGER"
      },
      {
        "name": "funnelStepAbandonmentRate",
        "type": "TYPE_INTEGER"
      }
    ],
    "rows": [
      {
        "dimensionValues": [
          {
            "value": "1. First open/visit"
          },
          {
            "value": "RESERVED_TOTAL"
          }
        ],
        "metricValues": [
          {
            "value": "4621565"
          },
          {
            "value": "0.27780178359495106"
          },
          {
            "value": "3337686"
          },
          {
            "value": "0.72219821640504889"
          }
        ]
      },
      {
        "dimensionValues": [
          {
            "value": "1. First open/visit"
          },
          {
            "value": "desktop"
          }
        ],
        "metricValues": [
          {
            "value": "4015959"
          },
          {
            "value": "0.27425279989163237"
          },
          {
            "value": "2914571"
          },
          {
            "value": "0.72574720010836768"
          }
        ]
      },
      {
        "dimensionValues": [
          {
            "value": "1. First open/visit"
          },
          {
            "value": "mobile"
          }
        ],
        "metricValues": [
          {
            "value": "595760"
          },
          {
            "value": "0.29156035987646034"
          },
          {
            "value": "422060"
          },
          {
            "value": "0.70843964012353966"
          }
        ]
      },
      {
        "dimensionValues": [
          {
            "value": "1. First open/visit"
          },
          {
            "value": "tablet"
          }
        ],
        "metricValues": [
          {
            "value": "33638"
          },
          {
            "value": "0.205571080325822"
          },
          {
            "value": "26723"
          },
          {
            "value": "0.79442891967417806"
          }
        ]
      },

...

    ],
    "metadata": {
      "samplingMetadatas": [
        {
          "samplesReadCount": "9917254",
          "samplingSpaceSize": "1162365416"
        }
      ]
    }
  },

  "funnelVisualization": {
    "dimensionHeaders": [
      {
        "name": "funnelStepName"
      }
    ],
    "metricHeaders": [
      {
        "name": "activeUsers",
        "type": "TYPE_INTEGER"
      }
    ],
    "rows": [
      {
        "dimensionValues": [
          {
            "value": "1. First open/visit"
          }
        ],
        "metricValues": [
          {
            "value": "4621565"
          }
        ]
      },

...

    ],
    "metadata": {
      "samplingMetadatas": [
        {
          "samplesReadCount": "9917254",
          "samplingSpaceSize": "1162365416"
        }
      ]
    }
  },
  "kind": "analyticsData#runFunnelReport"
}

Bibliothèques clientes

Consultez le guide de démarrage rapide pour découvrir comment installer et configurer les bibliothèques clientes.

Vous trouverez ci-dessous des exemples d'utilisation de bibliothèques clientes qui exécutent une requête d'entonnoir et impriment la réponse.

Java

import com.google.analytics.data.v1alpha.AlphaAnalyticsDataClient;
import com.google.analytics.data.v1alpha.DateRange;
import com.google.analytics.data.v1alpha.Dimension;
import com.google.analytics.data.v1alpha.DimensionHeader;
import com.google.analytics.data.v1alpha.FunnelBreakdown;
import com.google.analytics.data.v1alpha.FunnelEventFilter;
import com.google.analytics.data.v1alpha.FunnelFieldFilter;
import com.google.analytics.data.v1alpha.FunnelFilterExpression;
import com.google.analytics.data.v1alpha.FunnelFilterExpressionList;
import com.google.analytics.data.v1alpha.FunnelStep;
import com.google.analytics.data.v1alpha.FunnelSubReport;
import com.google.analytics.data.v1alpha.MetricHeader;
import com.google.analytics.data.v1alpha.Row;
import com.google.analytics.data.v1alpha.RunFunnelReportRequest;
import com.google.analytics.data.v1alpha.RunFunnelReportResponse;
import com.google.analytics.data.v1alpha.SamplingMetadata;
import com.google.analytics.data.v1alpha.StringFilter;
import com.google.analytics.data.v1alpha.StringFilter.MatchType;

/**
 * Google Analytics Data API sample application demonstrating the creation of a funnel report.
 *
 * <p>See
 * https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1alpha/properties/runFunnelReport
 * for more information.
 *
 * <p>Before you start the application, please review the comments starting with "TODO(developer)"
 * and update the code to use correct values.
 *
 * <p>To run this sample using Maven:
 *
 * <pre>{@code
 * cd google-analytics-data
 * mvn compile exec:java -Dexec.mainClass="com.google.analytics.data.samples.RunFunnelReportSample"
 * }</pre>
 */
public class RunFunnelReportSample {

  public static void main(String... args) throws Exception {
    /**
     * TODO(developer): Replace this variable with your Google Analytics 4 property ID before
     * running the sample.
     */
    String propertyId = "YOUR-GA4-PROPERTY-ID";
    sampleRunFunnelReport(propertyId);
  }

  /**
   * Runs a funnel query to build a report with 5 funnel steps.
   *
   * <ol>
   *   <li>First open/visit (event name is `first_open` or `first_visit`).
   *   <li>Organic visitors (`firstUserMedium` dimension contains the term "organic").
   *   <li>Session start (event name is `session_start`).
   *   <li>Screen/Page view (event name is `screen_view` or `page_view`).
   *   <li>Purchase (event name is `purchase` or `in_app_purchase`).
   * </ol>
   *
   * The report configuration reproduces the default funnel report provided in the Funnel
   * Exploration template of the Google Analytics UI. See more at
   * https://support.google.com/analytics/answer/9327974
   */
  static void sampleRunFunnelReport(String propertyId) throws Exception {

    // Using a default constructor instructs the client to use the credentials
    // specified in GOOGLE_APPLICATION_CREDENTIALS environment variable.
    try (AlphaAnalyticsDataClient analyticsData = AlphaAnalyticsDataClient.create()) {
      RunFunnelReportRequest.Builder requestBuilder =
          RunFunnelReportRequest.newBuilder()
              .setProperty("properties/" + propertyId)
              .addDateRanges(DateRange.newBuilder().setStartDate("30daysAgo").setEndDate("today"))
              .setFunnelBreakdown(
                  FunnelBreakdown.newBuilder()
                      .setBreakdownDimension(Dimension.newBuilder().setName("deviceCategory")));

      // Adds each step of the funnel.
      requestBuilder
          .getFunnelBuilder()
          .addSteps(
              FunnelStep.newBuilder()
                  .setName("First open/visit")
                  .setFilterExpression(
                      FunnelFilterExpression.newBuilder()
                          .setOrGroup(
                              FunnelFilterExpressionList.newBuilder()
                                  .addExpressions(
                                      FunnelFilterExpression.newBuilder()
                                          .setFunnelEventFilter(
                                              FunnelEventFilter.newBuilder()
                                                  .setEventName("first_open")))
                                  .addExpressions(
                                      FunnelFilterExpression.newBuilder()
                                          .setFunnelEventFilter(
                                              FunnelEventFilter.newBuilder()
                                                  .setEventName("first_visit"))))));
      requestBuilder
          .getFunnelBuilder()
          .addSteps(
              FunnelStep.newBuilder()
                  .setName("Organic visitors")
                  .setFilterExpression(
                      FunnelFilterExpression.newBuilder()
                          .setFunnelFieldFilter(
                              FunnelFieldFilter.newBuilder()
                                  .setFieldName("firstUserMedium")
                                  .setStringFilter(
                                      StringFilter.newBuilder()
                                          .setMatchType(MatchType.CONTAINS)
                                          .setCaseSensitive(false)
                                          .setValue("organic")))));
      requestBuilder
          .getFunnelBuilder()
          .addSteps(
              FunnelStep.newBuilder()
                  .setName("Session start")
                  .setFilterExpression(
                      FunnelFilterExpression.newBuilder()
                          .setFunnelEventFilter(
                              FunnelEventFilter.newBuilder().setEventName("session_start"))));

      requestBuilder
          .getFunnelBuilder()
          .addSteps(
              FunnelStep.newBuilder()
                  .setName("Screen/Page view")
                  .setFilterExpression(
                      FunnelFilterExpression.newBuilder()
                          .setOrGroup(
                              FunnelFilterExpressionList.newBuilder()
                                  .addExpressions(
                                      FunnelFilterExpression.newBuilder()
                                          .setFunnelEventFilter(
                                              FunnelEventFilter.newBuilder()
                                                  .setEventName("screen_view")))
                                  .addExpressions(
                                      FunnelFilterExpression.newBuilder()
                                          .setFunnelEventFilter(
                                              FunnelEventFilter.newBuilder()
                                                  .setEventName("page_view"))))));
      requestBuilder
          .getFunnelBuilder()
          .addSteps(
              FunnelStep.newBuilder()
                  .setName("Purchase")
                  .setFilterExpression(
                      FunnelFilterExpression.newBuilder()
                          .setOrGroup(
                              FunnelFilterExpressionList.newBuilder()
                                  .addExpressions(
                                      FunnelFilterExpression.newBuilder()
                                          .setFunnelEventFilter(
                                              FunnelEventFilter.newBuilder()
                                                  .setEventName("purchase")))
                                  .addExpressions(
                                      FunnelFilterExpression.newBuilder()
                                          .setFunnelEventFilter(
                                              FunnelEventFilter.newBuilder()
                                                  .setEventName("in_app_purchase"))))));

      // Make the request.
      RunFunnelReportResponse response = analyticsData.runFunnelReport(requestBuilder.build());
      printRunFunnelReportResponse(response);
    }
  }

  /** Prints results of a runFunnelReport call. */
  static void printRunFunnelReportResponse(RunFunnelReportResponse response) {
    System.out.println("Report result:");
    System.out.println("=== FUNNEL VISUALIZATION ===");
    printFunnelSubReport(response.getFunnelVisualization());

    System.out.println("=== FUNNEL TABLE ===");
    printFunnelSubReport(response.getFunnelTable());
  }

  /** Prints the contents of a FunnelSubReport object. */
  private static void printFunnelSubReport(FunnelSubReport funnelSubReport) {
    System.out.println("Dimension headers:");
    for (DimensionHeader dimensionHeader : funnelSubReport.getDimensionHeadersList()) {
      System.out.println(dimensionHeader.getName());
    }
    System.out.println();

    System.out.println("Metric headers:");
    for (MetricHeader metricHeader : funnelSubReport.getMetricHeadersList()) {
      System.out.println(metricHeader.getName());
    }
    System.out.println();

    System.out.println("Dimension and metric values for each row in the report:");
    for (int rowIndex = 0; rowIndex < funnelSubReport.getRowsCount(); rowIndex++) {
      Row row = funnelSubReport.getRows(rowIndex);
      for (int fieldIndex = 0; fieldIndex < row.getDimensionValuesCount(); fieldIndex++) {
        System.out.printf(
            "%s: '%s'%n",
            funnelSubReport.getDimensionHeaders(fieldIndex).getName(),
            row.getDimensionValues(fieldIndex).getValue());
      }
      for (int fieldIndex = 0; fieldIndex < row.getMetricValuesCount(); fieldIndex++) {
        System.out.printf(
            "%s: '%s'%n",
            funnelSubReport.getMetricHeaders(fieldIndex).getName(),
            row.getMetricValues(fieldIndex).getValue());
      }
    }
    System.out.println();

    System.out.println("Sampling metadata for each date range:");
    for (int metadataIndex = 0;
        metadataIndex < funnelSubReport.getMetadata().getSamplingMetadatasCount();
        metadataIndex++) {
      SamplingMetadata samplingMetadata =
          funnelSubReport.getMetadata().getSamplingMetadatas(metadataIndex);
      System.out.printf(
          "Sampling metadata for date range #%d: samplesReadCount=%d, samplingSpaceSize=%d%n",
          metadataIndex,
          samplingMetadata.getSamplesReadCount(),
          samplingMetadata.getSamplingSpaceSize());
    }
  }
}

Python

from google.analytics.data_v1alpha import AlphaAnalyticsDataClient
from google.analytics.data_v1alpha.types import (
    DateRange,
    Dimension,
    Funnel,
    FunnelBreakdown,
    FunnelEventFilter,
    FunnelFieldFilter,
    FunnelFilterExpression,
    FunnelFilterExpressionList,
    FunnelStep,
    RunFunnelReportRequest,
    StringFilter,
)


def run_sample():
    """Runs the sample."""
    # TODO(developer): Replace this variable with your Google Analytics 4
    #  property ID before running the sample.
    property_id = "YOUR-GA4-PROPERTY-ID"
    run_funnel_report(property_id)


def run_funnel_report(property_id="YOUR-GA4-PROPERTY-ID"):
    """Runs a funnel query to build a report with 5 funnel steps.
      Step 1: First open/visit (event name is `first_open` or `first_visit`).
      Step 2: Organic visitors (`firstUserMedium` dimension contains the term
      "organic").
      Step 3: Session start (event name is `session_start`).
      Step 4: Screen/Page view (event name is `screen_view` or `page_view`).
      Step 5: Purchase (event name is `purchase` or `in_app_purchase`).

    The report configuration reproduces the default funnel report provided in
    the Funnel Exploration template of the Google Analytics UI.
    See more at https://support.google.com/analytics/answer/9327974
    """
    client = AlphaAnalyticsDataClient()

    request = RunFunnelReportRequest(
        property=f"properties/{property_id}",
        date_ranges=[DateRange(start_date="30daysAgo", end_date="today")],
        funnel_breakdown=FunnelBreakdown(
            breakdown_dimension=Dimension(name="deviceCategory")
        ),
        funnel=Funnel(
            steps=[
                FunnelStep(
                    name="First open/visit",
                    filter_expression=FunnelFilterExpression(
                        or_group=FunnelFilterExpressionList(
                            expressions=[
                                FunnelFilterExpression(
                                    funnel_event_filter=FunnelEventFilter(
                                        event_name="first_open"
                                    )
                                ),
                                FunnelFilterExpression(
                                    funnel_event_filter=FunnelEventFilter(
                                        event_name="first_visit"
                                    )
                                ),
                            ]
                        )
                    ),
                ),
                FunnelStep(
                    name="Organic visitors",
                    filter_expression=FunnelFilterExpression(
                        funnel_field_filter=FunnelFieldFilter(
                            field_name="firstUserMedium",
                            string_filter=StringFilter(
                                match_type=StringFilter.MatchType.CONTAINS,
                                case_sensitive=False,
                                value="organic",
                            ),
                        )
                    ),
                ),
                FunnelStep(
                    name="Session start",
                    filter_expression=FunnelFilterExpression(
                        funnel_event_filter=FunnelEventFilter(
                            event_name="session_start"
                        )
                    ),
                ),
                FunnelStep(
                    name="Screen/Page view",
                    filter_expression=FunnelFilterExpression(
                        or_group=FunnelFilterExpressionList(
                            expressions=[
                                FunnelFilterExpression(
                                    funnel_event_filter=FunnelEventFilter(
                                        event_name="screen_view"
                                    )
                                ),
                                FunnelFilterExpression(
                                    funnel_event_filter=FunnelEventFilter(
                                        event_name="page_view"
                                    )
                                ),
                            ]
                        )
                    ),
                ),
                FunnelStep(
                    name="Purchase",
                    filter_expression=FunnelFilterExpression(
                        or_group=FunnelFilterExpressionList(
                            expressions=[
                                FunnelFilterExpression(
                                    funnel_event_filter=FunnelEventFilter(
                                        event_name="purchase"
                                    )
                                ),
                                FunnelFilterExpression(
                                    funnel_event_filter=FunnelEventFilter(
                                        event_name="in_app_purchase"
                                    )
                                ),
                            ]
                        )
                    ),
                ),
            ]
        ),
    )
    response = client.run_funnel_report(request)
    print_run_funnel_report_response(response)


def print_funnel_sub_report(funnel_sub_report):
    """Prints the contents of a FunnelSubReport object."""
    print("Dimension headers:")
    for dimension_header in funnel_sub_report.dimension_headers:
        print(dimension_header.name)

    print("\nMetric headers:")
    for metric_header in funnel_sub_report.metric_headers:
        print(metric_header.name)

    print("\nDimensions and metric values for each row in the report:")
    for row_idx, row in enumerate(funnel_sub_report.rows):
        print("\nRow #{}".format(row_idx))
        for field_idx, dimension_value in enumerate(row.dimension_values):
            dimension_name = funnel_sub_report.dimension_headers[field_idx].name
            print("{}: '{}'".format(dimension_name, dimension_value.value))

        for field_idx, metric_value in enumerate(row.metric_values):
            metric_name = funnel_sub_report.metric_headers[field_idx].name
            print("{}: '{}'".format(metric_name, metric_value.value))

    print("\nSampling metadata for each date range:")
    for metadata_idx, metadata in enumerate(
        funnel_sub_report.metadata.sampling_metadatas
    ):
        print(
            "Sampling metadata for date range #{}: samplesReadCount={}, "
            "samplingSpaceSize={}".format(
                metadata_idx, metadata.samples_read_count, metadata.sampling_space_size
            )
        )


def print_run_funnel_report_response(response):
    """Prints results of a runFunnelReport call."""
    print("Report result:")
    print("=== FUNNEL VISUALIZATION ===")
    print_funnel_sub_report(response.funnel_visualization)

    print("=== FUNNEL TABLE ===")
    print_funnel_sub_report(response.funnel_table)