Working with Offers
Access offers, player data, conditions, and rewards
Offers are the core of the Stacked platform - they represent tasks, achievements, or milestones that players can complete to earn rewards. This guide covers how to retrieve offers, check completion conditions, claim rewards, and display reward information in your game.
Accessing Offers
The SDK provides several methods to retrieve offers from the local store. All offer data is automatically synchronized via the real-time connection.
Get All Offers
Retrieve all offers available to the player.
// Get all offers
const allOffers = offerwallClient.getOffers();
console.log(`Total offers: ${allOffers.length}`);
// Iterate through offers
allOffers.forEach(offer => {
console.log(`${offer.name}: ${offer.status}`);
});// Get all offers
var allOffers = offerwallClient.GetOffers();
Console.WriteLine($"Total offers: {allOffers.Length}");
// Iterate through offers
foreach (var offer in allOffers)
{
Console.WriteLine($"{offer.Name}: {offer.Status}");
}Filter Offers by Status
Filter offers by their current status to show players relevant content.
// Get claimable offers
const claimableOffers = offerwallClient.store.getClaimableOffers();
// Get active offers (not expired, not claimed)
const activeOffers = offerwallClient.store.getActiveOffers();
// Get offers by specific status
const surfacedOffers = offerwallClient.store.getOffersByStatus('surfaced');
const viewedOffers = offerwallClient.store.getOffersByStatus('viewed');// Get claimable offers
var claimableOffers = offerwallClient.Store.GetClaimableOffers();
// Get active offers (not expired, not claimed)
var activeOffers = offerwallClient.Store.GetActiveOffers();
// Get offers by specific status
var surfacedOffers = offerwallClient.Store.GetOffersByStatus(PlayerOfferStatus.Surfaced);
var viewedOffers = offerwallClient.Store.GetOffersByStatus(PlayerOfferStatus.Viewed);Get Specific Offer
Retrieve a single offer by its instance ID.
const instanceId = 'instance-abc123';
const offer = offerwallClient.store.getOffer(instanceId);
if (offer) {
console.log('Offer found:', offer.name);
console.log('Status:', offer.status);
console.log('Rewards:', offer.rewards);
} else {
console.log('Offer not found');
}var instanceId = "instance-abc123";
var offer = offerwallClient.Store.GetOffer(instanceId);
if (offer != null)
{
Console.WriteLine($"Offer found: {offer.Name}");
Console.WriteLine($"Status: {offer.Status}");
Console.WriteLine($"Rewards: {offer.Rewards.Count}");
}
else
{
Console.WriteLine("Offer not found");
}Claiming Rewards
When an offer becomes claimable, the player can claim their rewards. The SDK handles the claim request and the server validates and distributes the rewards.
Basic Claim
Call claimReward() or ClaimRewardAsync() with the offer's instance ID.
async function claimOffer(instanceId: string) {
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
});Claim Hooks
Use the beforeOfferClaim hook to add client-side validation before claiming. Use the afterOfferClaim hook to show reward animations or update your UI after successful claims.
Working with Player Data
The player object contains the current state of player data including currencies, levels, achievements, and custom game data. This data is used by offer conditions to determine eligibility.
Accessing Player Data
Retrieve the current player state from the local store.
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).length);
}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}");
}Player Structure
The player object contains two main parts:
snapshot- Core player data tracked by Stacked (currencies, levels, achievements, etc.)data- Additional optional game-specific data with visual metadata
For complete type documentation, see API Types.
Refreshing Player Data
Manually trigger a refresh to get the latest offers and player data from the server.
// Manually refresh offers and player data
await offerwallClient.refreshOffersAndPlayer();
// Listen for refresh events
offerwallClient.events.on('refresh', ({ offers, player }) => {
console.log(`Refreshed: ${offers.length} offers`);
console.log('Player data updated:', player.snapshot.playerId);
});// Manually refresh offers and player data
await offerwallClient.RefreshOffersAndPlayerAsync();
// Listen for refresh events
offerwallClient.Events.On<RefreshEventData>("refresh", (data) =>
{
Console.WriteLine($"Refreshed: {data.Offers.Length} offers");
Console.WriteLine($"Player data updated: {data.Player.Snapshot.PlayerId}");
});Checking Completion Conditions
Completion conditions determine when a surfaced offer can be claimed. The server automatically validates these conditions, but the SDK provides utilities to check progress client-side for UI purposes (progress bars, completion indicators, etc.).
For detailed documentation on how completion conditions work, see Completion Conditions Concept.
Use the completion conditions utility to verify if a player has met the requirements to claim an offer and get detailed progress information.
import { meetsCompletionConditions } from '@pixels-online/pixels-client-js-sdk';
const player = offerwallClient.getPlayer();
const offer = offerwallClient.store.getOffer('instance-id');
if (player && offer?.completionConditions) {
const result = meetsCompletionConditions({
completionConditions: offer.completionConditions,
completionTrackers: offer.completionTrackers,
playerSnap: player.snapshot,
addDetails: true, // Get detailed condition data
});
console.log('Can claim:', result.isValid);
console.log('Condition details:', result.conditionData);
// Show progress
if (result.conditionData) {
const progress = calculateProgress(result.conditionData);
showProgressBar(progress);
}
}using PixelsOnline.Client.SDK;
var player = offerwallClient.GetPlayer();
var offer = offerwallClient.Store.GetOffer("instance-id");
if (player != null && offer != null)
{
var result = Conditions.MeetsCompletionConditions(
offer.CompletionConditions,
offer.CompletionTrackers,
player.Snapshot,
addDetails: true // Get detailed condition data
);
Console.WriteLine($"Can claim: {result.IsValid}");
// Show progress for each condition
if (result.ConditionData != null)
{
foreach (var detail in result.ConditionData)
{
Console.WriteLine($"{detail.Kind}: {detail.Text}");
Console.WriteLine($" Met: {detail.IsMet}");
if (detail.TrackerAmount.HasValue)
{
Console.WriteLine($" Progress: {detail.TrackerAmount}");
}
}
}
}Displaying Rewards
Rewards can have custom names and images defined by your game's asset resolver. The SDK provides helper methods to resolve these assets automatically.
Resolving Reward Assets
Get resolved reward data with custom names and images from your assetResolver configuration.
// Resolve a single reward
const reward = offer.rewards[0];
const resolved = offerwallClient.assets.resolveReward(reward);
console.log('Name:', resolved.name); // Custom name or default
console.log('Image:', resolved.image); // Custom image or fallback
console.log('Amount:', resolved.amount); // Original amount
// Resolve all offer rewards
const resolvedRewards = offerwallClient.assets.resolveOfferRewards(offer);
resolvedRewards.forEach(reward => {
console.log(`${reward.amount}x ${reward.name}`);
displayRewardCard({
name: reward.name,
image: reward.image,
amount: reward.amount,
kind: reward.kind,
});
});// Resolve a single reward
var reward = offer.Rewards[0];
var resolved = offerwallClient.Assets.ResolveReward(reward);
Console.WriteLine($"Name: {resolved.Name}"); // Custom name or default
Console.WriteLine($"Image: {resolved.Image}"); // Custom image or fallback
Console.WriteLine($"Amount: {resolved.Amount}"); // Original amount
// Resolve all offer rewards
var resolvedRewards = offerwallClient.Assets.ResolveOfferRewards(offer);
foreach (var rewardData in resolvedRewards)
{
Console.WriteLine($"{rewardData.Amount}x {rewardData.Name}");
DisplayRewardCard(new RewardCardData
{
Name = rewardData.Name,
Image = rewardData.Image,
Amount = rewardData.Amount,
Kind = rewardData.Kind
});
}
Stacked