Swan SDK
Guides

Track events

Screen tracking, typed e-commerce events, custom events, super-properties and the offline-first event queue.

Before reading this, Concepts → Event model has the model — families of events, offline queue, batching. This guide is the how.

You'll learn:

  1. Screen views — when and how
  2. Typed e-commerce events — the full catalog
  3. Custom events — when typed events don't fit
  4. Super-properties — set once, ride every event
  5. Manual flush — and when you'd want one
  6. Inspecting the queue + session

1. Track a screen view

Call once per screen the user lands on. The campaigns engine uses screen events to segment users (e.g. "show offer to users who hit Cart but not Checkout in the last 24h").

import cx.swan.sdk.Swan
import cx.swan.sdk.SwanEvents

// Recommended: SwanEvents helper. Wire event name is "screen".
SwanEvents.screen(mapOf(
    "screenName" to "ProductDetail",
    "productId"  to "SKU-100",
))

// Or: the equivalent low-level call
Swan.track("screen", mapOf(
    "screenName" to "ProductDetail",
    "productId"  to "SKU-100",
))

Pair with setCurrentScreenName so subsequent events get the current screen as a super-property without you passing it per-event:

Swan.setCurrentScreenName("ProductDetail")
SwanEvents.screen(attributes: ["screenName": "ProductDetail", "productId": "SKU-100"])
Swan.shared.setCurrentScreenName("ProductDetail")
import SwanSDK from '@loyalytics/swan-react-native-sdk';

const sdk = SwanSDK.getCurrentInstance();
sdk?.screen({ screenName: 'ProductDetail', productId: 'SKU-100' });
sdk?.setCurrentScreenName('ProductDetail');
Swan.screen({ screenName: 'ProductDetail', productId: 'SKU-100' });
Swan.setCurrentScreenName('ProductDetail');

2. Typed e-commerce events

These exist because the Swan campaigns engine recognises these exact event names and payload shapes and can target / segment on them. Free-form customEvent("productViewed", ...) will land but won't be indexed as e-commerce. Use the typed helpers for anything in the catalog below.

import cx.swan.sdk.SwanEvents

SwanEvents.productViewed(mapOf(
    "id"       to "SKU-100",
    "name"     to "Cotton tee",
    "price"    to 49.95,
    "currency" to "AED",
    "category" to "Apparel/Tops",
))

SwanEvents.checkoutStarted(mapOf(
    "cartId"     to "cart-abc",
    "itemCount"  to 3,
    "totalValue" to 142.50,
    "currency"   to "AED",
))

SwanEvents.orderCompleted(mapOf(
    "orderId"    to "ORD-9001",
    "totalValue" to 142.50,
    "currency"   to "AED",
    "items"      to listOf(
        mapOf("id" to "SKU-100", "qty" to 1),
        mapOf("id" to "SKU-200", "qty" to 2),
    ),
))
SwanEvents.productViewed(attributes: [
    "id": "SKU-100", "name": "Cotton tee",
    "price": 49.95, "currency": "AED",
])

SwanEvents.checkoutStarted(attributes: [
    "cartId": "cart-abc", "itemCount": 3,
    "totalValue": 142.50, "currency": "AED",
])
import SwanSDK from '@loyalytics/swan-react-native-sdk';

const sdk = SwanSDK.getCurrentInstance();

sdk?.productViewed({
    productId: 'SKU-100',
    productName: 'Cotton tee',
    price: 49.95,
    currency: 'AED',
    category: 'Apparel/Tops',
});

sdk?.checkoutStarted({
    checkoutId: 'co-abc',
    orderId: 'ORD-9001',
    totalAmount: 142.50,
    productIds: [
        { productId: 'SKU-100', quantity: 1, price: 49.95 },
        { productId: 'SKU-200', quantity: 2, price: 46.275 },
    ],
});

sdk?.checkoutCompleted({
    checkoutId: 'co-abc',
    orderId: 'ORD-9001',
    totalAmount: 142.50,
    productIds: [
        { productId: 'SKU-100', quantity: 1, price: 49.95 },
        { productId: 'SKU-200', quantity: 2, price: 46.275 },
    ],
});

The full set of typed methods — productViewed, productClicked, productListViewed, productAddedToAddTocart, productRemovedFromAddToCart, productAddedToWishlist, productRemovedFromWishlist, wishlistProductAddedToCart, clearCart, cartViewed, selectCategory, categoryViewedPage, offerAvailed, checkoutStarted, checkoutCompleted, checkoutCanceled, paymentInfoEntered, orderCompleted, orderRefunded, orderCancelled, orderExperianceRating, productRatedOrReviewed, productReview, productQuantitySelected, purchased, shipped, appLaunched, appUpdated, accountDeletion, forgotPassword, search, share, screen — is exported as methods on the SDK instance.

Swan.SwanEvents.productViewed({
    id: 'SKU-100', name: 'Cotton tee',
    price: 49.95, currency: 'AED',
});

Full catalog

MethodWire event nameTypical attributes
appLaunchedappLaunched{} (auto-tracked at SDK init too)
appUpdatedappUpdated{ fromVersion, toVersion }
accountDeletionaccountDeletion{}
forgotPasswordforgotPassword{ method } (email/sms)
searchsearch{ searchKeyword }
shareshare{ productId, channel }
productViewedproductViewed{ id, name, price, currency, category }
productClickedproductClicked{ id, name, position, listName }
productListViewedproductListViewed{ listName, listId, products[] }
productRatedOrReviewedproductRatedOrReviewed{ id, rating, reviewBody? }
productReviewproductReview{ id, rating, reviewBody }
productQuantitySelectedproductQuantitySelected{ id, qty }
productAddedToAddTocartproductAddedToaddTocart{ id, qty, price }
productRemovedFromAddToCartproductRemovedFromAddToCart{ id, qty }
clearCartclearCart{}
cartViewedcartViewed{ cartId, itemCount, totalValue }
selectCategoryselectCategory{ id, name }
categoryViewedPagecategoryViewedPage{ id, name, productCount }
productAddedToWishlistproductAddedToWishlist{ id }
productRemovedFromWishlistproductRemovedFromWishlist{ id }
wishlistProductAddedToCartwishlistProductAddedToCart{ id }
offerAvailedofferAvailed{ offerId, discount }
checkoutStartedcheckoutStarted{ cartId, itemCount, totalValue, currency }
checkoutCompletedcheckoutCompleted{ orderId, totalValue, currency }
checkoutCanceledcheckoutCanceled{ cartId, reason }
paymentInfoEnteredpaymentInfoEntered{ method }
orderCompletedorderCompleted{ orderId, totalValue, currency, items[] }
orderRefundedorderRefunded{ orderId, amount, reason }
orderCancelledorderCancelled{ orderId, reason }
orderExperianceRatingorderExperianceRating{ orderId, rating }
purchasedpurchased{ orderId, totalValue, currency }
shippedshipped{ orderId, trackingNumber }

Wire names with unusual spellings

Two wire event names use spellings that look like typos but are intentional: productAddedToaddTocart (lowercase a in the middle) and orderExperianceRating (Experiance, not Experience). The SDK method names are spelled normally (productAddedToAddTocart, orderExperianceRating) so your call sites stay clean, but campaign rules must match the wire spelling exactly.


3. Custom events — when typed don't fit

Anything domain-specific that isn't in the e-commerce catalog. The campaigns engine still ingests custom events; they just aren't auto-recognized as e-commerce.

Swan.customEvent("clickedHero", mapOf(
    "variant"  to "A",
    "position" to 0,
))

// No attributes
Swan.customEvent("onboardingDismissed")
Swan.shared.track("clickedHero", attributes: ["variant": "A", "position": 0])

iOS routes custom events through track(_:attributes:) — the same wire shape as Android's customEvent. No separate customEvent method.

import SwanSDK from '@loyalytics/swan-react-native-sdk';

const sdk = SwanSDK.getCurrentInstance();
sdk?.customEvent('clickedHero', { variant: 'A', position: 0 });
sdk?.customEvent('onboardingDismissed');
Swan.customEvent('clickedHero', { variant: 'A', position: 0 });

Naming convention: camelCase like the typed events (clickedHero, onboardingDismissed). Keep names stable across versions — campaign rules match on string equality.


4. Super-properties

Attributes that should ride along on every subsequent event, set once.

HelperSet-once values
setCountry(string)"AE", "SA", "US" — ISO-3166 alpha-2 recommended
setCurrency(string)"AED", "SAR", "USD" — ISO-4217
setBusinessUnit(string)host-app-defined (e.g. "loyalty-app", "guest-checkout")
setCurrentScreenName(string)rides every event, refresh on each navigation
Swan.setCountry("AE")
Swan.setCurrency("AED")
Swan.setBusinessUnit("loyalty-app")

// in your nav listener
Swan.setCurrentScreenName(currentRoute)
Swan.shared.setCountry("AE")
Swan.shared.setCurrency("AED")
Swan.shared.setBusinessUnit("loyalty-app")
Swan.shared.setCurrentScreenName(currentRoute)
import SwanSDK from '@loyalytics/swan-react-native-sdk';

const sdk = SwanSDK.getCurrentInstance();

sdk?.setCountry('AE');
sdk?.setCurrency('AED');
sdk?.setBusinessUnit('loyalty-app');

// in a navigation listener
navigation.addListener('state', () => {
    const route = navigation.getCurrentRoute()?.name;
    if (route) sdk?.setCurrentScreenName(route);
});
Swan.setCountry('AE');
Swan.setCurrency('AED');
Swan.setBusinessUnit('loyalty-app');

Super-properties are per-instance, in-memory. They reset on app restart — set them in your app's init code so they're always present.


5. Manual flush

The SDK flushes on its own schedule (every ~30s, or once 10 events are queued — the default batch size — or on app foreground / background transitions). You rarely need to flush manually. Cases where you might:

  • Just before logout / sign-out — ensure the last anonymous events ingest under the right CDID before the rotation. (Note: login(...) already flushes for you; you only need explicit flush around logout() for an extra guarantee.)
  • In an integration test — to assert the wire round-trip without waiting for the timer.
  • Before exiting the app on a controlled path — e.g. a custom "exit" button — the lifecycle observer already covers normal backgrounding.
Swan.flush()
Swan.shared.flush()
import SwanSDK from '@loyalytics/swan-react-native-sdk';

const sdk = SwanSDK.getCurrentInstance();
await sdk?.flushEvents();
await Swan.flush();

6. Inspect queue + session

For diagnostics — verify the SDK is queueing correctly, or correlate a user session with a downstream event in your warehouse.

val queued: Int    = Swan.getQueueSize()
val session: String? = Swan.getCurrentSessionId()
val info             = Swan.getDeviceInfo()
// info.identifier, info.generatedCDID, info.currentCDID, ...
let queued  = Swan.shared.getQueueSize()
let session = Swan.shared.getCurrentSessionId()
let info    = Swan.shared.getDeviceInfo()
import SwanSDK from '@loyalytics/swan-react-native-sdk';

const sdk = SwanSDK.getCurrentInstance();
const queued = await sdk?.getQueueSize();
const info   = await sdk?.getDeviceInfo();
// info: { deviceId, generatedCDID, currentCDID, identifier?, subscribedAt?, ... }
const swanId = await sdk?.getSwanIdentifier();
// swanId = info.currentCDID (logged in) ?? info.generatedCDID (anonymous)

getSwanIdentifier() returns the SDK's current identifier — the currentCDID when identified, otherwise the anonymous generatedCDID. Returns undefined only if device registration hasn't completed yet.

const queued = await Swan.getQueueSize();
const info   = await Swan.getDeviceInfo();

Reference

On this page