---
updatedAt: 2026-06-29T17:11:23.000Z
agentTools:
  projectIndex: https://dev.tapcart.com/llms.txt
---

# Clickstream Webhook

# Overview

Tapcart's clickstream webhook delivers realtime behavioral events from your mobile app to an endpoint you configure. Each event represents a discrete shopper action, such as opening the app, viewing a product, adding to cart, initiating checkout, and more. This document describes the full structure and meaning of every supported event type, and how to configure a webhook to begin receiving events.

Events are delivered as HTTP POST requests to your configured endpoint. The request body is a JSON object containing the event type, event specific data, and device / session context.

***

# Configuration

In your Tapcart dashboard under settings, there is a `Webhooks` section where you can globally enable or disable the feature, as well as enter your https endpoint. Below is the list of clickstream events which are eligible to be consumed via webhook. You can select all, or a subset of these to be delivered to your endpoint, allowing you to control the desired data volume entering your system.

| Event Type             | Description                                                  |
| ---------------------- | ------------------------------------------------------------ |
| `applicationInstalled` | App installed for the first time                             |
| `applicationOpened`    | App opened / brought to foreground                           |
| `cartAdd`              | Item added to the Shopify cart                               |
| `cartRemove`           | Item removed from the Shopify cart                           |
| `cartUpdated`          | Cart state changed (quantity update, discount applied, etc.) |
| `checkoutCreated`      | Shopper tapped the checkout button                           |
| `collectionViewed`     | Shopper opened a product collection                          |
| `loggedIn`             | Shopper logged in                                            |
| `loggedOut`            | Shopper logged out                                           |
| `pageView`             | Shopper viewed a screen                                      |
| `search`               | Shopper submitted a search query                             |
| `productViewed`        | Shopper opened a product detail page                         |
| `purchaseCompleted`    | Shopper completed a purchase / placed an order               |
| `pushOpened`           | Shopper opened a push notification                           |
| `wishlistItemAdded`    | Shopper added an item to a Tapcart wishlist                  |

***

# Request Structure

Every webhook payload shares the same top level structure, regardless of event type.

```json
{
  "event": "cartAdd",
  "data": { ... },
  "properties": { ... },
  "mp_metadata": {
    "mp_event_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
    "mp_session_id": "ffffffff-0000-1111-2222-333333333333"
  }
}
```

| Field         | Type   | Description                                                                                                                                                                        |
| ------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event`       | string | The event type name (see table above).                                                                                                                                             |
| `data`        | object | Event-specific payload. Structure varies by event type — documented in detail below.                                                                                               |
| `properties`  | object | Device and session context present on every event. See [Common Properties](#common-properties) below.                                                                              |
| `mp_metadata` | object | Analytics tracking identifiers. `mp_event_id` is a globally unique identifier for this event (use for deduplication); `mp_session_id` identifies the app session that produced it. |

<br />

Requests also include headers to signal high level data about the nature of the request. This can be helpful if you require additional filtering prior to parsing the request body itself. Below are some of the available headers.

| Header    | example                              |
| :-------- | :----------------------------------- |
| appid     | ABC123                               |
| eventtype | pageView                             |
| deviceid  | 00000000-1111-2222-3333-444444444444 |
| eventid   | 00000000-1111-2222-3333-444444444444 |

<br />

***

# Common Properties

The `properties` object carries device, locale, and session context on every event. Most fields are always present; a small number are conditional (noted below).

```json
{
  "appId": "ABC123",
  "device_id": "00000000-1111-2222-3333-444444444444",
  "distinct_id": "device:55555555-6666-7777-8888-999999999999",
  "time": 1778873103209,
  "os": "android",
  "os_version": 30,
  "country": "GB",
  "language": "en",
  "timezone": "Europe/London",
  "trackingEnabled": true,
  "tapcart_build": "20.19.0",
  "lib_version": "5.2.0",
  "version_code": "174",
  "version_name": "174",
  "userGroup": "userGroup016",
  "userId": null,
  "tags": []
}
```

## Identifiers

| Field                | Type           | Description                                                                                                                                                                                                  |
| -------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `appId`              | string         | Your Tapcart app identifier. Use this to confirm the event belongs to your store.                                                                                                                            |
| `device_id`          | string (UUID)  | Stable identifier for the physical device. Persists across sessions and app updates.                                                                                                                         |
| `distinct_id`        | string         | Analytics identity for this user. Format is `"device:<uuid>"` for anonymous (not logged-in) shoppers and the Shopify Customer GID (e.g. `"gid://shopify/Customer/5000000000001"`) after a successful login.  |
| `user_id` / `userId` | string \| null | Shopify Customer GID of the logged-in customer (e.g. `"gid://shopify/Customer/5000000000001"`). `null` when the shopper is not logged in. Both `user_id` and `userId` may appear; they carry the same value. |
| `tags`               | string\[]      | Shopify customer tags assigned to the logged-in customer. Empty array for anonymous users.                                                                                                                   |

## Device & Platform

| Field        | Type             | Description                                                                                      |
| ------------ | ---------------- | ------------------------------------------------------------------------------------------------ |
| `os`         | string           | Operating system: `"android"` or `"ios"`.                                                        |
| `os_version` | string \| number | OS version. A number (Android API level, e.g. `30`) on Android; a string (e.g. `"18.1"`) on iOS. |

## Locale

Depending on individual device settings, some of these fields may or may not be populated reliably.

| Field      | Type    | Description                                                                          |
| ---------- | ------- | ------------------------------------------------------------------------------------ |
| `country`  | string? | ISO 3166-1 alpha-2 country code inferred from device settings (e.g. `"US"`, `"GB"`). |
| `language` | string? | BCP 47 language tag from device settings (e.g. `"en"`, `"ar"`).                      |
| `timezone` | string? | IANA timezone string from device settings (e.g. `"America/New_York"`).               |

## App Context

| Field             | Type    | Description                                                                                                                                                                                         |
| ----------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `time`            | number  | Unix timestamp in milliseconds when the event occurred on-device.                                                                                                                                   |
| `tapcart_build`   | string  | Tapcart mobile app build version (e.g. `"20.19.0"`).                                                                                                                                                |
| `lib_version`     | string  | Version of the Tapcart analytics SDK embedded in the app (e.g. `"5.2.0"`).                                                                                                                          |
| `version_code`    | string  | Your store's app build number as published to the app stores.                                                                                                                                       |
| `version_name`    | string  | Your store's app version name as published to the app stores.                                                                                                                                       |
| `trackingEnabled` | boolean | `false` if the shopper has opted out of analytics tracking (e.g. via the iOS App Tracking Transparency prompt). Events are still delivered when `false`; respect this flag in your data processing. |
| `userGroup`       | string  | Internal A/B test cohort identifier (e.g. `"userGroup014"`). For internal Tapcart use.                                                                                                              |

***

# Notes on Shopify Data in Event Payloads

Several event types include data enriched from the Shopify Storefront API. Keep the following in mind when processing these fields.

**Global IDs (GIDs):** Shopify resources use the format `"gid://shopify/<ResourceType>/<numericId>"` (e.g. `"gid://shopify/Product/1000000000001"`). The numeric portion can be extracted for use with the Shopify Admin API.

**`__typename`:** GraphQL objects from the Storefront API include a `__typename` field on every nested object (e.g. `"__typename": "Cart"`). This is a GraphQL introspection artifact and can be safely ignored.

**MoneyV2:** Monetary amounts are represented as objects with `amount` (a decimal string) and `currencyCode` (an ISO 4217 code):

```json
{ "amount": "26.0", "currencyCode": "GBP" }
```

**Relay pagination:** Some nested Shopify collections use the Relay cursor pagination pattern (`{ "edges": [{ "node": { ... } }] }`) while others are plain arrays, depending on the API version and event type. Your parser should handle both shapes.

***

# Event Types

***

## `applicationInstalled`

Fired once when a shopper opens the app for the first time after installation. Use this to track new installs and attribute them to marketing campaigns.

### Schema

```json
{
  "event": "applicationInstalled",
  "data": { },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### `data` Fields

This event carries no event specific data.

***

## `applicationOpened`

Fired each time the app is brought to the foreground — on launch and on resume from background. Use this to measure daily/monthly active users and session starts.

### Schema

```json
{
  "event": "applicationOpened",
  "data": { },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### `data` Fields

This event carries no event specific data.

***

## `cartAdd`

Fired when a shopper adds a product variant to their Shopify cart. The `data` field contains a full snapshot of the cart at the time of the action, enriched with product and variant details from the Shopify Storefront API.

### Schema

```json
{
  "event": "cartAdd",
  "data": {
    "id": "gid://shopify/Cart/aaaaaaaaaaaaaaaaaaaaaaaa",
    "cartId": "gid://shopify/Cart/aaaaaaaaaaaaaaaaaaaaaaaa",
    "checkoutUrl": "https://www.example.com/cart/c/aaaaaaaaaaaaaaaaaaaaaaaa",
    "cost": {
      "subtotalAmount": { "amount": "26.0", "currencyCode": "GBP" },
      "totalAmount": { "amount": "26.0", "currencyCode": "GBP" }
    },
    "totalQuantity": 1,
    "updatedAt": "2026-04-24T19:26:03Z",
    "lineItems": [
      {
        "quantity": 1,
        "variantId": "gid://shopify/ProductVariant/20000000000001"
      }
    ],
    "lines": [
      {
        "id": "gid://shopify/CartLine/11111111-2222-3333-4444-555555555555?cart=aaaaaaaaaaaaaaaaaaaaaaaa",
        "quantity": 1,
        "cost": {
          "totalAmount": { "amount": "26.0", "currencyCode": "GBP" }
        },
        "discountAllocations": [],
        "attributes": [],
        "merchandise": {
          "id": "gid://shopify/ProductVariant/20000000000001",
          "title": "XL",
          "price": { "amount": "26.0", "currencyCode": "GBP" },
          "compareAtPrice": { "amount": "26.0", "currencyCode": "GBP" },
          "metafields": [],
          "product": {
            "id": "gid://shopify/Product/1000000000001",
            "title": "Example Product A",
            "handle": "example-product-a",
            "vendor": "Example Brand",
            "productType": "T-Shirts",
            "availableForSale": true,
            "requiresSellingPlan": false,
            "totalInventory": 4965,
            "tags": [],
            "metafields": [],
            "options": [
              {
                "id": "gid://shopify/ProductOption/30000000000001",
                "name": "Size",
                "values": ["S", "M", "L", "XL", "2XL"]
              }
            ],
            "priceRange": {
              "minVariantPrice": { "amount": "26.0", "currencyCode": "GBP" },
              "maxVariantPrice": { "amount": "26.0", "currencyCode": "GBP" }
            },
            "variants": {
              "edges": [
                {
                  "node": {
                    "id": "gid://shopify/ProductVariant/20000000000001",
                    "title": "XL",
                    "price": { "amount": "26.0", "currencyCode": "GBP" },
                    "compareAtPrice": { "amount": "26.0", "currencyCode": "GBP" },
                    "availableForSale": true,
                    "currentlyNotInStock": false,
                    "quantityAvailable": 993,
                    "requiresShipping": true,
                    "taxable": true,
                    "weight": 200,
                    "sku": "...",
                    "barcode": "...",
                    "selectedOptions": [{ "name": "Size", "value": "XL" }],
                    "image": {
                      "src": "https://cdn.shopify.com/...",
                      "url": "https://cdn.shopify.com/...",
                      "width": 2000
                    },
                    "metafields": []
                  }
                }
              ]
            },
            "variantsCount": { "count": 5 }
          }
        }
      }
    ],
    "buyerIdentity": {
      "countryCode": "GB",
      "deliveryAddressPreferences": []
    },
    "attributes": [],
    "discountCodes": [],
    "discountAllocations": [],
    "appliedGiftCards": [],
    "deliveryGroups": { "edges": [] },
    "note": ""
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### Key `data` Fields

| Field                                        | Type              | Description                                                                                                                              |
| -------------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `id` / `cartId`                              | string (GID)      | Shopify Cart GID. Both fields carry the same value. Use either to correlate with Shopify's Storefront or Admin APIs.                     |
| `checkoutUrl`                                | string (URL)      | Direct URL to continue checkout in a browser. This is the URL Tapcart hands off to Shopify Checkout.                                     |
| `cost.subtotalAmount`                        | MoneyV2           | Cart subtotal before shipping and taxes.                                                                                                 |
| `cost.totalAmount`                           | MoneyV2           | Cart total (may equal subtotal before discounts and shipping are calculated).                                                            |
| `totalQuantity`                              | number            | Total number of items in the cart.                                                                                                       |
| `updatedAt`                                  | string (ISO 8601) | When the cart was last modified on Shopify.                                                                                              |
| `lineItems`                                  | array             | Compact client-side summary of items in the cart. Each entry has `quantity` and `variantId` (GID). Use `lines` for authoritative data.   |
| `lines`                                      | array             | Full cart line items from the Shopify Storefront API.                                                                                    |
| `lines[].id`                                 | string (GID)      | Unique CartLine GID. Encodes both the line UUID and the cart ID.                                                                         |
| `lines[].quantity`                           | number            | Quantity of this line item.                                                                                                              |
| `lines[].cost.totalAmount`                   | MoneyV2           | Total cost for this line (price × quantity, after line-level discounts).                                                                 |
| `lines[].discountAllocations`                | array             | Discounts allocated to this specific line item.                                                                                          |
| `lines[].attributes`                         | array             | Custom line item attributes (key/value pairs).                                                                                           |
| `lines[].merchandise`                        | object            | The selected product variant (`ProductVariant`).                                                                                         |
| `lines[].merchandise.id`                     | string (GID)      | Shopify ProductVariant GID.                                                                                                              |
| `lines[].merchandise.title`                  | string            | Variant title (e.g. `"XL"`).                                                                                                             |
| `lines[].merchandise.price`                  | MoneyV2           | Selling price of this variant.                                                                                                           |
| `lines[].merchandise.compareAtPrice`         | MoneyV2           | Original/compare-at price. Equal to `price` when there is no markdown.                                                                   |
| `lines[].merchandise.product.id`             | string (GID)      | Shopify Product GID.                                                                                                                     |
| `lines[].merchandise.product.title`          | string            | Product title.                                                                                                                           |
| `lines[].merchandise.product.handle`         | string            | Shopify URL handle for the product.                                                                                                      |
| `lines[].merchandise.product.vendor`         | string            | Product vendor.                                                                                                                          |
| `lines[].merchandise.product.productType`    | string            | Product type as configured in Shopify.                                                                                                   |
| `lines[].merchandise.product.tags`           | string\[]         | Shopify product tags.                                                                                                                    |
| `lines[].merchandise.product.totalInventory` | number            | Total inventory across all variants.                                                                                                     |
| `lines[].merchandise.product.variants.edges` | array             | All product variants. Only the selected variant typically has full detail; others may be stub objects with only an `id`.                 |
| `buyerIdentity.countryCode`                  | string            | ISO 3166-1 alpha-2 country code associated with the cart buyer.                                                                          |
| `discountCodes`                              | array             | Discount codes applied to the cart. Each entry has `applicable` (boolean) and `code` (string).                                           |
| `appliedGiftCards`                           | array             | Gift cards applied to the cart.                                                                                                          |
| `attributes`                                 | array             | Custom cart attributes (key/value pairs). May include Tapcart-specific entries such as `{ "key": "sales-channel", "value": "tapcart" }`. |
| `note`                                       | string            | Order note attached to the cart.                                                                                                         |

***

## `cartRemove`

Fired when a shopper removes a product from their cart. The `data` field reflects the cart state **after** removal. A convenience field `data.lineItems` identifies the removed item.

### Schema

The top-level `data` structure is the same as `cartAdd`. The key difference is `lineItems`, which on `cartRemove` is a single **object** (not an array) describing the removed item:

```json
{
  "event": "cartRemove",
  "data": {
    "id": "gid://shopify/Cart/bbbbbbbbbbbbbbbbbbbbbbbb",
    "cartId": "gid://shopify/Cart/bbbbbbbbbbbbbbbbbbbbbbbb",
    "checkoutUrl": "https://www.example.com/cart/c/bbbbbbbbbbbbbbbbbbbbbbbb",
    "cost": {
      "subtotalAmount": { "amount": "159.0", "currencyCode": "SGD" },
      "totalAmount": { "amount": "159.0", "currencyCode": "SGD" }
    },
    "totalQuantity": 1,
    "updatedAt": "...",
    "lineItems": {
      "currency": "SGD",
      "price": "239.0",
      "productId": "gid://shopify/Product/1000000000002",
      "productTitle": "Example Sneaker",
      "quantity": 1,
      "variantId": "gid://shopify/ProductVariant/20000000000002",
      "variantTitle": "4.5",
      "vendor": "Example Brand"
    },
    "lines": [ ... ],
    "buyerIdentity": { ... },
    "attributes": [],
    "discountCodes": [],
    "appliedGiftCards": [],
    "note": ""
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### `data.lineItems` Fields

| Field          | Type         | Description                                       |
| -------------- | ------------ | ------------------------------------------------- |
| `productId`    | string (GID) | Shopify Product GID of the removed item.          |
| `variantId`    | string (GID) | Shopify ProductVariant GID of the removed item.   |
| `productTitle` | string       | Product title of the removed item.                |
| `variantTitle` | string       | Variant title of the removed item (e.g. `"4.5"`). |
| `price`        | string       | Price of the removed variant as a decimal string. |
| `currency`     | string       | ISO 4217 currency code.                           |
| `quantity`     | number       | Quantity of this line that was removed.           |
| `vendor`       | string       | Product vendor.                                   |

> **Note:** The `lines` field in `cartRemove` may use a Relay-style `{ "edges": [...] }` pagination wrapper rather than a plain array, depending on the app version. Handle both shapes.

***

## `cartUpdated`

Fired after any cart modification (quantity change, discount code applied, note updated, etc.) that does not specifically trigger `cartAdd` or `cartRemove`. Provides a lightweight cart snapshot useful for keeping external cart state in sync.

### Schema

```json
{
  "event": "cartUpdated",
  "data": {
    "id": "gid://shopify/Cart/aaaaaaaaaaaaaaaaaaaaaaaa",
    "cost": {
      "subtotalAmount": { "amount": "26.0", "currencyCode": "GBP" },
      "totalAmount": { "amount": "26.0", "currencyCode": "GBP" }
    },
    "totalQuantity": 1,
    "updatedAt": "2026-04-24T19:26:03Z",
    "discountCodes": [],
    "discountAllocations": [],
    "appliedGiftCards": [],
    "note": "",
    "lines": [
      {
        "id": "gid://shopify/CartLine/...",
        "quantity": 1,
        "cost": {
          "totalAmount": { "amount": "26.0", "currencyCode": "GBP" }
        },
        "discountAllocations": [],
        "attributes": [],
        "merchandise": {
          "id": "gid://shopify/ProductVariant/20000000000001",
          "title": "XL",
          "price": { "amount": "26.0", "currencyCode": "GBP" },
          "compareAtPrice": { "amount": "26.0", "currencyCode": "GBP" },
          "metafields": [],
          "product": { ... }
        }
      }
    ]
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### Key `data` Fields

| Field              | Type              | Description                                              |
| ------------------ | ----------------- | -------------------------------------------------------- |
| `id`               | string (GID)      | Shopify Cart GID.                                        |
| `cost`             | object            | Cart subtotal and total amounts.                         |
| `totalQuantity`    | number            | Total number of items currently in the cart.             |
| `updatedAt`        | string (ISO 8601) | When the cart was last modified.                         |
| `discountCodes`    | array             | Discount codes applied to the cart.                      |
| `appliedGiftCards` | array             | Gift cards applied to the cart.                          |
| `lines`            | array             | Current cart line items. Same structure as in `cartAdd`. |
| `note`             | string            | Order note attached to the cart.                         |

> **Note:** Unlike `cartAdd` and `cartRemove`, this event does not include `buyerIdentity`, `delivery`, or `deliveryGroups`.

***

## `checkoutCreated`

Fired when the shopper taps the checkout button, initiating the Shopify checkout flow. The `data` field wraps the full cart in a `cart` sub-object and adds a `cartWasEmpty` flag to distinguish standard checkouts from direct "Buy Now" flows.

### Schema

```json
{
  "event": "checkoutCreated",
  "data": {
    "cart": {
      "id": "gid://shopify/Cart/cccccccccccccccccccccccc",
      "checkoutUrl": "https://www.example.com/cart/c/cccccccccccccccccccccccc",
      "cartWasEmpty": true,
      "cost": {
        "subtotalAmount": { "amount": "6200.0", "currencyCode": "PHP" },
        "totalAmount": { "amount": "6200.0", "currencyCode": "PHP" }
      },
      "lines": [
        {
          "id": "gid://shopify/CartLine/...",
          "quantity": 1,
          "cost": {
            "totalAmount": { "amount": "6200.0", "currencyCode": "PHP" }
          },
          "discountAllocations": [],
          "attributes": [],
          "merchandise": {
            "id": "gid://shopify/ProductVariant/20000000000003",
            "compareAtPrice": { "amount": "6200.0", "currencyCode": "PHP" },
            "metafields": [],
            "product": {
              "id": "gid://shopify/Product/1000000000003",
              "title": "Example Athletic Shoe",
              "handle": "example-athletic-shoe",
              "availableForSale": true,
              "productType": "Shoes",
              "tags": ["example-tag-1", "example-tag-2"],
              "metafields": [
                { "key": "nickname", "value": "example-value" },
                { "key": "gender", "value": "WOMENS" }
              ],
              "options": [ ... ],
              "priceRange": { ... },
              "variants": [ ... ]
            }
          }
        }
      ],
      "buyerIdentity": { "countryCode": "PH", "deliveryAddressPreferences": [] },
      "attributes": [],
      "discountCodes": [],
      "discountAllocations": [],
      "appliedGiftCards": [],
      "deliveryGroups": []
    }
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### Key `data.cart` Fields

The cart object mirrors the structure documented under [`cartAdd`](#cartadd), with one notable addition:

| Field          | Type    | Description                                                                                                                                                   |
| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cartWasEmpty` | boolean | `true` if the cart was empty when checkout was initiated, as happens with "Buy Now" / direct-to-checkout product flows. `false` for a standard cart checkout. |

> **Note:** In `checkoutCreated`, the cart `lines` array and nested variant/product objects do not use the `__typename` field seen in `cartAdd` and `cartRemove`. The data structures are otherwise equivalent.

***

## `collectionViewed`

Fired when a shopper opens a product collection page within the app.

### Schema

```json
{
  "event": "collectionViewed",
  "data": {
    "collectionId": "100000000001",
    "collectionTitle": "100000000001"
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### `data` Fields

| Field             | Type   | Description                                                                                                                                             |
| ----------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `collectionId`    | string | The Shopify collection ID as a numeric string (not a GID). Use this to look up the collection via the Shopify Admin API.                                |
| `collectionTitle` | string | The display title of the collection. In some app configurations this field may be populated with the collection ID rather than the human-readable name. |

***

## `loggedIn`

Fired when a shopper successfully authenticates. After this event, subsequent events on this device will have `properties.distinct_id` set to the Shopify Customer GID.

### Schema

```json
{
  "event": "loggedIn",
  "data": {
    "userId": "gid://shopify/Customer/5000000000001",
    "tags": ["vip", "wholesale"]
  },
  "properties": {
    "userId": "gid://shopify/Customer/5000000000001",
    "tags": ["vip", "wholesale"],
    ...
  },
  "mp_metadata": { ... }
}
```

### `data` Fields

| Field    | Type         | Description                                                                                                     |
| -------- | ------------ | --------------------------------------------------------------------------------------------------------------- |
| `userId` | string (GID) | The Shopify Customer GID of the authenticated customer (e.g. `"gid://shopify/Customer/5000000000001"`).         |
| `tags`   | string\[]    | Shopify customer tags assigned to this customer. Useful for segmentation (e.g. VIP status, wholesale accounts). |

> **Note:** `userId` and `tags` are also duplicated in `properties` on this event.

***

## `loggedOut`

Fired when a shopper logs out. After this event, subsequent events on this device will have `properties.distinct_id` set back to the `"device:<uuid>"` format.

### Schema

```json
{
  "event": "loggedOut",
  "data": {
    "userId": null
  },
  "properties": {
    "userId": null,
    "tags": [],
    ...
  },
  "mp_metadata": { ... }
}
```

### `data` Fields

| Field    | Type | Description                                                                 |
| -------- | ---- | --------------------------------------------------------------------------- |
| `userId` | null | Always `null` on logout — indicates no customer is currently authenticated. |

***

## `pageView`

Fired when a shopper views a screen in the app that does not have a more specific event type (i.e., screens other than product detail pages and collections). Use this to track general navigation patterns and session depth.

### Schema

```json
{
  "event": "pageView",
  "data": {
    "_analytics": {}
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### `data` Fields

| Field        | Type   | Description                                                               |
| ------------ | ------ | ------------------------------------------------------------------------- |
| `_analytics` | object | Reserved for future analytics metadata. Currently always an empty object. |

<br />

***

## `productViewed`

Fired when a shopper opens a product detail page. The `data` field is a rich Shopify product object from the Storefront API, including all variants, images, metafields, and pricing information.

### Schema

```json
{
  "event": "productViewed",
  "data": {
    "id": "gid://shopify/Product/1000000000004",
    "productId": "1000000000004",
    "title": "Example Product B",
    "productTitle": "Example Product B",
    "handle": "example-product-b",
    "vendor": "Example Brand",
    "productType": "T Shirts",
    "availableForSale": true,
    "requiresSellingPlan": false,
    "publishedAt": "2026-03-27T17:00:02Z",
    "updatedAt": "2026-04-24T16:45:27Z",
    "productPrice": "26.0",
    "multiCurrencyCode": "GBP",
    "description": "...",
    "descriptionHtml": "<p>...</p>",
    "tags": [],
    "productTagsList": [],
    "metafields": [],
    "featuredImage": {
      "url": "https://cdn.shopify.com/...",
      "width": 2000,
      "height": 2000
    },
    "images": [
      {
        "url": "https://cdn.shopify.com/...",
        "altText": "Example Product B",
        "width": 2000,
        "height": 2000
      }
    ],
    "media": [
      {
        "mediaContentType": "IMAGE",
        "image": { "url": "https://cdn.shopify.com/..." }
      }
    ],
    "options": [
      {
        "id": "gid://shopify/ProductOption/30000000000002",
        "name": "Size",
        "values": ["S", "M", "L", "XL", "2XL"]
      }
    ],
    "priceRange": {
      "minVariantPrice": { "amount": "26.0", "currencyCode": "GBP" },
      "maxVariantPrice": { "amount": "26.0", "currencyCode": "GBP" }
    },
    "compareAtPriceRange": {
      "minVariantPrice": { "amount": "26.0", "currencyCode": "GBP" },
      "maxVariantPrice": { "amount": "26.0", "currencyCode": "GBP" }
    },
    "variants": [
      {
        "id": "gid://shopify/ProductVariant/20000000000004",
        "title": "S",
        "price": { "amount": "26.0", "currencyCode": "GBP" },
        "compareAtPrice": { "amount": "26.0", "currencyCode": "GBP" },
        "availableForSale": true,
        "selectedOptions": [{ "name": "Size", "value": "S" }],
        "image": {
          "id": "gid://shopify/ProductImage/40000000000001",
          "url": "https://cdn.shopify.com/...",
          "src": "https://cdn.shopify.com/...",
          "originalSrc": "https://cdn.shopify.com/...",
          "transformedSrc": "https://cdn.shopify.com/...",
          "width": 2000,
          "height": 2000
        }
      }
    ],
    "sellingPlanGroups": { "edges": [] },
    "seo": {
      "description": "..."
    }
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### Key `data` Fields

| Field                    | Type              | Description                                                                                                                                                                                                          |
| ------------------------ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                     | string (GID)      | Shopify Product GID.                                                                                                                                                                                                 |
| `productId`              | string            | Numeric Shopify Product ID extracted from the GID (without the `gid://shopify/Product/` prefix).                                                                                                                     |
| `title` / `productTitle` | string            | Product title. Both fields carry the same value.                                                                                                                                                                     |
| `handle`                 | string            | Shopify URL handle for the product (used in storefront URLs).                                                                                                                                                        |
| `vendor`                 | string            | Product vendor.                                                                                                                                                                                                      |
| `productType`            | string            | Shopify product type as configured in the merchant's catalog.                                                                                                                                                        |
| `availableForSale`       | boolean           | `true` if any variant of this product is currently available for purchase.                                                                                                                                           |
| `requiresSellingPlan`    | boolean           | `true` if the product can only be purchased through a subscription selling plan.                                                                                                                                     |
| `publishedAt`            | string (ISO 8601) | When the product was published to the sales channel.                                                                                                                                                                 |
| `updatedAt`              | string (ISO 8601) | When the product was last modified in Shopify.                                                                                                                                                                       |
| `productPrice`           | string            | Price of the first (default) variant as a decimal string.                                                                                                                                                            |
| `multiCurrencyCode`      | string            | ISO 4217 currency code in which the product is displayed to this shopper.                                                                                                                                            |
| `description`            | string            | Plain-text product description (HTML stripped).                                                                                                                                                                      |
| `descriptionHtml`        | string            | Full HTML product description as configured in Shopify.                                                                                                                                                              |
| `tags`                   | string\[]         | Shopify product tags.                                                                                                                                                                                                |
| `productTagsList`        | string\[]         | Alias for `tags`. May differ in some app configurations.                                                                                                                                                             |
| `metafields`             | array             | Shopify product metafields configured for your app. Each entry has `key` and `value` strings.                                                                                                                        |
| `featuredImage`          | object            | The product's primary image with `url`, `width`, and `height`.                                                                                                                                                       |
| `images`                 | array             | All product images. Each has `url`, `altText`, `width`, `height`.                                                                                                                                                    |
| `media`                  | array             | All product media (images, videos, 3D models). Each entry has `mediaContentType` (`"IMAGE"`, `"VIDEO"`, `"MODEL_3D"`) and a type-specific `image` or `sources` payload.                                              |
| `options`                | array             | Product option definitions (e.g. Size, Color). Each has `id`, `name`, and `values` (all possible option values).                                                                                                     |
| `priceRange`             | object            | Min and max variant selling prices across the product.                                                                                                                                                               |
| `compareAtPriceRange`    | object            | Min and max compare-at (original) prices across the product.                                                                                                                                                         |
| `variants`               | array             | All product variants as a flat array (not the `edges`/`node` Relay pattern used in cart events). Each variant includes `id`, `title`, `price`, `compareAtPrice`, `availableForSale`, `selectedOptions`, and `image`. |
| `sellingPlanGroups`      | object            | Available subscription selling plans in Relay pagination format (`{ "edges": [...] }`). Empty when the product has no selling plans.                                                                                 |
| `seo.description`        | string            | SEO meta description for the product page.                                                                                                                                                                           |

***

<br />

### `purchaseCompleted`

Fired when a shopper completes a purchase and an order is created. This is the conversion event — use it to attribute revenue and reconcile orders against earlier behavioral events. The `data` field carries the Shopify order identity, a snapshot of the purchased `cart` (line items and price breakdown), and the cart `token`.

The monetary `amount` values in this event are **numbers** (e.g. `110`, `23.28`), unlike the decimal-string amounts (e.g. `"6200.0"`) found in the Storefront-API-sourced cart events such as [`cartAdd`](#cartadd) and [`checkoutCreated`](#checkoutcreated).

#### Schema

```json
{
  "event": "purchaseCompleted",
  "data": {
    "id": "gid://shopify/OrderIdentity/5984563527820",
    "cart": {
      "token": "hWNDtrzjnmsS8VYuQZjXHIKy",
      "lines": [
        {
          "merchandiseId": "gid://shopify/ProductVariant/44257379352716",
          "productId": "gid://shopify/Product/8201169338508",
          "title": "T500",
          "quantity": 1,
          "price": { "amount": 110, "currencyCode": "MYR" },
          "image": {
            "altText": "...",
            "sm": "https://cdn.shopify.com/.../jd_CT500DA_a_64x64.jpg",
            "md": "https://cdn.shopify.com/.../jd_CT500DA_a_128x128.jpg",
            "lg": "https://cdn.shopify.com/.../jd_CT500DA_a_256x256.jpg"
          },
          "discounts": [
            {
              "title": "CHBJDZX8PV",
              "applicationType": "code",
              "value": 15,
              "valueType": "percentage",
              "amount": { "amount": 2.39, "currencyCode": "USD" }
            }
          ]
        }
      ],
      "price": {
        "subtotal": { "amount": 110, "currencyCode": "MYR" },
        "shipping": { "amount": 0, "currencyCode": "MYR" },
        "taxes": { "amount": 0, "currencyCode": "MYR" },
        "total": { "amount": 110, "currencyCode": "MYR" },
        "discounts": []
      }
    }
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

#### Key `data` Fields

| Field        | Type         | Description                                                                             |
| ------------ | ------------ | --------------------------------------------------------------------------------------- |
| `id`         | string (GID) | Shopify Order Identity GID for the completed order (`gid://shopify/OrderIdentity/...`). |
| `cart.token` | string       | Opaque cart token identifying the cart this purchase originated from.                   |
| `cart.lines` | array        | The purchased line items. See fields below.                                             |
| `cart.price` | object       | Order-level price breakdown. See fields below.                                          |

##### `cart.lines[*]`

| Field           | Type         | Description                                                                                           |
| --------------- | ------------ | ----------------------------------------------------------------------------------------------------- |
| `merchandiseId` | string (GID) | Shopify ProductVariant GID for the purchased variant.                                                 |
| `productId`     | string (GID) | Shopify Product GID for the purchased product.                                                        |
| `title`         | string       | Product title at time of purchase.                                                                    |
| `quantity`      | number       | Quantity purchased.                                                                                   |
| `price`         | object       | Per-unit price as `{ "amount": <number>, "currencyCode": <string> }`.                                 |
| `image`         | object       | Product image with `altText` and `sm` / `md` / `lg` thumbnail URLs (64px / 128px / 256px).            |
| `discounts`     | array        | Discounts applied to this line. Empty when none apply. See [discount fields](#discount-fields) below. |

##### `cart.price`

| Field       | Type   | Description                                                                                                      |
| ----------- | ------ | ---------------------------------------------------------------------------------------------------------------- |
| `subtotal`  | object | Sum of line item prices before shipping and taxes, as `{ "amount": <number>, "currencyCode": <string> }`.        |
| `shipping`  | object | Shipping cost.                                                                                                   |
| `taxes`     | object | Total taxes.                                                                                                     |
| `total`     | object | Grand total charged to the shopper.                                                                              |
| `discounts` | array  | Cart-level discounts applied to the order. Empty when none apply. See [discount fields](#discount-fields) below. |

##### Discount fields

Both `cart.lines[*].discounts` and `cart.price.discounts` use the same shape:

| Field             | Type   | Description                                                                           |
| ----------------- | ------ | ------------------------------------------------------------------------------------- |
| `title`           | string | Discount code or name (e.g. the code entered at checkout).                            |
| `applicationType` | string | How the discount was applied (e.g. `"code"`).                                         |
| `value`           | number | The discount value (e.g. `15` for a 15% discount).                                    |
| `valueType`       | string | How `value` is interpreted (e.g. `"percentage"`).                                     |
| `amount`          | object | The resolved monetary discount as `{ "amount": <number>, "currencyCode": <string> }`. |

***

## `pushOpened`

Fired when a shopper opens a push notification sent via Tapcart's push notification feature. Use this to measure push notification engagement and conversion.

### Schema

```json
{
  "event": "pushOpened",
  "data": {
    "actionId": "expo.modules.notifications.actions.DEFAULT",
    "data": {
      "aps": {
        "alert": {
          "title": "Push notification title",
					"body": "Push notification body"
        }
      },
      "destination": {
        "type": "internal",
				"url": "/products?id=123456"
      },
			"id": "123456",
      "payload": {
        "attachment": "https://cdn.shopify.com/...",
        "notification_id": "123456",
        "segment_id": "123456",
				"type": "product"
			}
    }
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### `data` Fields

| Field                          | Type   | Description                                                                                               |
| ------------------------------ | ------ | --------------------------------------------------------------------------------------------------------- |
| `data.aps.alert.title`         | string | The title (main content) of the push notification                                                         |
| `data.aps.alert.body`          | string | The body (secondary content) of the push notification                                                     |
| `data.destination.type`        | string |                                                                                                           |
| `data.destination.url`         | string | The internal destination url of the push. This is where the user will land in app after opening the push. |
| `data.id`                      | string | The primary identifier for the push.                                                                      |
| `data.payload.attachment`      | string | If the push includes visual content, it will be sourced from this url.                                    |
| `data.payload.notification_id` | string | The primary identifier for the push.                                                                      |
| `data.payload.segment_id`      | string | The primary identifier for the customer segment which was targeted by this push.                          |
| `data.payload.type`            | string |                                                                                                           |

<br />

***

## `search`

Fired when a shopper submits a search query in the app's search bar or a search block. Use this to understand popular search terms and identify catalog gaps.

### Schema

```json
{
  "event": "search",
  "data": {
    "query": "Tank ",
    "metadata": {
      "blockId": "000000000000000000000001",
      "layoutId": "000000000000000000000002"
    }
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### `data` Fields

| Field               | Type   | Description                                                                                                   |
| ------------------- | ------ | ------------------------------------------------------------------------------------------------------------- |
| `query`             | string | The raw search string entered by the shopper. May include trailing whitespace; trim before processing.        |
| `metadata`          | object | Identifies the search UI component that triggered the event. May be absent on events from older app versions. |
| `metadata.blockId`  | string | The Tapcart content block ID of the search component.                                                         |
| `metadata.layoutId` | string | The Tapcart layout ID containing the search component.                                                        |

***

## `wishlistItemAdded`

Fired when a shopper saves a product variant to a Tapcart native wishlist. The `data.itemDetail` field contains a product and variant summary drawn from Shopify data.

#### Schema

```json
{
  "event": "wishlistItemAdded",
  "data": {
    "wishlistId": "000000000000000000000003",
    "wishlistType": "tapcartNative",
    "itemType": "variant",
    "itemDetail": {
      "product_id": "1000000000005",
      "variant_id": "20000000000005",
      "product_name": "Example Graphic T-Shirt",
      "product_title": "Example Graphic T-Shirt",
      "product_url": "https://yourstore.myshopify.com/products/example-graphic-tshirt-black",
      "product_image_url": "https://cdn.shopify.com/...",
      "sku": "EXAMPLE-SKU-001",
      "vendor": "Example Vendor",
      "variant_name": "L / Black",
      "variant_price": 7,
      "variant_compare_at_price": 50,
      "currency": "USD",
      "multi_currency_code": "USD",
      "available_for_sale": true,
      "variant_option_names": ["Size", "Color"],
      "variant_option_values": ["L", "Black"],
      "tags": ["best seller", "sale"],
      "updated_at": "2026-04-24T21:03:43.708Z"
    }
  },
  "properties": { ... },
  "mp_metadata": { ... }
}
```

### `data` Fields

| Field          | Type   | Description                                                                                                                                          |
| -------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `wishlistId`   | string | Tapcart internal identifier for the wishlist this item was added to.                                                                                 |
| `wishlistType` | string | The wishlist implementation type. `"tapcartNative"` indicates Tapcart's built-in wishlist feature.                                                   |
| `itemType`     | string | The granularity of the wishlisted item. `"variant"` means the specific variant (including option selections) was saved, not just the parent product. |

### `data.itemDetail` Fields

| Field                            | Type              | Description                                                                                           |
| -------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------- |
| `product_id`                     | string            | Numeric Shopify Product ID (without GID prefix).                                                      |
| `variant_id`                     | string            | Numeric Shopify ProductVariant ID (without GID prefix).                                               |
| `product_name` / `product_title` | string            | Product title. Both carry the same value.                                                             |
| `product_url`                    | string (URL)      | Canonical Shopify storefront URL for the product.                                                     |
| `product_image_url`              | string (URL)      | URL of the product's featured image.                                                                  |
| `sku`                            | string            | SKU of the wishlisted variant.                                                                        |
| `vendor`                         | string            | Product vendor.                                                                                       |
| `variant_name`                   | string            | Human-readable variant label, combining all selected option values (e.g. `"L / Black"`).              |
| `variant_price`                  | number            | Current selling price of the variant (numeric, not a decimal string).                                 |
| `variant_compare_at_price`       | number            | Compare-at (original) price of the variant.                                                           |
| `currency`                       | string            | ISO 4217 currency code for the displayed prices.                                                      |
| `multi_currency_code`            | string            | Currency in which the variant is displayed to this shopper. Typically matches `currency`.             |
| `available_for_sale`             | boolean           | Whether this variant is currently purchasable.                                                        |
| `variant_option_names`           | string\[]         | Names of the product options in order (e.g. `["Size", "Color"]`).                                     |
| `variant_option_values`          | string\[]         | Selected values for each option, in the same order as `variant_option_names` (e.g. `["L", "Black"]`). |
| `tags`                           | string\[]         | Shopify product tags on the parent product.                                                           |
| `updated_at`                     | string (ISO 8601) | Timestamp of when this wishlist item was recorded in Tapcart's system.                                |