Przegląd

Interfejs Google Analytics Data API (wersja 1) umożliwia generowanie raportów ścieżek. Eksploracja ścieżki umożliwia wizualizację kroków podejmowanych przez użytkowników i szybką ocenę skuteczności ich wykonywania.

Wspólne funkcje w podstawowych raportach

Żądania raportowania ścieżki mają tę samą semantykę co żądania raportu podstawowego dotyczące wielu wspólnych funkcji. Na przykład podział na strony, filtry wymiarów i właściwości użytkownika w raportach ścieżki działa tak samo jak w raportach podstawowych. Ten przewodnik dotyczy funkcji raportowania ścieżki. Aby zapoznać się z podstawowymi funkcjami raportowania w interfejsie Data API w wersji 1, przeczytaj przewodnik po podstawach raportowania oraz przewodnik po zaawansowanych przypadkach użycia.

Metoda raportowania ścieżki

Interfejs Data API w wersji 1 obsługuje funkcję raportowania ścieżki w metodzie runFunnelReport. Zwraca ona niestandardowy raport ścieżki zawierający dane zdarzeń z Google Analytics.

Wybór podmiotu raportującego

Wszystkie metody interfejsu Data API w wersji 1 wymagają określenia identyfikatora usługi Google Analytics 4 w ścieżce żądania adresu URL w postaci properties/GA4_PROPERTY_ID, np.:

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

Gotowy raport zostanie wygenerowany na podstawie danych o zdarzeniach w Google Analytics zebranych w określonej usłudze w Google Analytics 4.

Jeśli używasz jednej z bibliotek klienta interfejsu Data API, nie musisz ręcznie modyfikować ścieżki adresu URL żądania. Większość klientów korzystających z interfejsu API udostępnia parametr property, który oczekuje ciągu znaków w postaci properties/GA4_PROPERTY_ID. Przykłady korzystania z bibliotek klienta znajdziesz w krótkim przewodniku.

Żądanie raportu ścieżki

Aby wysłać żądanie raportu ścieżki, możesz utworzyć obiekt RunFunnelReportRequest. Zalecamy zacząć od następujących parametrów żądania:

  • Prawidłowa wartość w polu dateRanges.

  • Prawidłowa specyfikacja ścieżki w polu funnel.

Specyfikacja ścieżki

Specyfikacja ścieżki w polu funnel obiektu RunFunnelReportRequest określa ścieżkę użytkownika, którą chcesz mierzyć, opisując steps tej ścieżki.

Kroki ścieżki zawierają co najmniej 1 warunek, który musi spełnić użytkownicy, aby zostali uwzględnieni w danym kroku ścieżki. Warunki uwzględnienia w poszczególnych krokach można opisać w polu filterExpression każdego kroku.

Każde wyrażenie filtra ścieżki stanowi kombinację 2 rodzajów filtrów:

  • funnelFieldFilter tworzy filtr wymiaru lub danych.

  • funnelEventFilter tworzy filtr dopasowujący zdarzenia o jednej nazwie. Jeśli określone jest opcjonalne pole funnelParameterFilterExpression, do tego filtra zdarzeń pasują tylko podzbiory zdarzeń, które pasują zarówno do nazwy pojedynczego zdarzenia, jak i wyrażeń filtra parametrów.

Filtry można łączyć za pomocą grup AND i OR, a także negować za pomocą wyrażenia NOT.

Wyniki raportu dotyczące poszczególnych kroków ścieżki zostaną podzielone według wymiaru i określone w polu funnelBreakdown.

Przykład raportu ścieżki

Użyjmy interfejsu Google Analytics Data API w wersji 1, aby odtworzyć domyślny raport ścieżki podany w szablonie eksploracji ścieżki w interfejsie Google Analytics:

Przykładowy interfejs raportu ścieżki

Kroki ścieżki

Powyższa konfiguracja ścieżki składa się z tych kroków:

# Nazwa etapu Warunek
1 Pierwsze uruchomienie / pierwsza wizyta Nazwa zdarzenia to first_open lub first_visit.
2 Użytkownicy korzystający z bezpłatnych wyników wyszukiwania Wymiar firstUserMedium zawiera hasło „bezpłatne”.
3 Rozpoczęcie sesji Nazwa zdarzenia: session_start.
4 Wyświetlenie strony/ekranu Nazwa zdarzenia to screen_view lub page_view.
5 Zakup Nazwa zdarzenia to purchase lub in_app_purchase.

Krok 1 (pierwsze otwarcie/wizyta) ścieżki obejmuje wszystkich użytkowników po pierwszej interakcji z witryną lub aplikacją, tj. którzy wywołali zdarzenia first_open lub first_visit.

Aby zaimplementować to zachowanie, poniższy fragment kodu określa obiekt FunnelStep z polem filterExpression. Pole wyrażenia filtra to obiekt FunnelFilterExpression utworzony przez połączenie 2 elementów FunnelEventFilter za pomocą funkcji LUB.

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

W kroku 2 (użytkownicy bezpłatny) na ścieżce są użytkownicy, których pierwsze medium zawiera słowo „bezpłatne”. We fragmencie kodu poniżej pole fieldName w polu FunnelFieldFilter informuje, że filtr pasuje do wymiaru firstUserMedium. Pole stringFilter zawiera warunek uwzględniający tylko wartości wymiaru zawierającego słowo „bezpłatne”.

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

Pozostałe kroki ścieżki można określić w podobny sposób.

Wymiar podziału

Opcjonalny wymiar podziału (w tym przykładzie deviceCategory) można określić za pomocą obiektu FunnelBreakdown:

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

Domyślnie raport uwzględnia tylko 5 pierwszych różnych wartości wymiaru podziału. Aby zastąpić to działanie, możesz użyć pola limit obiektu FunnelBreakdown.

Zapytanie o raport pełnej ścieżki

Oto pełne zapytanie, które generuje raport ścieżki na podstawie wszystkich opisanych powyżej kroków:

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"
                }
              }
            ]
          }
        }
      }
    ]
  }
}

Zgłoś odpowiedź

Odpowiedź raportu ścieżki na żądanie interfejsu API raportu ścieżki składa się z 2 głównych części, które są zwracane jako obiekt FunnelSubReport: Wizualizacja ścieżek i Tabela ścieżek.

Wizualizacja ścieżek

Wizualizacja ścieżek zwracana w polu funnelVisualization w odpowiedzi na raport ścieżki zawiera ogólny przegląd raportu ścieżki. Jest to przydatne, jak sama nazwa wskazuje, do szybkiej wizualizacji wygenerowanego raportu ścieżki.

Każdy wiersz tabeli wizualizacji ścieżek zawiera niektóre lub wszystkie te pola:

  • Nazwa kroku ścieżki (wymiar funnelStepName).

  • Liczba aktywnych użytkowników (liczba danych: activeUsers).

  • Segment (segment wymiar). Występuje tylko wtedy, gdy w zapytaniu dotyczącym ścieżki został określony parametr Segment.

  • Data (date wymiar). Widoczny tylko wtedy, gdy w zapytaniu został określony typ wizualizacji TRENDED_FUNNEL.

  • Wymiar następnego działania (funnelStepNextAction wymiar). Widoczny tylko wtedy, gdy w zapytaniu dotyczącym ścieżki został określony parametr FunnelNextAction.

Sekcja wizualizacji ścieżek z przykładowego raportu omówionego powyżej będzie wyświetlana w interfejsie Google Analytics w ten sposób:

Nagłówki raportu ścieżki: przykład

Tabela ścieżek

Tabela ścieżek zwracana w polu funnelTable w odpowiedzi na raport ścieżki stanowi główną część raportu. Każdy wiersz tabeli zawiera niektóre lub wszystkie te pola:

  • Nazwa kroku ścieżki (wymiar funnelStepName).

  • Wymiar podziału.

  • Liczba aktywnych użytkowników (liczba danych: activeUsers).

  • Współczynnik ukończenia kroku (liczba danych: funnelStepCompletionRate).

  • Liczba porzuceń kroku (funnelStepAbandonments rodzaj danych).

  • Współczynnik porzuceń etapu (liczba danych: funnelStepAbandonmentRate).

  • Nazwa segmentu (segment wymiar). Występuje tylko wtedy, gdy w zapytaniu dotyczącym ścieżki został określony parametr Segment.

Podobnie jak w przypadku podstawowego raportowania, łączne wartości są zwracane w oddzielnym wierszu, w którym jako wartość wymiaru podziału jest RESERVED_TOTAL.

Poniżej znajduje się przykład tabeli ścieżek wyświetlanej w interfejsie Google Analytics: Tabela raportu ścieżki: przykład

Nieprzetworzona odpowiedź

Poniższy fragment kodu przedstawia przykład nieprzetworzonych danych zwracanych w odpowiedzi na zapytanie runFunnelReport.

W zależności od danych zebranych przez Twoją usługę powyższy przykładowy raport zwróci poniższy raport z liczbą aktywnych użytkowników uwzględnionych w każdym kroku ścieżki.

{
  "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"
}

Biblioteki klienta

Wyjaśnienie sposobu instalowania i konfigurowania bibliotek klienta znajdziesz w krótkim przewodniku dla początkujących.

Poniżej znajdziesz przykłady korzystania z bibliotek klienta, które uruchamiają zapytanie ścieżki i drukują odpowiedź.

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)