npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@datra/engage-sdk

v0.2.0

Published

Official JavaScript and TypeScript SDK for Datra Engage in-app messages, promotions, coupons, and customer engagement tracking.

Readme

Datra Engage SDK helps web apps, mobile apps, React Native apps and embedded client experiences show personalized in-app messages powered by Datra.

Use it when marketing and product teams need to show the right message to the right customer at the right moment without hardcoding every campaign into the application.

Datra Engage is part of the Datra Customer Engagement Platform.

Links


What is Datra Engage?

Datra Engage is the delivery layer between your app and Datra.

It helps your application receive and render:

  • banners
  • popups
  • coupon cards
  • bottom sheets
  • stories
  • in-app messages linked to push campaigns
  • personalized campaign messages
  • gamification entry points

Your app keeps full control over the UI.

Datra decides what should be shown.
Your app decides how it should look.


Supported message types

The SDK supports the same message types as Datra Engage API:

| Type | Typical use | | --- | --- | | BANNER | Home screen promo, category offer, campaign strip | | POPUP | Important one-time offer or announcement | | BOTTOM_SHEET | Cart, checkout or coupon reminder | | COUPON_CARD | Active coupon, gift or personal offer | | INLINE_BLOCK | Embedded block inside profile, checkout or loyalty screens | | CAROUSEL | Multiple offers in one placement | | STORY | Story-like marketing or gamification entry point |


What this SDK does

The SDK can:

  • identify a customer
  • resolve messages for a screen or placement
  • send screen view events
  • track message impressions
  • track clicks
  • track dismiss events
  • track conversions
  • work safely in non-blocking UI flows
  • retry temporary failed requests
  • queue failed tracking events
  • deduplicate UI tracking events

What this SDK does not do

For security reasons, this SDK does not:

  • apply promotions
  • redeem loyalty points
  • create orders
  • change customer balances
  • mutate customer data
  • confirm discounts
  • validate final checkout logic

All sensitive operations must happen on your backend through Datra Core.

Frontend shows the offer.
Backend confirms the offer.


Installation

npm install @datra/engage-sdk

Quick Start

import { DatraEngage } from "@datra/engage-sdk";

const engage = new DatraEngage({
  baseUrl: "https://api.datra.uz",
  publicKey: "pk_live_xxx",
  customerExternalId: "customer_123",
  platform: "ios",
  appVersion: "1.5.0",
  locale: "ru",
  defaultContext: {
    branchExternalId: "branch_1",
  },
});

const { messages } = await engage.screenViewed("home", {
  placement: "home_top_banner",
  context: {
    cartTotal: 120000,
  },
});

await engage.trackShown(messages, {
  idempotencyKeyPrefix: "home",
});

Basic Concept

Datra Engage works around three ideas:

1. Screen

Where the customer is now.

Examples:

"home"
"cart"
"checkout"
"profile"
"order_status"

2. Placement

The exact place where a message can appear.

Examples:

"home_top_banner"
"cart_bottom_sheet"
"checkout_coupon_card"
"profile_reward_block"

3. Message

The campaign content returned by Datra.

Examples:

"BANNER"
"POPUP"
"COUPON_CARD"
"BOTTOM_SHEET"
"STORY"

Render Messages

Datra Engage returns structured data.
Your app renders it using your own native components.

for (const message of messages) {
  if (message.type === "BANNER") {
    renderBanner({
      title: message.title,
      body: message.body,
      imageUrl: message.imageUrl,
      cta: message.cta,
      onPress: async () => {
        await engage.messageClickedSafe(message.decisionId);
        handleDatraAction(message.action);
      },
    });
  }
}

Example message:

{
  "decisionId": "decision_123",
  "type": "BANNER",
  "title": "Получите подарок",
  "body": "Сделайте заказ от 100 000 сум и получите напиток бесплатно",
  "imageUrl": "https://cdn.datra.uz/campaigns/free-drink.png",
  "cta": {
    "text": "Заказать"
  },
  "action": {
    "type": "OPEN_PROMOTION",
    "promotionId": "promotion_123"
  }
}

Tracking

Tracking helps Datra measure campaign performance.

You can track:

  • shown
  • clicked
  • dismissed
  • converted

Strict tracking

Use strict tracking when your app needs to know about failures.

await engage.messageClicked("decision_id", {
  idempotencyKey: "click-event-id",
});

await engage.messageDismissed("decision_id");

await engage.messageConverted("decision_id", {
  metadata: {
    orderExternalId: "order_123",
  },
});

Safe tracking

Use safe tracking for non-blocking UI events.

Safe methods never throw.

await engage.messageShownSafe("decision_id");
await engage.messageClickedSafe("decision_id");
await engage.messageDismissedSafe("decision_id");

Safe methods return:

{
  accepted: boolean;
  response?: unknown;
  error?: unknown;
  queued?: boolean;
  deduped?: boolean;
}

Action Contract

Messages can include an action object. The SDK does not execute actions automatically because each app owns its navigation.

Recommended action types:

"OPEN_SCREEN"
"OPEN_PROMOTION"
"OPEN_COUPON"
"OPEN_PRODUCT"
"OPEN_CART"
"OPEN_URL"
"OPEN_STORY"
"OPEN_MECHANIC"

Use the action handler helper to keep app navigation consistent:

import { createDatraEngageActionHandler } from "@datra/engage-sdk";

const handleDatraAction = createDatraEngageActionHandler({
  onOpenPromotion: async (promotionId) => {
    navigation.navigate("Promotion", { promotionId });
  },
  onOpenCoupon: async (couponId) => {
    navigation.navigate("Coupon", { couponId });
  },
  onOpenCart: async () => {
    navigation.navigate("Cart");
  },
  onUnhandledAction: async (action) => {
    console.warn("Unhandled Datra action", action);
  },
});

Offline Queue and Dedupe

Safe tracking can queue temporary failures and flush them later.

import { DatraEngage, createWebStorageAdapter } from "@datra/engage-sdk";

const storage = createWebStorageAdapter(window.localStorage, "my-app:");

const engage = new DatraEngage({
  baseUrl: "https://api.datra.uz",
  publicKey: "pk_live_xxx",
  eventQueue: {
    enabled: true,
    storage,
  },
  dedupe: {
    enabled: true,
    storage,
  },
});

await engage.flushEventQueue();
await engage.messageShownSafe("decision_id");

For React Native, pass an adapter backed by your storage library, for example AsyncStorage:

const asyncStorageAdapter = {
  getItem: (key: string) => AsyncStorage.getItem(key),
  setItem: (key: string, value: string) => AsyncStorage.setItem(key, value),
  removeItem: (key: string) => AsyncStorage.removeItem(key),
};

Dedupe is enabled by default for safe tracking. Event queue is opt-in so apps can choose where queued events are stored.


Identity Updates

Use identify when the active customer changes.

identify updates the SDK identity locally and uses it for subsequent resolve and tracking calls.

engage.identify({
  customerExternalId: "customer_456",
  platform: "android",
  appVersion: "1.6.0",
  context: {
    branchExternalId: "branch_2",
  },
});

React Native and Expo

import { DatraEngage } from "@datra/engage-sdk";
import { DatraEngageProvider, useEngageMessages } from "@datra/engage-sdk/react";

const engage = new DatraEngage({
  baseUrl: "https://api.datra.uz",
  publicKey: "pk_live_xxx",
  platform: "ios",
  appVersion: "1.5.0",
});

export function App() {
  return (
    <DatraEngageProvider client={engage}>
      <HomeScreen customerExternalId="customer_123" />
    </DatraEngageProvider>
  );
}

function HomeScreen({ customerExternalId }: { customerExternalId: string }) {
  const { messages, isLoading, refresh } = useEngageMessages("home", {
    placement: "home_top_banner",
    customerExternalId,
    trackShown: {
      idempotencyKeyPrefix: `home:${customerExternalId}`,
    },
  });

  if (isLoading || messages.length === 0) {
    return null;
  }

  return renderInAppMessage(messages[0], { refresh });
}

React is an optional peer dependency. The core SDK does not import React unless you use @datra/engage-sdk/react.

More examples:

  • examples/react-native-home-screen.tsx
  • examples/web-home.ts
  • examples/hoty-dogy-action-handler.ts

Example Flow

A customer opens the app.

const { messages } = await engage.screenViewed("home");

Datra returns a personalized campaign.

renderInAppMessage(messages[0]);

The app tracks that it was shown.

await engage.messageShownSafe(messages[0].decisionId);

The customer clicks the message.

await engage.messageClickedSafe(messages[0].decisionId);

The app opens the offer, product, coupon or checkout screen.

handleDatraAction(messages[0].action);

The backend confirms the promotion through Datra Core.


Recommended Integration Pattern

Datra Engage should be non-blocking.

If Datra Engage is unavailable, your app should continue working normally.

Recommended behavior:

  • app opens normally
  • catalog works normally
  • cart works normally
  • checkout works normally
  • only marketing messages are hidden

Example:

try {
  const { messages } = await engage.screenViewed("home");
  showMessages(messages);
} catch {
  showMessages([]);
}

Timeout and Retry

Requests time out after 5 seconds by default and retry once on temporary failures.

const engage = new DatraEngage({
  baseUrl: "https://api.datra.uz",
  publicKey: "pk_live_xxx",
  timeoutMs: 3000,
  retry: {
    retries: 2,
    retryDelayMs: 200,
    maxRetryDelayMs: 1000,
  },
  onError: (error, context) => {
    console.warn("Datra Engage request failed", {
      path: context.path,
      attempt: context.attempt,
      retryable: context.retryable,
      error,
    });
  },
});

Disable retries:

const engage = new DatraEngage({
  baseUrl: "https://api.datra.uz",
  publicKey: "pk_live_xxx",
  retry: 0,
});

API Contract

The SDK calls:

POST /api/v1/engage/messages/resolve
POST /api/v1/engage/events

Authorization uses the public SDK key:

x-datra-public-key: pk_live_xxx

By default, the SDK adds /api/v1 to baseUrl. You can override this with apiPrefix.


Security Model

Use a public SDK key in frontend applications.

publicKey: "pk_live_xxx"

Never use a secret key inside a mobile app or browser.

Sensitive actions must be handled by your backend:

  • order creation
  • promotion application
  • coupon redemption
  • loyalty point redemption
  • bonus balance changes

Package Scripts

npm run build
npm run typecheck
npm test

Brand Principle

Datra Engage is not just a message delivery SDK.

It is a bridge between customer data and real customer action.

Use it to turn app screens into personalized engagement moments.