Getting Started
Complete tutorial for integrating the Client SDK into your application
This guide will walk you through integrating the Stacked Client SDK into your application from installation to claiming your first offer.
Installation
Install the SDK via npm:
npm install @pixels-online/pixels-client-js-sdkdotnet add package PixelsOnline.Client.SDKStep-by-Step Integration
Create a Token Provider Endpoint
The Client SDK requires a JWT token to authenticate with the Stacked API. You must create a server endpoint that generates this token using the Analytics SDK.
Security
Never expose your API key or client ID in client-side code. Always generate JWTs server-side using the Analytics SDK.
Server-side example:
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',
});
// 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' });
}
});Initialize the Client
Create and configure the OfferwallClient in your application:
import { OfferwallClient } from '@pixels-online/pixels-client-js-sdk';
const offerwallClient = new OfferwallClient({
env: 'test', // Use 'live' for production
// Token provider - fetches JWT from your server
tokenProvider: async () => {
const response = await fetch('/api/stacked-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
});
const data = await response.json();
return data.token;
},
// Fallback image for rewards without images
fallbackRewardImage: '/images/default-reward.png',
});using PixelsOnline.Client.SDK;
var offerwallClient = new OfferwallClient(new OfferwallConfig
{
Env = "test", // Use "live" for production
// Token provider - fetches JWT from your server
TokenProvider = async () =>
{
var response = await httpClient.PostAsync("/api/stacked-token", null);
var data = await response.Content.ReadFromJsonAsync<TokenResponse>();
return data.Token;
},
// Fallback image for rewards without images
FallbackRewardImage = "/images/default-reward.png",
});Connect to the Offerwall
If you didn't set autoConnect: true, manually initialize the connection:
try {
await offerwallClient.initialize();
console.log('Connected to Stacked!');
} catch (error) {
console.error('Failed to connect:', error);
}try
{
await offerwallClient.InitializeAsync();
Console.WriteLine("Connected to Stacked!");
}
catch (Exception ex)
{
Console.WriteLine($"Failed to connect: {ex.Message}");
}This method does three things:
- Fetches the JWT token using your
tokenProvider - Retrieves initial offers and player data
- Establishes SSE connection for real-time updates
Listen for Events
Subscribe to connection and offer events to update your UI:
// Listen for initial offers and refresh events
offerwallClient.events.on('refresh', ({ offers, player }) => {
console.log('Received offers:', offers);
console.log('Player data:', player);
// Update your UI
displayOffersInUI(offers);
updatePlayerStats(player);
});
// Listen for new offers appearing in real-time
offerwallClient.events.on('offer_surfaced', ({ offer }) => {
console.log('New offer surfaced:', offer);
showOfferNotification(offer);
});
// Listen for connection events
offerwallClient.events.on('connected', ({ timestamp }) => {
console.log('Connected at:', timestamp);
showConnectionStatus('online');
});
offerwallClient.events.on('disconnected', ({ reason }) => {
console.log('Disconnected:', reason);
showConnectionStatus('offline');
});// Listen for initial offers and refresh events
offerwallClient.Events.On<RefreshEventData>("refresh", (data) =>
{
Console.WriteLine($"Received {data.Offers.Length} offers");
Console.WriteLine($"Player ID: {data.Player.Data.PlayerId}");
// Update your UI
DisplayOffersInUI(data.Offers);
UpdatePlayerStats(data.Player);
});
// Listen for new offers appearing in real-time
offerwallClient.Events.On<OfferSurfacedEventData>("offer_surfaced", (data) =>
{
Console.WriteLine($"New offer surfaced: {data.Offer.Name}");
ShowOfferNotification(data.Offer);
});
// Listen for connection events
offerwallClient.Events.On<ConnectedEventData>("connected", (data) =>
{
Console.WriteLine($"Connected at: {data.Timestamp}");
ShowConnectionStatus("online");
});
offerwallClient.Events.On<DisconnectedEventData>("disconnected", (data) =>
{
Console.WriteLine($"Disconnected: {data.Reason}");
ShowConnectionStatus("offline");
});Event Types
See the Events documentation for a complete list of all available events.
Access Offers
Access the current offers from the store:
// Get all offers
const allOffers = offerwallClient.getOffers();
// Filter by status (via store)
const claimableOffers = offerwallClient.store.getClaimableOffers();
const activeOffers = offerwallClient.store.getActiveOffers();
// Get specific offer
const offer = offerwallClient.store.getOffer('instance-id');// Get all offers
var allOffers = offerwallClient.GetOffers();
// Filter by status (via Store)
var claimableOffers = offerwallClient.Store.GetClaimableOffers();
var activeOffers = offerwallClient.Store.GetActiveOffers();
// Get specific offer
var offer = offerwallClient.Store.GetOffer("instance-id");Claim Rewards
When a player completes an offer, claim the rewards:
async function claimOffer(instanceId) {
const offer = offerwallClient.store.getOffer(instanceId);
if (!offer) {
console.error('Offer not found');
return;
}
if (offer.status !== 'claimable') {
console.error('Offer is not claimable yet. Status:', offer.status);
return;
}
try {
await offerwallClient.claimReward(instanceId);
console.log('Rewards claimed successfully!');
showSuccessMessage(`You claimed ${offer.rewards.length} rewards!`);
} catch (error) {
console.error('Failed to claim rewards:', error);
showErrorMessage('Failed to claim rewards');
}
}
// Listen for claim events
offerwallClient.events.on('offer_claimed', ({ instanceId }) => {
console.log('Offer claimed:', instanceId);
// Update UI to reflect claimed offer
});async Task ClaimOffer(string instanceId)
{
var offer = offerwallClient.Store.GetOffer(instanceId);
if (offer == null)
{
Console.WriteLine("Offer not found");
return;
}
if (offer.Status != "claimable")
{
Console.WriteLine($"Offer is not claimable yet. Status: {offer.Status}");
return;
}
try
{
await offerwallClient.ClaimRewardAsync(instanceId);
Console.WriteLine("Rewards claimed successfully!");
ShowSuccessMessage($"You claimed {offer.Rewards.Count} rewards!");
}
catch (Exception ex)
{
Console.WriteLine($"Failed to claim rewards: {ex.Message}");
ShowErrorMessage("Failed to claim rewards");
}
}
// Listen for claim events
offerwallClient.Events.On<OfferClaimedEventData>("offer_claimed", (data) =>
{
Console.WriteLine($"Offer claimed: {data.InstanceId}");
// Update UI to reflect claimed offer
});Access Player Data
Get current player information:
const player = offerwallClient.getPlayer();
if (player) {
// Access player snapshot
const snapshot = player.snapshot;
console.log('Player ID:', snapshot.playerId);
console.log('Days in game:', snapshot.daysInGame);
console.log('Login streak:', snapshot.loginStreak);
console.log('Trust score:', snapshot.trustScore);
// Access currencies
const goldBalance = snapshot.currencies?.cur_coins?.balance || 0;
console.log('Gold balance:', goldBalance);
// Access levels
const forestryLevel = snapshot.levels?.forestry?.level || 1;
console.log('Forestry level:', forestryLevel);
// Access achievements
const achievements = snapshot.achievements || {};
console.log('Achievements:', Object.keys(achievements));
}var player = offerwallClient.GetPlayer();
if (player != null)
{
// Access player snapshot
var snapshot = player.Snapshot;
Console.WriteLine($"Player ID: {snapshot.PlayerId}");
Console.WriteLine($"Days in game: {snapshot.DaysInGame}");
Console.WriteLine($"Login streak: {snapshot.LoginStreak}");
Console.WriteLine($"Trust score: {snapshot.TrustScore}");
// Access currencies
var goldBalance = snapshot.Currencies?.GetValueOrDefault("cur_coins")?.Balance ?? 0;
Console.WriteLine($"Gold balance: {goldBalance}");
// Access levels
var forestryLevel = snapshot.Levels?.GetValueOrDefault("forestry")?.Level ?? 1;
Console.WriteLine($"Forestry level: {forestryLevel}");
// Access achievements
var achievements = snapshot.Achievements ?? new Dictionary<string, AchievementData>();
Console.WriteLine($"Achievements: {achievements.Count}");
}
Stacked