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.
{
"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 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. |
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 |
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).
{
"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):
{ "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
applicationInstalledFired 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
{
"event": "applicationInstalled",
"data": { },
"properties": { ... },
"mp_metadata": { ... }
}data Fields
data FieldsThis event carries no event specific data.
applicationOpened
applicationOpenedFired 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
{
"event": "applicationOpened",
"data": { },
"properties": { ... },
"mp_metadata": { ... }
}data Fields
data FieldsThis event carries no event specific data.
cartAdd
cartAddFired 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
{
"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
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
cartRemoveFired 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:
{
"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
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
linesfield incartRemovemay use a Relay-style{ "edges": [...] }pagination wrapper rather than a plain array, depending on the app version. Handle both shapes.
cartUpdated
cartUpdatedFired 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
{
"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
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
cartAddandcartRemove, this event does not includebuyerIdentity,delivery, ordeliveryGroups.
checkoutCreated
checkoutCreatedFired 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
{
"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
data.cart FieldsThe cart object mirrors the structure documented under 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 cartlinesarray and nested variant/product objects do not use the__typenamefield seen incartAddandcartRemove. The data structures are otherwise equivalent.
collectionViewed
collectionViewedFired when a shopper opens a product collection page within the app.
Schema
{
"event": "collectionViewed",
"data": {
"collectionId": "100000000001",
"collectionTitle": "100000000001"
},
"properties": { ... },
"mp_metadata": { ... }
}data Fields
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
loggedInFired 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
{
"event": "loggedIn",
"data": {
"userId": "gid://shopify/Customer/5000000000001",
"tags": ["vip", "wholesale"]
},
"properties": {
"userId": "gid://shopify/Customer/5000000000001",
"tags": ["vip", "wholesale"],
...
},
"mp_metadata": { ... }
}data Fields
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:
userIdandtagsare also duplicated inpropertieson this event.
loggedOut
loggedOutFired 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
{
"event": "loggedOut",
"data": {
"userId": null
},
"properties": {
"userId": null,
"tags": [],
...
},
"mp_metadata": { ... }
}data Fields
data Fields| Field | Type | Description |
|---|---|---|
userId | null | Always null on logout — indicates no customer is currently authenticated. |
pageView
pageViewFired 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
{
"event": "pageView",
"data": {
"_analytics": {}
},
"properties": { ... },
"mp_metadata": { ... }
}data Fields
data Fields| Field | Type | Description |
|---|---|---|
_analytics | object | Reserved for future analytics metadata. Currently always an empty object. |
productViewed
productViewedFired 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
{
"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
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. |
purchaseCompleted
purchaseCompletedFired 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 and checkoutCreated.
Schema
{
"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
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[*]
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 below. |
cart.price
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 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
pushOpenedFired when a shopper opens a push notification sent via Tapcart's push notification feature. Use this to measure push notification engagement and conversion.
Schema
{
"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
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 |
search
searchFired 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
{
"event": "search",
"data": {
"query": "Tank ",
"metadata": {
"blockId": "000000000000000000000001",
"layoutId": "000000000000000000000002"
}
},
"properties": { ... },
"mp_metadata": { ... }
}data Fields
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
wishlistItemAddedFired 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
{
"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
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
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. |
