LogoStacked
Client SDK

Configuration

Complete configuration reference for the Client SDK

The Client SDK is highly configurable to fit various integration scenarios. This page documents all available configuration options.


Configuration Interface

Prop

Type

Prop

Type


Required Options

env

The environment to connect to:

  • test (recommended for development) - https://api.sandbox.pixels.xyz
  • live (production) - https://api.pixels.xyz
// Development
const client = new OfferwallClient({
  env: 'test',
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/default-reward.png'
});

// Production
const client = new OfferwallClient({
  env: 'live',
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/default-reward.png'
});
// Development
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/default-reward.png"
});

// Production
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "live",
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/default-reward.png"
});

Environment Recommendation

Always use test environment during development and live for production.


tokenProvider

Required: Yes

A function that returns a JWT token for authenticating with the Stacked API. This token should be generated server-side using the Analytics SDK.

const client = new OfferwallClient({
  env: 'test',
  tokenProvider: async () => {
    const response = await fetch('/api/stacked-token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
    });
    const data = await response.json();
    return data.token;
  },
  fallbackRewardImage: '/default-reward.png'
});
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    TokenProvider = async () =>
    {
        var httpClient = new HttpClient();
        var response = await httpClient.PostAsync(
            "https://your-server.com/api/stacked-token",
            null
        );
        var json = await response.Content.ReadAsStringAsync();
        var tokenData = JsonSerializer.Deserialize<TokenResponse>(json);
        return tokenData.Token;
    },
    FallbackRewardImage = "/default-reward.png"
});

Security Warning

Never hardcode JWT tokens or API keys in client-side code. Always fetch tokens from a secure server endpoint.

The SDK will automatically call this function:

  • On initial connection
  • When the current token expires (less than 1 minute remaining)
  • When a token validation error occurs

fallbackRewardImage

Required: Yes

The default image URL to use for rewards that don't have an image specified. This ensures all rewards can be displayed visually.

const client = new OfferwallClient({
  env: 'test',
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/images/default-reward.png'
});

// or use a CDN URL
const client = new OfferwallClient({
  env: 'test',
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: 'https://cdn.example.com/rewards/default.png'
});
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/images/default-reward.png"
});

// or use a CDN URL
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "https://cdn.example.com/rewards/default.png"
});

Optional Connection Options

autoConnect

Default: false

Whether to automatically connect when the client is instantiated. If false, you must manually call initialize() or InitializeAsync().

// Auto-connect on creation
const client = new OfferwallClient({
  env: 'test',
  autoConnect: true,
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/default-reward.png'
});
// Client is connecting automatically

// Manual connection
const client = new OfferwallClient({
  env: 'test',
  autoConnect: false, // or omit this option
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/default-reward.png'
});
await client.initialize(); // Connect manually
// Auto-connect on creation
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    AutoConnect = true,
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/default-reward.png"
});
// Client is connecting automatically

// Manual connection
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    AutoConnect = false, // or omit this option
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/default-reward.png"
});
await client.InitializeAsync(); // Connect manually

When to Use Auto-Connect

Use autoConnect: true when you want the SDK to connect immediately on page load. Use false when you want to control when the connection happens (e.g., after user login).


reconnect

Default: true

Whether to automatically reconnect if the connection is lost.

const client = new OfferwallClient({
  env: 'test',
  reconnect: true, // Enable auto-reconnection
  reconnectDelay: 1000,
  maxReconnectAttempts: 5,
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/default-reward.png'
});
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    Reconnect = true, // Enable auto-reconnection
    ReconnectDelay = 1000,
    MaxReconnectAttempts = 5,
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/default-reward.png"
});

When enabled, the SDK will:

  1. Detect connection loss
  2. Wait for reconnectDelay milliseconds
  3. Attempt to reconnect
  4. Use exponential backoff for subsequent attempts (2x delay each time)
  5. Give up after maxReconnectAttempts attempts

reconnectDelay

Default: 1000 (1 second)

The initial delay (in milliseconds) before attempting to reconnect after a disconnection. Each subsequent attempt uses exponential backoff (delay × 2).

const client = new OfferwallClient({
  env: 'test',
  reconnectDelay: 2000, // Wait 2 seconds before first reconnection attempt
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/default-reward.png'
});

// Reconnection timeline:
// 1st attempt: 2000ms (2s)
// 2nd attempt: 4000ms (4s)
// 3rd attempt: 8000ms (8s)
// 4th attempt: 16000ms (16s)
// 5th attempt: 32000ms (32s)
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    ReconnectDelay = 2000, // Wait 2 seconds before first reconnection attempt
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/default-reward.png"
});

// Reconnection timeline:
// 1st attempt: 2000ms (2s)
// 2nd attempt: 4000ms (4s)
// 3rd attempt: 8000ms (8s)
// 4th attempt: 16000ms (16s)
// 5th attempt: 32000ms (32s)

Server-Suggested Retry Time

The server can suggest a custom retry time via SSE. When provided, this overrides the reconnectDelay configuration.


maxReconnectAttempts

Default: 5

The maximum number of reconnection attempts before giving up.

const client = new OfferwallClient({
  env: 'test',
  maxReconnectAttempts: 10, // Try up to 10 times
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/default-reward.png'
});
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    MaxReconnectAttempts = 10, // Try up to 10 times
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/default-reward.png"
});

After reaching the maximum attempts, the client will emit a disconnected event with reason: 'max_reconnect_attempts'.


debug

Default: false

Enable debug logging to the console. Useful for development and troubleshooting.

const client = new OfferwallClient({
  env: 'test',
  debug: true, // Enable debug logs
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/default-reward.png'
});

When enabled, you'll see logs like:

[OfferwallClient] Connecting to SSE endpoint...
[SSEConnection] Connection opened
[OfferStore] Set 5 offers
[EventEmitter] Event emitted: refresh
var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    Debug = true, // Enable debug logs
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/default-reward.png"
});

When enabled, you'll see logs like:

[OfferwallClient] Connecting to SSE endpoint...
[SSEConnection] Connection opened
[OfferStore] Set 5 offers
[EventEmitter] Event emitted: refresh

Production Warning

Disable debug logging in production to avoid exposing internal state and improve performance.


Optional Advanced Options

hooks

Default: {}

Lifecycle hooks for custom logic at various points in the SDK lifecycle.

Interface:

Prop

Type

Example:

const client = new OfferwallClient({
  env: 'test',
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/default-reward.png',
  hooks: {
    beforeConnect: async ({ jwt, endpoint }) => {
      console.log('About to connect to:', endpoint);
    },
    afterOfferClaim: async (offer, rewards) => {
      console.log('Claimed rewards:', rewards);
      showRewardAnimation(rewards);
    },
    onOfferSurfaced: (offer) => {
      // Return true to emit event, false to suppress
      return offer.priority <= 5;
    },
    onError: (error, context) => {
      console.error(`Error in ${context}:`, error);
      reportErrorToAnalytics(error);
    }
  }
});

Interface:

Prop

Type

Related Types:

public class ConnectionInfo
{
    public string Jwt { get; set; }
    public string Endpoint { get; set; }
}

Example:

var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/default-reward.png",
    Hooks = new OfferwallHooks
    {
        BeforeConnect = async (config) =>
        {
            Console.WriteLine($"About to connect to: {config.Endpoint}");
        },
        AfterOfferClaim = async (offer, rewards) =>
        {
            Console.WriteLine($"Claimed rewards: {rewards.Count}");
            ShowRewardAnimation(rewards);
        },
        OnOfferSurfaced = (offer) =>
        {
            // Return true to emit event, false to suppress
            return offer.Priority <= 5;
        },
        OnError = (error, context) =>
        {
            Console.WriteLine($"Error in {context}: {error.Message}");
            ReportErrorToAnalytics(error);
        }
    }
});

assetResolver

Default: undefined

A custom function to resolve reward assets (names and images) based on your game's data. This allows you to map reward IDs to your game's asset library.

Type:

type AssetResolver = (identifier: RewardIdentifier) => AssetContent | undefined | null;

interface RewardIdentifier {
  rewardId?: string; // Your game's asset ID
  kind: 'item' | 'coins' | 'exp' | 'trust_points' | 'loyalty_currency';
}

interface AssetContent {
  name?: string;
  image?: string;
}

Example:

const gameAssets = {
  'gold': { name: 'Gold Coins', image: '/assets/gold.png' },
  'gems': { name: 'Precious Gems', image: '/assets/gems.png' },
  'sword_iron': { name: 'Iron Sword', image: '/assets/weapons/iron-sword.png' },
  'potion_health': { name: 'Health Potion', image: '/assets/potions/health.png' },
};

const client = new OfferwallClient({
  env: 'test',
  tokenProvider: async () => { /* ... */ },
  fallbackRewardImage: '/assets/default-reward.png',
  assetResolver: (identifier) => {
    // identifier.rewardId contains the ID from the offer
    const asset = gameAssets[identifier.rewardId || ''];

    if (asset) {
      return {
        name: asset.name,
        image: asset.image,
      };
    }

    // Return null to use fallback
    return null;
  }
});

Type:

TypeDescription
Func<RewardIdentifier, AssetContent?>?Function that receives reward identifier and returns custom asset content

Related Types:

public class RewardIdentifier
{
    public string? RewardId { get; set; }  // Your game's asset ID
    public string Kind { get; set; }       // "item", "coins", "exp", "trust_points", "loyalty_currency"
}

public class AssetContent
{
    public string? Name { get; set; }
    public string? Image { get; set; }
}

Example:

var gameAssets = new Dictionary<string, AssetContent>
{
    ["gold"] = new AssetContent { Name = "Gold Coins", Image = "/assets/gold.png" },
    ["gems"] = new AssetContent { Name = "Precious Gems", Image = "/assets/gems.png" },
    ["sword_iron"] = new AssetContent { Name = "Iron Sword", Image = "/assets/weapons/iron-sword.png" },
    ["potion_health"] = new AssetContent { Name = "Health Potion", Image = "/assets/potions/health.png" }
};

var client = new OfferwallClient(new OfferwallConfig
{
    Env = "test",
    TokenProvider = async () => { /* ... */ },
    FallbackRewardImage = "/assets/default-reward.png",
    AssetResolver = (identifier) =>
    {
        // identifier.RewardId contains the ID from the offer
        if (gameAssets.TryGetValue(identifier.RewardId ?? "", out var asset))
        {
            return asset;
        }

        // Return null to use fallback
        return null;
    }
});

If your resolver returns:

  • { name, image } - Uses your custom assets
  • null or undefined - Falls back to default name and fallbackRewardImage