---
metadata:
  - name: generator
    content: Diplodoc Platform v5.50.6
alternate:
  - https://appmetrica.yandex.com/docs/en/data-collection/offers.md
  - https://appmetrica.yandex.com/docs/ru/data-collection/offers.md
---
> **Documentation Index:** Fetch the complete configuration index at https://appmetrica.yandex.com/docs/en/llms.txt

# Offer events in product scenarios

Documentation on Product Flow with SDK integration examples:

- **Android** — [Product scenarios and offer events](https://appmetrica.yandex.com/docs/en/sdk/android/analytics/android-product-flow.md);
- **iOS** — [Product scenarios and offer events](https://appmetrica.yandex.com/docs/en/sdk/ios/analytics/ios-product-flow.md).

## More about the approach {#details}

**Product Flow** is a new schema for handling standard AppMetrica events in apps with offers, purchases, applications, and multi-step product and service ordering scenarios.

This approach helps standardize analytics for the following entities and scenarios:

- product offers;
- marketing offers;
- purchases of goods and services;
- user funnels;
- ordering steps;
- applications and approval results;
- asynchronous S2S results.

We recommend using the Product Flow approach for the following types of apps:

- banks;
- insurance services;
- telecom apps;
- booking and travel services;
- subscription services;
- delivery services;
- marketplaces;
- gaming apps;
- any apps with product scenarios, purchases, and funnel analytics.

{% note tip "Does not consume custom events and DSA limits" %}

The new standard events do not count toward the following limits:

- `custom events`;
- `Data Stream API`.

This allows you to:

- gradually adopt the new markup schema;
- send more product scenarios and steps;
- build detailed funnels and analytics without consuming custom event and DSA limits.

{% endnote %}

## What problem does this approach solve {#problem-statement}

Currently, many apps use `custom events` to send analytics data about the following entities and scenarios:

- offers;
- applications;
- product scenarios;
- onboarding scenarios;
- order placement scenarios;
- approval scenarios.

This approach leads to the following problems:

- identical scenarios are marked up differently;
- building standard reports is difficult;
- analytics is hard to transfer between teams;
- automatic funnel building is impossible;
- it is difficult to compare the effectiveness of offers and scenarios.

The product scenario and offer event schema offers a unified approach to marking up key stages:

- offer display;
- start of ordering;
- intermediate steps;
- final result.

## Main events {#main-events}

The interaction schema is based on four main events:

#|
|| **Event** | **Meaning** ||
|| `offerShown` | The user saw an offer or proposal ||
|| `flowStart` | The user started ordering a product ||
|| `flowStep` | An intermediate ordering step ||
|| `flowResult` | The final result ||
|#

## Markup scenarios {#scenarios}

This section shows complete user scenarios for different industries.

{% note tip "Scenario examples" %}

All scenarios in this document are **examples** of markup and demonstrate possible integration options.

Event names, parameters, scenario steps, and payload structure can be adapted to the specifics of your app and user scenarios.

{% endnote %}

Each scenario describes:

- what the user sees and does in the app;
- which events need to be sent;
- when `offerShown` can be omitted;
- when `flowStart` can be omitted;
- how to pass intermediate steps via `flowStep`;
- how to pass the final result via `flowResult`;
- how to use `payload`, `referrer`, and `stepOption`;
- how to pass the result later via S2S.

### Banks and Fintech {#banks}

#### Loan via personal offer: offer → application → pending → S2S result {#personal-offer}

{% cut "The user sees a banner: 'You are pre-approved for a loan of up to 500,000 RUB at a rate from 12.5%'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("credit_q1", "financial_product")
          .withProductId("personal_loan")
          .withBenefitType("discount_percentage")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("banner")
                      .withIdentifier("main_screen_credit_banner")
                      .withScreen("main")
                      .build()
          )
          .withPayload(mapOf(
              "campaign_id" to "credit_spring_2026",
              "segment" to "preapproved_users",
              "approved_limit" to "500000",
              "currency" to "RUB",
              "interest_rate" to "12.5"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "credit_q1", offerType: "financial_product")
      .withProductId("personal_loan")
      .withBenefitType("discount_percentage")
      .withReferrer(OfferReferrer(type: "banner", identifier: "main_screen_credit_banner", screen: "main"))
      .withPayload([
          "campaign_id": "credit_spring_2026",
          "segment": "preapproved_users",
          "approved_limit": "500000",
          "currency": "RUB",
          "interest_rate": "12.5"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user taps the banner and starts filling out the application." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("personal_loan")
          .withProductOfferId("credit_q1")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "personal_loan")
      .withProductOfferId("credit_q1")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user uploads documents." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("personal_loan", "documents")
          .withProductOfferId("credit_q1")
          .withStepOption("passport_upload")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "personal_loan", stepType: "documents")
      .withProductOfferId("credit_q1")
      .withStepOption("passport_upload")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user submits the application for scoring." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("personal_loan", "scoring")
          .withProductOfferId("credit_q1")
          .withStepOption("automatic_scoring")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "personal_loan", stepType: "scoring")
      .withProductOfferId("credit_q1")
      .withStepOption("automatic_scoring")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user has completed their part, the application is under review." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.PENDING, "personal_loan")
          .withProductOfferId("credit_q1")
          .withPayload(mapOf(
              "application_id" to "loan_app_12345",
              "requested_amount" to "450000",
              "currency" to "RUB"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "personal_loan", status: .pending)
      .withProductOfferId("credit_q1")
      .withPayload([
          "application_id": "loan_app_12345",
          "requested_amount": "450000",
          "currency": "RUB"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Later, the bank sends the final result via S2S." %}

```java
flowResult(
    productId = "travel_insurance",
    productOfferId = "travel_insurance_offer",
    status = "success",
    payload = mapOf(
        "application_id" to "insurance_app_987",
        "policy_id" to "policy_555",
        "decision_source" to "s2s"
    )
)
```

Sending offer events via the S2S scheme will be implemented via the POST API in one of the upcoming releases. The current documentation provides an example script that demonstrates the expected integration method.

{% endcut %}

#### Organic loan application without an offer {#no-offer}

{% cut "The user opened the 'Loans' section from the app menu on their own. There was no offer." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("personal_loan")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "personal_loan")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user uploads documents." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("personal_loan", "documents")
          .withStepOption("passport_upload")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "personal_loan", stepType: "documents")
      .withStepOption("passport_upload")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The application is submitted for review." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.PENDING, "personal_loan")
          .withPayload(mapOf(
              "application_id" to "loan_app_67890",
              "requested_amount" to "300000",
              "currency" to "RUB"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "personal_loan", status: .pending)
      .withPayload([
          "application_id": "loan_app_67890",
          "requested_amount": "300000",
          "currency": "RUB"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Later, the bank sends a rejection via S2S." %}

```java
flowResult(
    productId = "personal_loan",
    productOfferId = null,
    status = "declined",
    payload = mapOf(
        "application_id" to "loan_app_67890",
        "decline_reason" to "scoring_rejected",
        "decision_source" to "s2s"
    )
)
```

Sending offer events via the S2S scheme will be implemented via the POST API in one of the upcoming releases. The current documentation provides an example script that demonstrates the expected integration method.

{% endcut %}


### Telecom {#telecom}

#### eSIM activation via offer {#esim}

{% cut "The user opens the tariff screen and sees a banner: 'eSIM with 20% off the first month'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("esim_offer_q2", "service")
          .withProductId("esim")
          .withBenefitType("discount_percentage")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("banner")
                      .withIdentifier("tariffs_screen_esim_banner")
                      .withScreen("tariffs")
                      .build()
          )
          .withPayload(mapOf(
              "campaign_id" to "esim_discount_q2",
              "discount_value" to "20",
              "discount_period" to "first_month",
              "region" to "RS"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "esim_offer_q2", offerType: "service")
      .withProductId("esim")
      .withBenefitType("discount_percentage")
      .withReferrer(OfferReferrer(type: "banner", identifier: "tariffs_screen_esim_banner", screen: "tariffs"))
      .withPayload([
          "campaign_id": "esim_discount_q2",
          "discount_value": "20",
          "discount_period": "first_month",
          "region": "RS"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user taps the banner and starts activation." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("esim")
          .withProductOfferId("esim_offer_q2")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "esim")
      .withProductOfferId("esim_offer_q2")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects a tariff." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("esim", "tariff_selection")
          .withProductOfferId("esim_offer_q2")
          .withStepOption("unlimited_30d")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "esim", stepType: "tariff_selection")
      .withProductOfferId("esim_offer_q2")
      .withStepOption("unlimited_30d")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user goes through identity verification." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("esim", "identity_verification")
          .withProductOfferId("esim_offer_q2")
          .withStepOption("document_scan")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "esim", stepType: "identity_verification")
      .withProductOfferId("esim_offer_q2")
      .withStepOption("document_scan")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "eSIM successfully activated." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "esim")
          .withProductOfferId("esim_offer_q2")
          .withPayload(mapOf(
              "tariff_id" to "unlimited_30d",
              "activation_type" to "esim",
              "discount_applied" to "true"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "esim", status: .success)
      .withProductOfferId("esim_offer_q2")
      .withPayload([
          "tariff_id": "unlimited_30d",
          "activation_type": "esim",
          "discount_applied": "true"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

#### Roaming package activation before a trip {#roaming}

{% cut "The user opens the roaming section and sees an offer: '10 GB in Europe for 14 days for 1,500 RUB'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("eu_roaming_10gb", "service")
          .withProductId("roaming_package")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("banner")
                      .withIdentifier("roaming_europe_banner")
                      .withScreen("roaming")
                      .build()
          )
          .withPayload(mapOf(
              "region" to "Europe",
              "traffic_limit_gb" to "10",
              "duration_days" to "14",
              "price" to "1500",
              "currency" to "RUB"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "eu_roaming_10gb", offerType: "service")
      .withProductId("roaming_package")
      .withReferrer(OfferReferrer(type: "banner", identifier: "roaming_europe_banner", screen: "roaming"))
      .withPayload([
          "region": "Europe",
          "traffic_limit_gb": "10",
          "duration_days": "14",
          "price": "1500",
          "currency": "RUB"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user starts activating the roaming package." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("roaming_package")
          .withProductOfferId("eu_roaming_10gb")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "roaming_package")
      .withProductOfferId("eu_roaming_10gb")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user confirms the activation terms." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("roaming_package", "terms_confirmation")
          .withProductOfferId("eu_roaming_10gb")
          .withStepOption("accepted")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "roaming_package", stepType: "terms_confirmation")
      .withProductOfferId("eu_roaming_10gb")
      .withStepOption("accepted")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Roaming package successfully activated." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "roaming_package")
          .withProductOfferId("eu_roaming_10gb")
          .withPayload(mapOf(
              "region" to "Europe",
              "traffic_limit_gb" to "10",
              "duration_days" to "14",
              "activation_status" to "enabled"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "roaming_package", status: .success)
      .withProductOfferId("eu_roaming_10gb")
      .withPayload([
          "region": "Europe",
          "traffic_limit_gb": "10",
          "duration_days": "14",
          "activation_status": "enabled"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

#### Tariff upgrade {#upgrade-tariff}

{% cut "The user sees an offer: 'Upgrade to the Premium tariff with unlimited internet'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("premium_tariff_upgrade", "service")
          .withProductId("tariff_upgrade")
          .withBenefitType("bundle_extra")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("popup")
                      .withIdentifier("premium_upgrade_popup")
                      .withScreen("tariff_details")
                      .build()
          )
          .withPayload(mapOf(
              "current_tariff" to "smart_m",
              "target_tariff" to "premium_unlimited",
              "monthly_price" to "1990",
              "currency" to "RUB"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "premium_tariff_upgrade", offerType: "service")
      .withProductId("tariff_upgrade")
      .withBenefitType("bundle_extra")
      .withReferrer(OfferReferrer(type: "popup", identifier: "premium_upgrade_popup", screen: "tariff_details"))
      .withPayload([
          "current_tariff": "smart_m",
          "target_tariff": "premium_unlimited",
          "monthly_price": "1990",
          "currency": "RUB"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user starts changing the tariff." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("tariff_upgrade")
          .withProductOfferId("premium_tariff_upgrade")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "tariff_upgrade")
      .withProductOfferId("premium_tariff_upgrade")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user confirms the new tariff." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("tariff_upgrade", "tariff_confirmation")
          .withProductOfferId("premium_tariff_upgrade")
          .withStepOption("premium_unlimited")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "tariff_upgrade", stepType: "tariff_confirmation")
      .withProductOfferId("premium_tariff_upgrade")
      .withStepOption("premium_unlimited")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Tariff successfully changed." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "tariff_upgrade")
          .withProductOfferId("premium_tariff_upgrade")
          .withPayload(mapOf(
              "previous_tariff" to "smart_m",
              "new_tariff" to "premium_unlimited",
              "upgrade_status" to "completed"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "tariff_upgrade", status: .success)
      .withProductOfferId("premium_tariff_upgrade")
      .withPayload([
          "previous_tariff": "smart_m",
          "new_tariff": "premium_unlimited",
          "upgrade_status": "completed"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

#### Home internet connection {#home-internet}

{% cut "The user opens the home internet section and sees an offer: 'Home internet 500 Mbps for 990 RUB per month'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("home_internet_500", "service")
          .withProductId("home_internet")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("banner")
                      .withIdentifier("home_internet_offer")
                      .withScreen("home_services")
                      .build()
          )
          .withPayload(mapOf(
              "speed_mbps" to "500",
              "monthly_price" to "990",
              "currency" to "RUB",
              "connection_fee" to "0"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "home_internet_500", offerType: "service")
      .withProductId("home_internet")
      .withReferrer(OfferReferrer(type: "banner", identifier: "home_internet_offer", screen: "home_services"))
      .withPayload([
          "speed_mbps": "500",
          "monthly_price": "990",
          "currency": "RUB",
          "connection_fee": "0"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user starts filling out the home internet connection application." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("home_internet")
          .withProductOfferId("home_internet_500")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "home_internet")
      .withProductOfferId("home_internet_500")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user enters the connection address." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("home_internet", "address_input")
          .withProductOfferId("home_internet_500")
          .withStepOption("manual_input")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "home_internet", stepType: "address_input")
      .withProductOfferId("home_internet_500")
      .withStepOption("manual_input")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects the technician visit date." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("home_internet", "installation_timeslot")
          .withProductOfferId("home_internet_500")
          .withStepOption("2026-06-20_10:00")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "home_internet", stepType: "installation_timeslot")
      .withProductOfferId("home_internet_500")
      .withStepOption("2026-06-20_10:00")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The connection request has been submitted, the user is waiting for the technician visit." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.PENDING, "home_internet")
          .withProductOfferId("home_internet_500")
          .withPayload(mapOf(
              "request_id" to "internet_request_555",
              "connection_status" to "awaiting_installation",
              "selected_timeslot" to "2026-06-20_10:00"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "home_internet", status: .pending)
      .withProductOfferId("home_internet_500")
      .withPayload([
          "request_id": "internet_request_555",
          "connection_status": "awaiting_installation",
          "selected_timeslot": "2026-06-20_10:00"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Later, the operator reports via S2S that the technician has completed the installation, the internet is connected, and the tariff is activated." %}

```java
flowResult(
    productId = "home_internet",
    productOfferId = "home_internet_500",
    status = "success",
    payload = mapOf(
        "request_id" to "internet_request_555",
        "installation_status" to "completed",
        "technician_visit" to "completed",
        "tariff_id" to "home_500",
        "tariff_status" to "active",
        "decision_source" to "s2s"
    )
)
```

Sending offer events via the S2S scheme will be implemented via the POST API in one of the upcoming releases. The current documentation provides an example script that demonstrates the expected integration method.

{% endcut %}

### Travel / Booking {#travel}

#### Hotel booking with a discount offer {#booking-offer-discount}

{% cut "The user is searching for a hotel in Belgrade and sees a card: '20% off this hotel'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("hotel_discount_may", "booking")
          .withProductId("hotel_booking")
          .withBenefitType("discount_percentage")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("banner")
                      .withIdentifier("search_results_hotel_discount")
                      .withScreen("hotel_search_results")
                      .build()
          )
          .withPayload(mapOf(
              "campaign_id" to "may_hotels_sale",
              "hotel_id" to "hotel_987",
              "city" to "Belgrade",
              "discount_value" to "20",
              "original_price" to "25000",
              "final_price" to "20000",
              "currency" to "RUB",
              "room_type" to "deluxe",
              "refundable" to "true"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "hotel_discount_may", offerType: "booking")
      .withProductId("hotel_booking")
      .withBenefitType("discount_percentage")
      .withReferrer(OfferReferrer(type: "banner", identifier: "search_results_hotel_discount", screen: "hotel_search_results"))
      .withPayload([
          "campaign_id": "may_hotels_sale",
          "hotel_id": "hotel_987",
          "city": "Belgrade",
          "discount_value": "20",
          "original_price": "25000",
          "final_price": "20000",
          "currency": "RUB",
          "room_type": "deluxe",
          "refundable": "true"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user starts booking." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("hotel_booking")
          .withProductOfferId("hotel_discount_may")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "hotel_booking")
      .withProductOfferId("hotel_discount_may")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects dates." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("hotel_booking", "dates")
          .withProductOfferId("hotel_discount_may")
          .withStepOption("3_nights")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "hotel_booking", stepType: "dates")
      .withProductOfferId("hotel_discount_may")
      .withStepOption("3_nights")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects guests." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("hotel_booking", "guests")
          .withProductOfferId("hotel_discount_may")
          .withStepOption("2_adults")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "hotel_booking", stepType: "guests")
      .withProductOfferId("hotel_discount_may")
      .withStepOption("2_adults")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects a payment method." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("hotel_booking", "payment")
          .withProductOfferId("hotel_discount_may")
          .withStepOption("bank_card")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "hotel_booking", stepType: "payment")
      .withProductOfferId("hotel_discount_may")
      .withStepOption("bank_card")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Booking successfully completed." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "hotel_booking")
          .withProductOfferId("hotel_discount_may")
          .withPayload(mapOf(
              "hotel_id" to "hotel_987",
              "city" to "Belgrade",
              "nights" to "3",
              "guests" to "2",
              "original_price" to "25000",
              "final_price" to "20000",
              "currency" to "RUB",
              "discount_applied" to "true"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "hotel_booking", status: .success)
      .withProductOfferId("hotel_discount_may")
      .withPayload([
          "hotel_id": "hotel_987",
          "city": "Belgrade",
          "nights": "3",
          "guests": "2",
          "original_price": "25000",
          "final_price": "20000",
          "currency": "RUB",
          "discount_applied": "true"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

### Medical services {#med-services}

#### Organic doctor appointment without an offer {#doctors-appointment}

{% cut "The user opens the doctor appointment section from the app menu on their own. There was no offer or promotional proposal." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("doctor_appointment")
          .withPayload(mapOf("entry_point" to "menu", "clinic_id" to "clinic_123"))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "doctor_appointment")
      .withPayload(["entry_point": "menu", "clinic_id": "clinic_123"])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects a doctor's specialization." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("doctor_appointment", "specialization_selection")
          .withStepOption("therapy")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "doctor_appointment", stepType: "specialization_selection")
      .withStepOption("therapy")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects a doctor." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("doctor_appointment", "doctor_selection")
          .withStepOption("doctor_456")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "doctor_appointment", stepType: "doctor_selection")
      .withStepOption("doctor_456")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects the appointment date and time." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("doctor_appointment", "timeslot_selection")
          .withStepOption("2026-06-10_14:30")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "doctor_appointment", stepType: "timeslot_selection")
      .withStepOption("2026-06-10_14:30")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Doctor appointment successfully created." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "doctor_appointment")
          .withPayload(mapOf(
              "appointment_id" to "appointment_777",
              "clinic_id" to "clinic_123",
              "doctor_specialization" to "therapy"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "doctor_appointment", status: .success)
      .withPayload([
          "appointment_id": "appointment_777",
          "clinic_id": "clinic_123",
          "doctor_specialization": "therapy"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

#### Doctor appointment via offer {#appointment-suggestion}

{% cut "The user opens the clinic app's main screen and sees a card: 'Book a checkup with 20% off'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("checkup_discount_q2", "service")
          .withProductId("doctor_appointment")
          .withBenefitType("discount_percentage")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("banner")
                      .withIdentifier("main_checkup_banner")
                      .withScreen("main")
                      .build()
          )
          .withPayload(mapOf(
              "clinic_id" to "clinic_123",
              "specialization" to "therapy",
              "discount_value" to "20",
              "campaign_id" to "health_checkup_q2"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "checkup_discount_q2", offerType: "service")
      .withProductId("doctor_appointment")
      .withBenefitType("discount_percentage")
      .withReferrer(OfferReferrer(type: "banner", identifier: "main_checkup_banner", screen: "main"))
      .withPayload([
          "clinic_id": "clinic_123",
          "specialization": "therapy",
          "discount_value": "20",
          "campaign_id": "health_checkup_q2"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user starts booking a doctor appointment." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("doctor_appointment")
          .withProductOfferId("checkup_discount_q2")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "doctor_appointment")
      .withProductOfferId("checkup_discount_q2")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects a doctor." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("doctor_appointment", "doctor_selection")
          .withProductOfferId("checkup_discount_q2")
          .withStepOption("therapist")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "doctor_appointment", stepType: "doctor_selection")
      .withProductOfferId("checkup_discount_q2")
      .withStepOption("therapist")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects the appointment date and time." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("doctor_appointment", "timeslot_selection")
          .withProductOfferId("checkup_discount_q2")
          .withStepOption("2026-06-10_14:30")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "doctor_appointment", stepType: "timeslot_selection")
      .withProductOfferId("checkup_discount_q2")
      .withStepOption("2026-06-10_14:30")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Appointment successfully created." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "doctor_appointment")
          .withProductOfferId("checkup_discount_q2")
          .withPayload(mapOf(
              "appointment_id" to "appointment_555",
              "doctor_specialization" to "therapy",
              "clinic_id" to "clinic_123",
              "discount_applied" to "true"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "doctor_appointment", status: .success)
      .withProductOfferId("checkup_discount_q2")
      .withPayload([
          "appointment_id": "appointment_555",
          "doctor_specialization": "therapy",
          "clinic_id": "clinic_123",
          "discount_applied": "true"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

### Beauty / Wellness {#beauty}

#### SPA booking with prepayment {#spa-registry}

{% cut "The user opens the SPA salon app and sees an offer: '20% off SPA program with online payment'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("spa_weekend_offer", "service")
          .withProductId("spa_booking")
          .withBenefitType("discount_percentage")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("banner")
                      .withIdentifier("spa_weekend_banner")
                      .withScreen("main")
                      .build()
          )
          .withPayload(mapOf(
              "service_type" to "spa_program",
              "discount_value" to "20",
              "original_price" to "12000",
              "final_price" to "9600",
              "currency" to "RUB",
              "campaign_id" to "spa_weekend_q2"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "spa_weekend_offer", offerType: "service")
      .withProductId("spa_booking")
      .withBenefitType("discount_percentage")
      .withReferrer(OfferReferrer(type: "banner", identifier: "spa_weekend_banner", screen: "main"))
      .withPayload([
          "service_type": "spa_program",
          "discount_value": "20",
          "original_price": "12000",
          "final_price": "9600",
          "currency": "RUB",
          "campaign_id": "spa_weekend_q2"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user starts booking the SPA." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("spa_booking")
          .withProductOfferId("spa_weekend_offer")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "spa_booking")
      .withProductOfferId("spa_weekend_offer")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects the SPA program." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("spa_booking", "service_selection")
          .withProductOfferId("spa_weekend_offer")
          .withStepOption("relax_spa_program")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "spa_booking", stepType: "service_selection")
      .withProductOfferId("spa_weekend_offer")
      .withStepOption("relax_spa_program")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects the visit date and time." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("spa_booking", "timeslot_selection")
          .withProductOfferId("spa_weekend_offer")
          .withStepOption("2026-06-15_18:00")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "spa_booking", stepType: "timeslot_selection")
      .withProductOfferId("spa_weekend_offer")
      .withStepOption("2026-06-15_18:00")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user proceeds to prepayment." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("spa_booking", "prepayment")
          .withProductOfferId("spa_weekend_offer")
          .withStepOption("bank_card")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "spa_booking", stepType: "prepayment")
      .withProductOfferId("spa_weekend_offer")
      .withStepOption("bank_card")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Prepayment successfully made, booking confirmed." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "spa_booking")
          .withProductOfferId("spa_weekend_offer")
          .withPayload(mapOf(
              "booking_id" to "spa_booking_555",
              "service_type" to "relax_spa_program",
              "prepayment_amount" to "3000",
              "remaining_amount" to "6600",
              "currency" to "RUB",
              "payment_status" to "partially_paid"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "spa_booking", status: .success)
      .withProductOfferId("spa_weekend_offer")
      .withPayload([
          "booking_id": "spa_booking_555",
          "service_type": "relax_spa_program",
          "prepayment_amount": "3000",
          "remaining_amount": "6600",
          "currency": "RUB",
          "payment_status": "partially_paid"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Later, the SPA salon confirms via S2S that the user actually attended the treatment." %}

```java
flowResult(
    productId = "spa_booking",
    productOfferId = "spa_weekend_offer",
    status = "success",
    payload = mapOf(
        "booking_id" to "spa_booking_555",
        "visit_status" to "completed",
        "service_type" to "relax_spa_program",
        "final_payment_amount" to "6600",
        "currency" to "RUB",
        "decision_source" to "s2s"
    )
)
```

Sending offer events via the S2S scheme will be implemented via the POST API in one of the upcoming releases. The current documentation provides an example script that demonstrates the expected integration method.

{% endcut %}

#### Manicure appointment {#manicure}

{% cut "The user opens the salon app and sees an offer: '15% off your first visit'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("first_visit_nails", "service")
          .withProductId("beauty_appointment")
          .withBenefitType("discount_percentage")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("popup")
                      .withIdentifier("new_user_discount_popup")
                      .withScreen("main")
                      .build()
          )
          .withPayload(mapOf(
              "service_type" to "manicure",
              "discount_value" to "15",
              "campaign_id" to "new_clients_q2"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "first_visit_nails", offerType: "service")
      .withProductId("beauty_appointment")
      .withBenefitType("discount_percentage")
      .withReferrer(OfferReferrer(type: "popup", identifier: "new_user_discount_popup", screen: "main"))
      .withPayload([
          "service_type": "manicure",
          "discount_value": "15",
          "campaign_id": "new_clients_q2"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user starts booking at the salon." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("beauty_appointment")
          .withProductOfferId("first_visit_nails")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "beauty_appointment")
      .withProductOfferId("first_visit_nails")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects a service." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("beauty_appointment", "service_selection")
          .withProductOfferId("first_visit_nails")
          .withStepOption("manicure_gel")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "beauty_appointment", stepType: "service_selection")
      .withProductOfferId("first_visit_nails")
      .withStepOption("manicure_gel")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects a master." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("beauty_appointment", "master_selection")
          .withProductOfferId("first_visit_nails")
          .withStepOption("top_master")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "beauty_appointment", stepType: "master_selection")
      .withProductOfferId("first_visit_nails")
      .withStepOption("top_master")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects date and time." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("beauty_appointment", "timeslot_selection")
          .withProductOfferId("first_visit_nails")
          .withStepOption("2026-06-12_18:00")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "beauty_appointment", stepType: "timeslot_selection")
      .withProductOfferId("first_visit_nails")
      .withStepOption("2026-06-12_18:00")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Appointment successfully created." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "beauty_appointment")
          .withProductOfferId("first_visit_nails")
          .withPayload(mapOf(
              "appointment_id" to "beauty_booking_987",
              "service_type" to "manicure_gel",
              "master_level" to "top_master",
              "discount_applied" to "true"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "beauty_appointment", status: .success)
      .withProductOfferId("first_visit_nails")
      .withPayload([
          "appointment_id": "beauty_booking_987",
          "service_type": "manicure_gel",
          "master_level": "top_master",
          "discount_applied": "true"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

---

#### Haircut and coloring appointment with subsequent cancellation {#haircut-cancel}

{% cut "The user opens the salon app and independently starts booking a haircut and coloring. There was no offer or promotional proposal." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("beauty_appointment")
          .withPayload(mapOf("entry_point" to "catalog", "service_category" to "hair"))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "beauty_appointment")
      .withPayload(["entry_point": "catalog", "service_category": "hair"])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects a service: haircut and coloring." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("beauty_appointment", "service_selection")
          .withStepOption("haircut_coloring")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "beauty_appointment", stepType: "service_selection")
      .withStepOption("haircut_coloring")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects a master." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("beauty_appointment", "master_selection")
          .withStepOption("top_master")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "beauty_appointment", stepType: "master_selection")
      .withStepOption("top_master")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects the appointment date and time." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("beauty_appointment", "timeslot_selection")
          .withStepOption("2026-06-20_15:00")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "beauty_appointment", stepType: "timeslot_selection")
      .withStepOption("2026-06-20_15:00")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Appointment successfully created." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "beauty_appointment")
          .withPayload(mapOf(
              "booking_id" to "beauty_booking_777",
              "service_type" to "haircut_coloring",
              "master_level" to "top_master",
              "booking_status" to "confirmed"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "beauty_appointment", status: .success)
      .withPayload([
          "booking_id": "beauty_booking_777",
          "service_type": "haircut_coloring",
          "master_level": "top_master",
          "booking_status": "confirmed"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Later, the user cancels the appointment through the app." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.CANCELLED, "beauty_appointment")
          .withPayload(mapOf(
              "booking_id" to "beauty_booking_777",
              "cancellation_reason" to "client_cancelled",
              "cancellation_source" to "app"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "beauty_appointment", status: .cancelled)
      .withPayload([
          "booking_id": "beauty_booking_777",
          "cancellation_reason": "client_cancelled",
          "cancellation_source": "app"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Or the salon reports via S2S that the appointment was cancelled." %}

```java
flowResult(
    productId = "beauty_appointment",
    productOfferId = null,
    status = "cancelled",
    payload = mapOf(
        "booking_id" to "beauty_booking_777",
        "cancellation_reason" to "client_cancelled",
        "decision_source" to "s2s"
    )
)
```

Sending offer events via the S2S scheme will be implemented via the POST API in one of the upcoming releases. The current documentation provides an example script that demonstrates the expected integration method.

{% endcut %}

### Subscription / Media {#media}

#### Trial subscription without a separate flowStart {#no-flowstart}

{% cut "The user receives a push notification: 'Try Premium free for 30 days'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("premium_trial_30d", "subscription")
          .withProductId("premium_subscription")
          .withBenefitType("trial")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("notification")
                      .withIdentifier("premium_trial_push")
                      .build()
          )
          .withPayload(mapOf(
              "trial_days" to "30",
              "subscription_plan" to "premium_monthly",
              "campaign_id" to "trial_reactivation_2026"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "premium_trial_30d", offerType: "subscription")
      .withProductId("premium_subscription")
      .withBenefitType("trial")
      .withReferrer(OfferReferrer(type: "notification", identifier: "premium_trial_push"))
      .withPayload([
          "trial_days": "30",
          "subscription_plan": "premium_monthly",
          "campaign_id": "trial_reactivation_2026"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user taps the push and immediately activates the trial. There is no separate ordering process, so flowStart can be omitted." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "premium_subscription")
          .withProductOfferId("premium_trial_30d")
          .withPayload(mapOf(
              "trial_days" to "30",
              "subscription_plan" to "premium_monthly",
              "activation_source" to "push"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "premium_subscription", status: .success)
      .withProductOfferId("premium_trial_30d")
      .withPayload([
          "trial_days": "30",
          "subscription_plan": "premium_monthly",
          "activation_source": "push"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

### Video platforms and online cinemas {#video}

#### Trial subscription activation {#trial-activation}

{% cut "The user opens the online cinema app and sees a fullscreen paywall: '30 days Premium for free'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("premium_trial_30d", "subscription")
          .withProductId("premium_subscription")
          .withBenefitType("trial")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("screen")
                      .withIdentifier("premium_paywall")
                      .withScreen("home")
                      .build()
          )
          .withPayload(mapOf(
              "trial_days" to "30",
              "subscription_plan" to "premium_monthly",
              "campaign_id" to "summer_trial_2026"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "premium_trial_30d", offerType: "subscription")
      .withProductId("premium_subscription")
      .withBenefitType("trial")
      .withReferrer(OfferReferrer(type: "screen", identifier: "premium_paywall", screen: "home"))
      .withPayload([
          "trial_days": "30",
          "subscription_plan": "premium_monthly",
          "campaign_id": "summer_trial_2026"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user taps 'Try for free'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("premium_subscription")
          .withProductOfferId("premium_trial_30d")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "premium_subscription")
      .withProductOfferId("premium_trial_30d")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects a plan." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("premium_subscription", "plan_selection")
          .withProductOfferId("premium_trial_30d")
          .withStepOption("premium_monthly")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "premium_subscription", stepType: "plan_selection")
      .withProductOfferId("premium_trial_30d")
      .withStepOption("premium_monthly")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user adds a payment method." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("premium_subscription", "payment_method")
          .withProductOfferId("premium_trial_30d")
          .withStepOption("bank_card")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "premium_subscription", stepType: "payment_method")
      .withProductOfferId("premium_trial_30d")
      .withStepOption("bank_card")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Trial subscription successfully activated." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "premium_subscription")
          .withProductOfferId("premium_trial_30d")
          .withPayload(mapOf(
              "subscription_plan" to "premium_monthly",
              "trial_days" to "30",
              "autorenew_enabled" to "true"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "premium_subscription", status: .success)
      .withProductOfferId("premium_trial_30d")
      .withPayload([
          "subscription_plan": "premium_monthly",
          "trial_days": "30",
          "autorenew_enabled": "true"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

#### Movie rental {#movie-rental}

{% cut "The user opens a movie card and sees an offer: 'Rent this movie for 299 RUB'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("movie_rental_offer", "digital_good")
          .withProductId("movie_rental")
          .withBenefitType("discount_absolute")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("button")
                      .withIdentifier("rent_movie_button")
                      .withScreen("movie_details")
                      .build()
          )
          .withPayload(mapOf(
              "movie_id" to "movie_987",
              "movie_title" to "SciFi Adventure",
              "rental_price" to "299",
              "currency" to "RUB"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "movie_rental_offer", offerType: "digital_good")
      .withProductId("movie_rental")
      .withBenefitType("discount_absolute")
      .withReferrer(OfferReferrer(type: "button", identifier: "rent_movie_button", screen: "movie_details"))
      .withPayload([
          "movie_id": "movie_987",
          "movie_title": "SciFi Adventure",
          "rental_price": "299",
          "currency": "RUB"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user starts the rental process." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("movie_rental")
          .withProductOfferId("movie_rental_offer")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "movie_rental")
      .withProductOfferId("movie_rental_offer")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user confirms payment." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("movie_rental", "payment_confirmation")
          .withProductOfferId("movie_rental_offer")
          .withStepOption("bank_card")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "movie_rental", stepType: "payment_confirmation")
      .withProductOfferId("movie_rental_offer")
      .withStepOption("bank_card")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Movie rental successfully completed." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "movie_rental")
          .withProductOfferId("movie_rental_offer")
          .withPayload(mapOf(
              "movie_id" to "movie_987",
              "rental_duration_hours" to "48",
              "payment_status" to "paid"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "movie_rental", status: .success)
      .withProductOfferId("movie_rental_offer")
      .withPayload([
          "movie_id": "movie_987",
          "rental_duration_hours": "48",
          "payment_status": "paid"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

#### Buying a ticket for an online movie screening {#offline-ticket}

{% cut "The user opens a movie card and sees an offer: 'Buy a ticket for the online screening for 500 RUB'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("online_premiere_ticket_offer", "digital_good")
          .withProductId("online_event_ticket")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("button")
                      .withIdentifier("buy_ticket_button")
                      .withScreen("premiere_details")
                      .build()
          )
          .withPayload(mapOf(
              "event_id" to "premiere_987",
              "event_type" to "online_premiere",
              "content_id" to "movie_987",
              "ticket_price" to "500",
              "currency" to "RUB"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "online_premiere_ticket_offer", offerType: "digital_good")
      .withProductId("online_event_ticket")
      .withReferrer(OfferReferrer(type: "button", identifier: "buy_ticket_button", screen: "premiere_details"))
      .withPayload([
          "event_id": "premiere_987",
          "event_type": "online_premiere",
          "content_id": "movie_987",
          "ticket_price": "500",
          "currency": "RUB"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user starts buying the ticket." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("online_event_ticket")
          .withProductOfferId("online_premiere_ticket_offer")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "online_event_ticket")
      .withProductOfferId("online_premiere_ticket_offer")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects the ticket type." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("online_event_ticket", "ticket_type_selection")
          .withProductOfferId("online_premiere_ticket_offer")
          .withStepOption("standard")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "online_event_ticket", stepType: "ticket_type_selection")
      .withProductOfferId("online_premiere_ticket_offer")
      .withStepOption("standard")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user confirms payment." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("online_event_ticket", "payment_confirmation")
          .withProductOfferId("online_premiere_ticket_offer")
          .withStepOption("bank_card")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "online_event_ticket", stepType: "payment_confirmation")
      .withProductOfferId("online_premiere_ticket_offer")
      .withStepOption("bank_card")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Ticket successfully purchased." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "online_event_ticket")
          .withProductOfferId("online_premiere_ticket_offer")
          .withPayload(mapOf(
              "event_id" to "premiere_987",
              "content_id" to "movie_987",
              "ticket_type" to "standard",
              "payment_status" to "paid"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "online_event_ticket", status: .success)
      .withProductOfferId("online_premiere_ticket_offer")
      .withPayload([
          "event_id": "premiere_987",
          "content_id": "movie_987",
          "ticket_type": "standard",
          "payment_status": "paid"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

### Loyalty / Promo {#promo}

#### Getting a promo code without a complex flow {#get-promocode}

{% cut "The user sees a popup on the checkout screen: 'Get promo code SUMMER20'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("promo_summer_20", "digital_good")
          .withProductId("promo_code")
          .withBenefitType("discount_absolute")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("popup")
                      .withIdentifier("summer_promo_popup")
                      .withScreen("checkout")
                      .build()
          )
          .withPayload(mapOf(
              "promo_code" to "SUMMER20",
              "discount_value" to "20",
              "currency" to "EUR",
              "min_order_value" to "100"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "promo_summer_20", offerType: "digital_good")
      .withProductId("promo_code")
      .withBenefitType("discount_absolute")
      .withReferrer(OfferReferrer(type: "popup", identifier: "summer_promo_popup", screen: "checkout"))
      .withPayload([
          "promo_code": "SUMMER20",
          "discount_value": "20",
          "currency": "EUR",
          "min_order_value": "100"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user taps 'Get promo code'. There is no separate flow, so the result can be sent immediately." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "promo_code")
          .withProductOfferId("promo_summer_20")
          .withPayload(mapOf("promo_code" to "SUMMER20", "copied_to_clipboard" to "true"))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "promo_code", status: .success)
      .withProductOfferId("promo_summer_20")
      .withPayload(["promo_code": "SUMMER20", "copied_to_clipboard": "true"])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

### Insurance {#insurance}

#### Insurance application with server-side decision (S2S result) {#s2s}

{% cut "The user opens the trip screen and sees a button: 'Add insurance with 15% off'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("travel_insurance_offer", "insurance")
          .withProductId("travel_insurance")
          .withBenefitType("discount_percentage")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("button")
                      .withIdentifier("trip_details_insurance_button")
                      .withScreen("trip_details")
                      .build()
          )
          .withPayload(mapOf(
              "campaign_id" to "travel_insurance_q2",
              "discount_value" to "15",
              "destination_country" to "Serbia",
              "trip_duration_days" to "7"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "travel_insurance_offer", offerType: "insurance")
      .withProductId("travel_insurance")
      .withBenefitType("discount_percentage")
      .withReferrer(OfferReferrer(type: "button", identifier: "trip_details_insurance_button", screen: "trip_details"))
      .withPayload([
          "campaign_id": "travel_insurance_q2",
          "discount_value": "15",
          "destination_country": "Serbia",
          "trip_duration_days": "7"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user starts the insurance application." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("travel_insurance")
          .withProductOfferId("travel_insurance_offer")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "travel_insurance")
      .withProductOfferId("travel_insurance_offer")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user selects coverage." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("travel_insurance", "coverage_selection")
          .withProductOfferId("travel_insurance_offer")
          .withStepOption("standard")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "travel_insurance", stepType: "coverage_selection")
      .withProductOfferId("travel_insurance_offer")
      .withStepOption("standard")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user enters their details." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("travel_insurance", "traveler_details")
          .withProductOfferId("travel_insurance_offer")
          .withStepOption("manual_input")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "travel_insurance", stepType: "traveler_details")
      .withProductOfferId("travel_insurance_offer")
      .withStepOption("manual_input")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The application has been submitted for review." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.PENDING, "travel_insurance")
          .withProductOfferId("travel_insurance_offer")
          .withPayload(mapOf(
              "application_id" to "insurance_app_987",
              "coverage_type" to "standard",
              "destination_country" to "Serbia"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "travel_insurance", status: .pending)
      .withProductOfferId("travel_insurance_offer")
      .withPayload([
          "application_id": "insurance_app_987",
          "coverage_type": "standard",
          "destination_country": "Serbia"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Later, the insurance company sends the final result via S2S." %}

```java
flowResult(
    productId = "travel_insurance",
    productOfferId = "travel_insurance_offer",
    status = "success",
    payload = mapOf(
        "application_id" to "insurance_app_987",
        "policy_id" to "policy_555",
        "decision_source" to "s2s"
    )
)
```

Sending offer events via the S2S scheme will be implemented via the POST API in one of the upcoming releases. The current documentation provides an example script that demonstrates the expected integration method.

{% endcut %}

### Gaming {#gaming}

#### Purchasing a game bundle {#bundle}

{% cut "The user opens the in-game store and sees a banner: 'Starter bundle: coins + gems + bonus item'." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.offerShown("starter_bundle_offer", "bundle")
          .withProductId("starter_bundle")
          .withBenefitType("bundle_extra")
          .withReferrer(
                  OfferReferrer.newBuilder()
                      .withType("banner")
                      .withIdentifier("store_starter_bundle_banner")
                      .withScreen("game_store")
                      .build()
          )
          .withPayload(mapOf(
              "bundle_id" to "starter_bundle",
              "bonus_items" to "coins,gems,sword_skin",
              "price_tier" to "low",
              "campaign_id" to "starter_pack_campaign"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.offerShown(productOfferId: "starter_bundle_offer", offerType: "bundle")
      .withProductId("starter_bundle")
      .withBenefitType("bundle_extra")
      .withReferrer(OfferReferrer(type: "banner", identifier: "store_starter_bundle_banner", screen: "game_store"))
      .withPayload([
          "bundle_id": "starter_bundle",
          "bonus_items": "coins",
          "price_tier": "low",
          "campaign_id": "starter_pack_campaign"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user opens the bundle purchase." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("starter_bundle")
          .withProductOfferId("starter_bundle_offer")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "starter_bundle")
      .withProductOfferId("starter_bundle_offer")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user confirms the purchase." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("starter_bundle", "purchase_confirmation")
          .withProductOfferId("starter_bundle_offer")
          .withStepOption("confirmed")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "starter_bundle", stepType: "purchase_confirmation")
      .withProductOfferId("starter_bundle_offer")
      .withStepOption("confirmed")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "Purchase successfully completed." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "starter_bundle")
          .withProductOfferId("starter_bundle_offer")
          .withPayload(mapOf(
              "bundle_id" to "starter_bundle",
              "payment_status" to "paid",
              "bonus_items_granted" to "true"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "starter_bundle", status: .success)
      .withProductOfferId("starter_bundle_offer")
      .withPayload([
          "bundle_id": "starter_bundle",
          "payment_status": "paid",
          "bonus_items_granted": "true"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

### Surveys and product reviews {#surveys}

#### One-page post-purchase survey {#one-page-survey}

{% cut "The user has completed a purchase and sees a screen: 'Rate the product'. There is no offer, flowStart can be omitted." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "product_review")
          .withPayload(mapOf(
              "survey_id" to "post_purchase_review",
              "product_id" to "sku_12345",
              "rating" to "5",
              "has_comment" to "true"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "product_review", status: .success)
      .withPayload([
          "survey_id": "post_purchase_review",
          "product_id": "sku_12345",
          "rating": "5",
          "has_comment": "true"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

#### Multi-step post-purchase survey {#many-step-survey}

{% cut "The user has completed a purchase and sees a screen: 'Help us improve recommendations — answer a few questions'. There is no offer, but there is a multi-step flow." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStart("product_review_survey")
          .withPayload(mapOf(
              "survey_id" to "post_purchase_review",
              "product_id" to "sku_12345",
              "entry_point" to "order_success_screen"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStart(productId: "product_review_survey")
      .withPayload([
          "survey_id": "post_purchase_review",
          "product_id": "sku_12345",
          "entry_point": "order_success_screen"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user rates the product." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("product_review_survey", "rating")
          .withStepOption("5")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "product_review_survey", stepType: "rating")
      .withStepOption("5")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user answers what they liked." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("product_review_survey", "positive_feedback")
          .withStepOption("quality")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowStep(productId: "product_review_survey", stepType: "positive_feedback")
      .withStepOption("quality")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

{% cut "The user proceeds to the comment step but closes the screen. The last flowStep before flowResult(cancelled) helps identify where the drop-off occurred." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowStepForProduct("product_review_survey", "comment")
          .withStepOption("optional_text")
          .build()
  )
  ```

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.CANCELLED, "product_review_survey")
          .withPayload(mapOf(
              "survey_id" to "post_purchase_review",
              "product_id" to "sku_12345",
              "last_completed_step" to "comment"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let commentStep = ProductFlowEvents.flowStep(productId: "product_review_survey", stepType: "comment")
      .withStepOption("optional_text")
      .build()

  AppMetrica.report(event: commentStep)
  ```

  ```swift translate=no
  let result = ProductFlowEvents.flowResult(productId: "product_review_survey", status: .cancelled)
      .withPayload([
          "survey_id": "post_purchase_review",
          "product_id": "sku_12345",
          "last_completed_step": "comment"
      ])
      .build()

  AppMetrica.report(event: result)
  ```

{% endlist %}

{% endcut %}

{% cut "The user completed the survey to the end." %}

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "product_review_survey")
          .withPayload(mapOf(
              "survey_id" to "post_purchase_review",
              "product_id" to "sku_12345",
              "rating" to "5",
              "positive_feedback" to "quality",
              "has_comment" to "true"
          ))
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "product_review_survey", status: .success)
      .withPayload([
          "survey_id": "post_purchase_review",
          "product_id": "sku_12345",
          "rating": "5",
          "positive_feedback": "quality",
          "has_comment": "true"
      ])
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

{% endcut %}

## How to read the markup scenarios {#how-to-read}

`offerShown` 

:   Sent if the user actually saw the offer: a banner, popup, push notification, button, card, or other promo block.

`flowStart` 

:   Sent if the user has a separate start for ordering, activation, or a multi-step scenario.

`flowStep` 

:   Sent for important intermediate steps. Especially useful when you need to determine at which stage users stop or abandon the scenario.

`flowResult` 

:   Always sent when the scenario outcome is known.

If the result is not known immediately, an intermediate result is sent first:

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.PENDING, "...")
          .withProductOfferId("...")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "...", status: .pending)
      .withProductOfferId("...")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

And later, the final result is sent via S2S:

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.SUCCESS, "...")
          .withProductOfferId("...")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "...", status: .success)
      .withProductOfferId("...")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

or

{% list tabs %}

- Kotlin

  ```kotlin translate=no
  AppMetrica.reportEvent(
      ProductFlowEvent.flowResultForProduct(ProductFlowStatus.DECLINED, "...")
          .withProductOfferId("...")
          .build()
  )
  ```

- Swift

  ```swift translate=no
  let event = ProductFlowEvents.flowResult(productId: "...", status: .declined)
      .withProductOfferId("...")
      .build()

  AppMetrica.report(event: event)
  ```

{% endlist %}

## Recommended statuses {#recommended-statuses}

#|
|| **Status** | **Meaning** ||
|| `success` | Successful completion ||
|| `declined` | Declined by a third party ||
|| `pending` | Awaiting decision ||
|| `cancelled` | Cancelled by the user ||
|| `expired` | Offer or session expired ||
|| `fail` | Technical error ||
|#

## How to determine if the new event markup is right for you {#how-to}

We recommend this markup schema if your app has:

- offers;
- proposal cards;
- onboarding scenarios;
- order placement scenarios;
- financial product application scenarios;
- booking scenarios;
- subscription scenarios;
- tariff or product upgrade scenarios;
- approval scenarios;
- funnel analytics.

The schema will be especially useful if in the current implementation:

- all events are sent as `custom events`;
- events are difficult to correlate with each other;
- identical steps are named differently;
- it is difficult to analyze conversion between stages;
- there is no unified approach to the product funnel.

## Migrating from custom events {#custom-events}

If you are already using `custom events`, the migration can be gradual: new events can be sent in parallel with existing custom events.

The new standard events do not consume the `custom events` limit and allow you to verify the correctness of the integration and data completeness before migration.

After verification, sending the corresponding `custom events` can be disabled.

<!-- source: en/_includes/feedback-button.md -->
If you didn't find the answer you were looking for, you can use the feedback form to submit your question. Please describe the problem in as much detail as possible. Attach a screenshot if possible.

<a href="../troubleshooting/feedback-new">
  <span class="button">Contact support</span>
</a>

<a href="../troubleshooting/feedback-docs">
  <span class="button">Suggest an improvement for documentation</span>
</a>
<!-- endsource: en/_includes/feedback-button.md -->
