AlgorithmX
Integrations7 min read

Customers, Events, and Navigation

Shared JavaScript integration for customers, events, custom actions, and campaign links.

SDK 1.1.0: these APIs use SDK-generated anonymous/device IDs and API-based in-app delivery. Existing 1.0.x integrations should follow the updated identity and profile instructions below.

These examples are shared by Expo and React Native apps. Complete your native setup first. Your app owns customer identity, business events, permissions, and navigation. No native implementation of each custom action or campaign link is needed.

Imagine a customer opens a product, adds it to the cart, and later taps a campaign to return to that product. Your app supplies the customer ID and those business events; the SDK delivers them to AlgorithmX and returns the campaign action to your router.

Start with one customer, one event, and one destination. Once that path works, add the rest of your agreed event and action names. Example names such as appRouter below mean your app's existing navigation code, which you supply.

Identify the customer

The SDK generates and stores an anonymous UUID and a separate installation device UUID during startup. You do not generate either ID or call the bootstrap endpoint yourself. The anonymous UUID stays the same across app restarts and login; events continue to use it in X-Anonymous-Id.

Use the stable account ID from your application's backend when the customer signs in. The SDK sends it as ExternalId, allowing AlgorithmX to resolve the same customer across devices. AlgorithmX manages its own internal profile ID.

Call the identity function after login and when starting with a signed-in customer. Email and phone become trusted identifiers; supported profile fields are sent separately to /Customer/Ingest.

ts
AlgorithmX.identify('customer_123', {
  email: '[email protected]',
  firstName: 'Amina', lastName: 'Hassan',
  emailOptIn: true, smsOptIn: false, pushOptIn: true,
  gdprAccepted: true, whatsAppOptIn: false,
});

Supported identifier fields are email, phone, and userName; your application's userId becomes ExternalId. Supported profile fields are firstName, lastName, gender, dateOfBirth, registeredAt, emailOptIn, smsOptIn, pushOptIn, gdprAccepted, and whatsAppOptIn. Send dates as ISO 8601 text and consent fields as booleans.

Send a complete profile. /Customer/Ingest replaces these traits: omitted text/date fields are cleared and omitted consent fields become false. Include all current values whenever you send profile fields through identify / identifyUser or setUserProfile. An identify call containing only identifiers does not send a profile update.

Fields such as plan, language, country, and loyaltyTier are not supported customer traits by these endpoints. The SDK rejects unsupported fields. Send arbitrary business data with trackEvent; that records event data and does not create custom profile fields.

To update profile fields later, pass profile, your application's complete current customer profile object, without email, phone, or userName:

ts
AlgorithmX.setUserProfile(profile);

On logout:

ts
AlgorithmX.resetIdentity();

Logout clears waiting campaigns, generates a fresh anonymous UUID and bootstraps a new anonymous profile. The installation's device UUID is retained. Calling identify with a different account ID also rotates the anonymous UUID first, preventing the two accounts from being merged. Close any campaign already on screen as part of your app's logout flow.

To inspect the SDK-generated UUID for diagnostics:

ts
const anonymousId = await AlgorithmX.getAnonymousId();

The SDK remembers the external account ID across restarts. These calls do not replace your application's authentication. API requests are sent in order, but the backend responds with 202 Accepted and processes messages asynchronously; confirm the stored customer data in AlgorithmX. Offline event/profile requests are dropped. Bootstrap and saved account identification are attempted again on startup/foreground; profile updates must be sent again by your app if delivery failed.

Check: the customer can be found using the external ID/email you supplied, and the anonymous UUID is unchanged after login. After logout or switching accounts, it changes.

Send business events

Send an event right after an action succeeds, for example after an order is confirmed. Put it next to your existing analytics calls.

ts
AlgorithmX.trackEvent('productView', { productId: 'SKU-123' });

AlgorithmX.trackEvent('addToCart', { productId: 'SKU-123', quantity: 2 });

AlgorithmX.trackEvent('purchase', {
  orderId: 'ORDER-1001',
  total: 149.9,
  currency: 'SAR',
  items: [{ productId: 'SKU-123', quantity: 2 }],
});

For example, send purchase after your checkout confirms success. Keep the event name and field names consistent with the list your campaign team uses.

Rules for events:

  • Event transport: general events use POST /api/v1/Event/Log, with the event name in eventType, properties in data, and an ISO 8601 UTC timestamp. The SDK sends an array and adds the required partner and anonymous-ID headers automatically. See the request contract.

  • Values: use text, numbers, true/false, arrays, and objects. Send dates as a timestamp or an ISO 8601 string.

  • Names and keys: use AlgorithmX's camelCase naming approach, such as addToCart and productId. Custom names and keys are sent as supplied; their casing is not enforced or normalized.

  • Offline: an event sent without internet is lost. It is not sent again later. Keep your own backend as the record of orders and payments.

Check: the event appears for the customer in AlgorithmX.

Route campaign actions

When a customer taps an AlgorithmX notification, the SDK sends an event to JavaScript. Your listeners open the screens. You write each supported route once; your campaign team can then use that route in many campaigns.

A tap can produce both a general notification-click callback and a specific action callback. Use the specific action to navigate, and use the general callback for logging or observation. Otherwise, the same tap can open a screen twice.

EventWhen it comesWhat to do
onDeepLinkThe campaign opens a screen with a link.Open the link with your router.
onCustomActionThe campaign runs a custom action.Open the screen for that action.
onActionButtonThe customer taps a notification button.Handle the button. The notification's main action does not run after it.
onNotificationClickEvery tap, for your information.Nothing. The SDK already runs the campaign's action, so do not navigate here too.

"Open a web page" and "open an in-app campaign" need no listener; the SDK does them.

ts
import AlgorithmX from '@algorithmxcloud/react-native-sdk';
import { appRouter } from './navigation/appRouter'; // Your existing navigation code.

AlgorithmX.addListener('onDeepLink', ({ url }) => appRouter.openUrl(url));

AlgorithmX.addListener('onCustomAction', ({ action, data }) => {
  const details = (data.parsedActionData ?? {}) as Record<string, unknown>;
  if (action === 'viewProduct' && typeof details.productId === 'string') {
    appRouter.openProduct(details.productId);
  } else if (action === 'viewCart') {
    appRouter.openCart();
  }
});

AlgorithmX.addListener('onActionButton', ({ actionText }) => {
  if (actionText === 'viewCart') appRouter.openCart();
});
  • Add all listeners together, at app start, before the first render, for example in a startup file imported by index.js. The native bridge keeps up to 50 early events. It flushes them when observation starts, so register every listener together before calling init(). Listeners added later, inside a screen, can miss them.
  • Wait for your navigation. When a tap starts the app, events come before your navigation is ready. Keep the destination and open it when it is ready. With React Navigation, that is when navigationRef.isReady() is true, or in onReady.
  • Match buttons on their action text, not their title, because the title can be translated. Handle every button your campaigns use; a button with no case does nothing.
  • You do not need new links or screens. Give your campaign team the links and action names your released app supports, for example myapp://open/product?id=SKU-123.
  • Keep your normal login and permission checks before sensitive screens: a campaign only suggests where to go.

Check: send a test notification for each link, action, and button your app supports. The right screen opens once.

Try a notification while the app is already open, then one that launches the app. The second test checks that a destination waits for navigation instead of disappearing before your first screen mounts.

Start once, before rendering

After registering the listeners above, connect to native startup inside your app’s async startup function:

ts
await AlgorithmX.init();
AlgorithmX.setLoggingEnabled(__DEV__);

Call SDK methods after initialization succeeds. Keep startup outside screen components, and handle a failed initialization in your app. Logging helps during development; avoid enabling it in release builds. Calls that register tokens, identify customers, or track events do not confirm network delivery.

Your appRouter is app-owned. It must queue destinations until navigation is ready. An external URL that launches the app from a browser also needs your normal Android intent filters and iOS URL schemes or associated domains; an SDK campaign callback does not configure these.

Next: test the integration.