LogoStacked
Analytics SDK

Getting Started

Complete tutorial for integrating the Analytics SDK into your server

This guide will walk you through integrating the Stacked Analytics SDK into your server application from installation to tracking your first event.


Installation

Install the SDK via npm:

npm install @pixels-online/pixels-analytics-node-sdk

Install the SDK via Go modules:

go get github.com/pixels-online/pixels-analytics-go-sdk

Step-by-Step Integration

Initialize the SDK

Initialize the Analytics SDK using your credentials from the dashboard.

Single Instance

You should have a single instance of the SDK in your server application, for example in a services/analytics file.

import PixelsAnalytics from "@pixels-online/pixels-analytics-node-sdk";

const analytics = new PixelsAnalytics({
  apiKey: process.env.PIXELS_API_KEY!,
  clientId: process.env.PIXELS_CLIENT_ID!,
  env: "test", // 'test' | 'live' | 'staging' | 'dev'
});

export default analytics;
package main

import (
    "context"
    "log"
    "os"

    pixels "github.com/pixels-online/pixels-analytics-go-sdk"
)

func main() {
    config := pixels.Config{
        APIKey:   os.Getenv("PIXELS_API_KEY"),
        ClientID: os.Getenv("PIXELS_CLIENT_ID"),
        Env:      "test", // "test" or "live"
    }

    analytics, err := pixels.New(config)
    if err != nil {
        log.Fatalf("Failed to create analytics client: %v", err)
    }
    defer analytics.Close() // Ensure graceful shutdown

    ctx := context.Background()

    // Use analytics...
}

Environment Recommendation

Always use test environment during development and live for production.

Track Your First Event

Track a player sign-in event:

// Track player sign-in
analytics.signIn("player-123", {
  username: "CoolPlayer",
  extra: { platform: "steam" },
});
// Track player sign-in
err := analytics.SignIn(ctx, "player-123", pixels.SignInParams{
    Username: stringPtr("CoolPlayer"),
    Extra: map[string]interface{}{
        "platform": "steam",
    },
})
if err != nil {
    log.Printf("Error tracking sign-in: %v", err)
}

// Helper function for optional strings
func stringPtr(s string) *string {
    return &s
}

Automatic Batching

Events are automatically batched and sent to the server. You don't need to manually flush unless you want immediate sending.

Track Currency Transactions

Track when players earn or spend currency:

// Track currency transaction
const txId = analytics.spendCurrency("player-123", {
  currency_id: "gold",
  currency_amount: 100,
  context: "weapon_upgrade",
  to_kind: "store",
  to_id: "blacksmith",
});

console.log("Transaction ID:", txId);
// Track currency transaction
txID, err := analytics.SpendCurrency(ctx, "player-123", pixels.SpendCurrencyParams{
    CurrencyID:     "gold",
    CurrencyAmount: 100.0,
    Context:        stringPtr("weapon_upgrade"),
    ToKind:         stringPtr("store"),
    ToID:           stringPtr("blacksmith"),
})
if err != nil {
    log.Printf("Error tracking currency spend: %v", err)
} else {
    log.Printf("Transaction ID: %s", txID)
}

Track Item Gains

Track when players gain items, optionally linking to a currency transaction:

// Track item gained (linked to currency transaction)
analytics.gainItem("player-123", {
  item_id: "legendary_sword",
  item_amount: 1,
  tx_id: txId, // Link to previous transaction
  context: "weapon_upgrade",
});
// Track item gained (linked to currency transaction)
err = analytics.GainItem(ctx, "player-123", pixels.GainItemParams{
    ItemID:     "legendary_sword",
    ItemAmount: 1,
    TxID:       stringPtr(txID), // Link to previous transaction
    Context:    stringPtr("weapon_upgrade"),
})
if err != nil {
    log.Printf("Error tracking item gain: %v", err)
}

Track Player Snapshots

Send a complete snapshot of the player's current state. This is crucial for offer targeting.

analytics.playerSnapshot("player-123", {
  username: "CoolPlayer",
  trust_score: 85,
  currencies: [
    { id: "gold", balance: 1500, in: 5000, out: 3500 },
    { id: "gems", balance: 50 },
  ],
  levels: [
    { skill_id: "combat", level_value: 15 },
    { skill_id: "crafting", level_value: 10 },
  ],
  achievements: [
    { id: "first_boss", count: 1 },
    { id: "pvp_wins", count: 25 },
  ],
  extra: {
    guild_id: "warriors_123",
    premium_member: true,
  },
});
trustScore := 85
err = analytics.PlayerSnapshot(ctx, "player-123", pixels.SnapshotParams{
    Username:   stringPtr("CoolPlayer"),
    TrustScore: &trustScore,
    Currencies: []pixels.CurrencySnapshot{
        {ID: "gold", Balance: 1500, In: floatPtr(5000.0), Out: floatPtr(3500.0)},
        {ID: "gems", Balance: 50},
    },
    Levels: []pixels.LevelSnapshot{
        {SkillID: "combat", LevelValue: 15},
        {SkillID: "crafting", LevelValue: 10},
    },
    Achievements: []pixels.AchievementSnapshot{
        {ID: "first_boss", Count: intPtr(1)},
        {ID: "pvp_wins", Count: intPtr(25)},
    },
    Extra: map[string]interface{}{
        "guild_id":       "warriors_123",
        "premium_member": true,
    },
})
if err != nil {
    log.Printf("Error tracking snapshot: %v", err)
}

// Helper functions for optional parameters
func intPtr(i int) *int {
    return &i
}

func floatPtr(f float64) *float64 {
    return &f
}

Best Practice

Send player snapshots regularly (e.g., on login, after significant changes) to keep Stacked's user profiles up-to-date.

Create JWT Endpoint for Client SDKs

If you're using the Client SDK, create an endpoint to generate JWT tokens:

// Express endpoint example
app.post('/api/stacked-token', async (req, res) => {
  const playerId = req.user.id; // Your user ID from session/auth

  try {
    const token = await analytics.signJwt({ playerId });
    res.json({ token });
  } catch (error) {
    res.status(500).json({ error: 'Failed to generate token' });
  }
});
// HTTP handler example
func stackedTokenHandler(w http.ResponseWriter, r *http.Request) {
    playerID := getPlayerIDFromSession(r) // Your auth logic

    token, err := analytics.SignJwt(r.Context(), playerID)
    if err != nil {
        http.Error(w, "Failed to generate token", http.StatusInternalServerError)
        return
    }

    json.NewEncoder(w).Encode(map[string]string{
        "token": token,
    })
}

Security Warning

Never expose API keys in client-side code. Always generate JWT tokens server-side using the Analytics SDK.


Next Steps

Now that you have the SDK integrated, explore:


Common Patterns

Login Flow

// 1. User signs in
analytics.signIn("player-123", {
  username: "CoolPlayer",
});

// 2. Send current snapshot
analytics.playerSnapshot("player-123", {
  // ... current user state
});
// 1. User signs in
err := analytics.SignIn(ctx, "player-123", pixels.SignInParams{
    Username: stringPtr("CoolPlayer"),
})

// 2. Send current snapshot
err = analytics.PlayerSnapshot(ctx, "player-123", pixels.SnapshotParams{
    // ... current user state
})

Purchase Flow

// 1. User spends currency
const txId = analytics.spendCurrency("player-123", {
  currency_id: "gold",
  currency_amount: 100,
  context: "item_purchase",
});

// 2. User gains item
analytics.gainItem("player-123", {
  item_id: "sword_01",
  item_amount: 1,
  tx_id: txId, // Link to currency transaction
  context: "item_purchase",
});
// 1. User spends currency
txID, err := analytics.SpendCurrency(ctx, "player-123", pixels.SpendCurrencyParams{
    CurrencyID:     "gold",
    CurrencyAmount: 100.0,
    Context:        stringPtr("item_purchase"),
})

// 2. User gains item
err = analytics.GainItem(ctx, "player-123", pixels.GainItemParams{
    ItemID:     "sword_01",
    ItemAmount: 1,
    TxID:       stringPtr(txID), // Link to currency transaction
    Context:    stringPtr("item_purchase"),
})