useLoyalty
Widget

Configuration

All widget configuration options and member data

This reference covers all configuration options available when initializing the useLoyalty Widget.

Configuration Object

interface UseLoyaltyWidgetConfig {
  // Required - Authentication
  publicKey: string;
  externalId: string;
  timestamp: number;
  signature: string;

  // Optional - API
  apiUrl?: string;

  // Optional - Appearance
  theme?: WidgetTheme;
  language?: WidgetLanguage;

  // Optional - Member Data
  member?: MemberData;

  // Optional - Callbacks
  onReady?: () => void;
  onError?: (error: Error) => void;
  onWelcomeBonus?: (points: number) => void;
}

Required Parameters

publicKey

Your project's public API key (starts with pk_).

publicKey: "pk_live_abc123xyz";

externalId

The unique identifier for the member in your system.

externalId: "user_12345"; // Your user ID
externalId: "cust_abc123"; // Or customer ID
externalId: user.id; // Dynamic value

timestamp

Current Unix timestamp in milliseconds. Used for replay attack prevention.

timestamp: Date.now(); // Current time
timestamp: 1704067200000; // Specific timestamp

Timestamps older than 5 minutes are rejected. Always generate fresh timestamps.

signature

HMAC-SHA256 signature generated server-side.

signature: "a1b2c3d4e5f6..."; // 64-character hex string

Optional Parameters

apiUrl

Override the default API URL (useful for self-hosted instances).

apiUrl: "https://app.useloyalty.app"; // Default
apiUrl: "https://your-instance.com/api"; // Self-hosted

theme

Customize the widget appearance. See Theming for full details.

theme: {
  primaryColor: '#6366f1',
  backgroundColor: '#ffffff',
  textColor: '#1e293b',
  position: 'right'
}

language

Set the widget language. See Internationalization for details.

language: "en"; // English (default)
language: "es"; // Spanish
language: "fr"; // French
language: "de"; // German
language: "ja"; // Japanese
language: "zh-CN"; // Chinese (Simplified)

member

Provide member data to sync with the widget:

member: {
  email: 'user@example.com',
  name: 'John Doe',
  phone: '+1234567890',
  dateOfBirth: '1990-05-15',  // ISO date
  avatarUrl: 'https://example.com/avatar.jpg',
  metadata: {
    tier: 'gold',
    preferences: { newsletter: true }
  }
}

Member Data Object

interface MemberData {
  email?: string;
  name?: string;
  phone?: string;
  dateOfBirth?: string; // YYYY-MM-DD format
  avatarUrl?: string;
  metadata?: Record<string, unknown>;
}
FieldTypeDescription
emailstringMember's email address
namestringDisplay name
phonestringPhone number
dateOfBirthstringBirth date for birthday bonuses
avatarUrlstringProfile image URL
metadataobjectCustom key-value data

Callbacks

onReady

Called when the widget is fully loaded and ready.

onReady: () => {
  console.log("Widget ready");
  // Enable related UI elements
  document.querySelector("#loyalty-link").classList.remove("hidden");
};

onError

Called when an error occurs during initialization.

onError: (error) => {
  console.error("Widget error:", error.message);
  // Show fallback UI or retry
  if (error.message.includes("network")) {
    showRetryButton();
  }
};

onWelcomeBonus

Called when a new member receives their welcome bonus.

onWelcomeBonus: (points) => {
  // Show celebration
  showToast(`Welcome! You've earned ${points} points!`);
  // Track analytics
  analytics.track("welcome_bonus_received", { points });
};

Theme Object

interface WidgetTheme {
  primaryColor?: string;
  backgroundColor?: string;
  textColor?: string;
  fontFamily?: string;
  position?: "left" | "right";
  borderRadius?: string;
  hideQuests?: boolean;
  hidePromo?: boolean;
  hideBadges?: boolean;
  hideRefer?: boolean;
  launcher?: LauncherConfig;
}

interface LauncherConfig {
  displayMode?: "floating" | "custom";
  variant?: "icon-only" | "icon-text";
  icon?: "gift" | "star" | "coin" | "award";
  text?: string;
  size?: number;
  offset?: { x?: number; y?: number };
  pulse?: boolean;
}
OptionTypeDefaultDescription
primaryColorstring#6366f1Primary brand color
backgroundColorstring#ffffffWidget background
textColorstring#1e293bText color
fontFamilystringSystem fontsFont stack
positionstringrightLauncher position
borderRadiusstring16pxCorner radius
hideQuestsbooleanfalseHide quests tab
hidePromobooleanfalseHide promo input
hideBadgesbooleanfalseHide badges
hideReferbooleanfalseHide referral tab

Launcher Configuration

The launcher option controls how the widget trigger button appears and behaves.

Display Modes

ModeDescription
floatingShows a floating button (default)
customNo launcher button - use UseLoyaltyWidget.open() from your own UI

Launcher Options

OptionTypeDefaultDescription
displayModestringfloatingfloating or custom
variantstringicon-onlyicon-only or icon-text
iconstringgiftIcon: gift, star, coin, award
textstringRewardsText label (for icon-text variant)
sizenumber56Button size in pixels
offsetobject{x:24, y:24}Distance from screen edge
pulsebooleanfalseEnable attention-grabbing pulse animation

Floating Button Examples

// Default floating button
UseLoyaltyWidget.init({
  ...auth,
  theme: {
    launcher: {
      displayMode: "floating",
      variant: "icon-only",
      icon: "gift",
    },
  },
});

// Button with text label
UseLoyaltyWidget.init({
  ...auth,
  theme: {
    launcher: {
      displayMode: "floating",
      variant: "icon-text",
      icon: "star",
      text: "Earn Points",
      pulse: true, // Draws attention
    },
  },
});

Custom Trigger Mode

Hide the floating button and trigger the widget from your own UI:

// Initialize without visible launcher
UseLoyaltyWidget.init({
  ...auth,
  theme: {
    launcher: {
      displayMode: "custom",
    },
  },
});

// Trigger from your own button
document.querySelector("#my-rewards-btn").addEventListener("click", () => {
  UseLoyaltyWidget.open();
});

// Or toggle open/closed
document.querySelector("#toggle-btn").addEventListener("click", () => {
  UseLoyaltyWidget.toggle();
});

This is useful when you want to:

  • Add the trigger to your navigation menu
  • Use a custom-styled button
  • Open the widget based on user actions (e.g., after purchase)
  • Integrate with existing reward/loyalty UI elements

Full Example

UseLoyaltyWidget.init({
  // Authentication
  publicKey: "pk_live_abc123",
  externalId: user.id,
  timestamp: Date.now(),
  signature: authResponse.signature,

  // API
  apiUrl: "https://app.useloyalty.app",

  // Appearance
  theme: {
    primaryColor: "#2563eb",
    backgroundColor: "#ffffff",
    textColor: "#0f172a",
    fontFamily: "Inter, system-ui, sans-serif",
    position: "right",
    borderRadius: "12px",
    hidePromo: false,
    launcher: {
      size: 56,
      offset: { x: 20, y: 20 },
    },
  },

  // Language
  language: "en",

  // Member Data
  member: {
    email: user.email,
    name: user.name,
    avatarUrl: user.avatar,
    dateOfBirth: user.birthday,
    metadata: {
      plan: user.subscription,
      signupSource: "web",
    },
  },

  // Callbacks
  onReady: () => {
    console.log("useLoyalty widget ready");
    trackEvent("widget_loaded");
  },

  onError: (error) => {
    console.error("useLoyalty widget error:", error);
    reportError(error);
  },

  onWelcomeBonus: (points) => {
    showNotification(`Welcome! +${points} points`);
  },
});

Environment-Based Config

const config = {
  development: {
    apiUrl: "http://localhost:3000",
    publicKey: process.env.USELOYALTY_PUBLIC_KEY_DEV,
  },
  production: {
    apiUrl: "https://app.useloyalty.app",
    publicKey: process.env.USELOYALTY_PUBLIC_KEY_PROD,
  },
};

const env = process.env.NODE_ENV || "development";

UseLoyaltyWidget.init({
  ...config[env],
  externalId: user.id,
  timestamp: auth.timestamp,
  signature: auth.signature,
});

Feature Flags

Control widget features via theme options:

// Minimal widget - rewards only
UseLoyaltyWidget.init({
  ...auth,
  theme: {
    hideQuests: true,
    hideRefer: true,
    hideBadges: true,
    hidePromo: true,
  },
});

// Full featured widget
UseLoyaltyWidget.init({
  ...auth,
  theme: {
    hideQuests: false,
    hideRefer: false,
    hideBadges: false,
    hidePromo: false,
  },
});

On this page