Pixels Client JS SDK
A powerful TypeScript SDK for integrating Pixels BuildOn offerwall functionality into web applications and games. This SDK provides real-time offer management, player progression tracking, and reward handling capabilities.
- Real-time Offer Management - Live updates via Server-Sent Events (SSE)
- Player Progression Tracking - Monitor player stats, achievements, and conditions
- Reward System Integration - Handle various reward types (coins, items, exp, etc.)
- Event-Driven Architecture - React to offer events and player actions
- TypeScript Support - Full type safety and IntelliSense support
- Flexible Configuration - Customizable asset resolution and hooks
- Multi-Environment Support - Local, Test, staging, and production environments
- Auto-Reconnection - Robust connection management with retry logic
``bash`
npm install @pixels-online/pixels-client-js-sdk
`typescript
import { OfferwallClient } from '@pixels-online/pixels-client-js-sdk';
const client = new OfferwallClient({
env: 'test', // or 'live' for production
tokenProvider: async () => {
// Fetch JWT token from your server. We recommend using our server-side SDK on your server for JWT creation
const response = await fetch('/api/auth/pixels-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
});
const data = await response.json();
return data.token;
},
assetResolver: (_, id: string) => {
return {
name: exampleGameLib[id]?.name || 'Unknown2',
image: exampleGameLib[id]?.image,
};
},
fallbackRewardImage: 'https://example.com/default-reward.png',
hooks: {
onOfferSurfaced: (offer) => {
var random = Math.random() < 0.5;
return random; // 50% chance to show the offer
},
},
autoConnect: true,
});
`
`typescript
// Initialize the client
await client.initialize();
// Listen for offers
client.on('offersUpdated', (offers) => {
console.log('Available offers:', offers);
displayOffersInUI(offers);
});
// Listen for player updates
client.on('playerUpdated', (player) => {
console.log('Player snapshot updated:', player.snapshot);
console.log('Player data updated:', player.data);
updatePlayerStatsUI(player);
});
`
Each offer object returned by the SDK includes helper methods for rendering offer state in your UI.
#### Checking if an Offer is Claimable
Use offer.canClaim() to determine whether the player has met all requirements and can claim the offer:
`typescript`
const claimable = offer.canClaim?.();
renderClaimButton(offer, { disabled: !claimable });
Use offer.getProgressPercent() to get the player's overall completion percentage (0–100):
`typescript
const progress = offer.getProgressPercent?.() ?? 0;
// Example: render a progress bar
renderProgressBar(offer, { percent: progress });
`
Use offer.getCompletionConditions() to get a list of individual conditions, each with isMet (boolean) and text (human-readable description):
`typescript
const conditions = offer.getCompletionConditions?.() ?? [];
for (const condition of conditions) {
renderCondition({
text: condition.text,
completed: condition.isMet,
});
}
// Example React rendering
function OfferConditions({ offer }) {
const conditions = offer.getCompletionConditions?.() ?? [];
return (
$3
For team offers (offers where all team members must complete for anyone to claim), use
offer.getSiblingProgress() to display each sibling's progress:`typescript
const isTeamOffer = offer.labels?.includes('team_offer');if (isTeamOffer) {
const siblingProgress = offer.getSiblingProgress?.() ?? [];
for (const sibling of siblingProgress) {
renderSiblingRow({
playerId: sibling.playerId,
percentCompleted: sibling.percentCompleted,
isComplete: sibling.isComplete,
});
}
}
// Example React rendering
function TeamProgress({ offer }) {
const siblings = offer.getSiblingProgress?.() ?? [];
if (!siblings.length) return null;
return (
Team Progress
{siblings.map((s) => (
{s.playerId}
{s.percentCompleted}%
{s.isComplete ? '✓ Complete' : 'In Progress'}
))}
);
}
`$3
`typescript
// Claim an offer
try {
const result = await client.claimOffer(offerId);
console.log('Offer claimed successfully:', result);
} catch (error) {
console.error('Failed to claim offer:', error);
}
`📊 Player Data Structure
The SDK provides player information through the
IClientPlayer interface:`typescript
interface IClientPlayer {
snapshot: IPlayerSnapshot; // Core player data (levels, currencies, achievements, etc.)
data?: IPlayerData | null; // Additional game-specific data
}
`$3
`typescript
// Get the current player
const player = client.getPlayer();if (player) {
// Access core player data
console.log('Player ID:', player.snapshot.playerId);
console.log('Player level:', player.snapshot.levels?.combat?.level);
console.log('Currency balance:', player.snapshot.currencies?.gold?.balance);
// Access additional player data (if available)
if (player.data) {
console.log('Additional currencies:', player.data.currencies);
}
}
`🎯 Configuration Options
$3
`typescript
interface OfferwallConfig {
/* Environment: 'test' | 'live' | custom endpoint /
env: 'test' | 'live' | (string & {}); /* Auto-connect on initialization (default: false) /
autoConnect?: boolean;
/* Enable auto-reconnection (default: true) /
reconnect?: boolean;
/* Reconnection delay in ms (default: 1000) /
reconnectDelay?: number;
/* Max reconnection attempts (default: 5) /
maxReconnectAttempts?: number;
/* Enable debug logging (default: false) /
debug?: boolean;
/* Event hooks for custom logic /
hooks?: Partial;
/* Custom asset resolver for rewards /
assetResolver?: AssetResolver;
/* Fallback image for unknown rewards /
fallbackRewardImage: string;
/* JWT token provider function /
tokenProvider: TokenProvider;
}
`🎨 Asset Resolution
Customize how rewards are displayed in your game:
`typescript
const gameAssets = {
gems: { name: 'Gems', image: '/assets/gems.png' },
gold: { name: 'Gold Coins', image: '/assets/gold.png' },
sword_1: { name: 'Iron Sword', image: '/assets/sword_iron.png' },
};const client = new OfferwallClient({
// ... other config
assetResolver: (reward, assetId) => {
const asset = gameAssets[assetId];
if (asset) {
return { name: asset.name, image: asset.image };
}
return { name:
Unknown Item (${assetId}), image: null };
},
});
`🎣 Event Hooks
Implement custom logic with event hooks:
`typescript
const client = new OfferwallClient({
// ... other config
hooks: {
// Control which offers to show
onOfferSurfaced: (offer) => {
// Custom logic to determine if offer should be shown
const currentPlayer = client.getPlayer();
return currentPlayer?.snapshot.levels?.overall?.level >= offer.minLevel;
}, // Handle successful offer claims
onOfferClaimed: async (offer, rewards) => {
console.log('Offer completed!', { offer, rewards });
// Award rewards in your game
await showConfetti(rewards);
},
// Handle connection events
onConnect: () => {
console.log('Connected to Pixels BuildOn');
showConnectionStatus('connected');
},
onDisconnect: () => {
console.log('Disconnected from Pixels BuildOn');
showConnectionStatus('disconnected');
},
},
});
`📡 Events
Listen to various events emitted by the client:
`typescript
// Offer-related events
client.on('offersUpdated', (offers) => {
/ Handle offers update /
});
client.on('offerAdded', (offer) => {
/ Handle new offer /
});
client.on('offerRemoved', (offerId) => {
/ Handle offer removal /
});
client.on('offerUpdated', (offer) => {
/ Handle offer changes /
});// Player-related events
client.on('playerUpdated', (player) => {
/ Handle player data changes /
});
// Connection events
client.on('connected', () => {
/ Handle connection /
});
client.on('disconnected', () => {
/ Handle disconnection /
});
client.on('reconnecting', (attempt) => {
/ Handle reconnection attempts /
});
// Error events
client.on('error', (error) => {
/ Handle errors /
});
`🏗️ API Reference
$3
####
initialize(): PromiseInitialize the client and establish connection.
####
disconnect(): PromiseDisconnect from the service.
####
refreshOffersAndPlayer(): { offers: IClientOffer[], player: IClientPlayer }Refresh and get all current offers.
####
claimOffer(offerId: string): PromiseClaim an offer and receive rewards.
####
getConnectionState(): ConnectionStateGet current connection status.
$3
`typescript
import { meetsConditions, AssetHelper } from '@pixels-online/pixels-client-js-sdk';// Check if player meets offer conditions
const canClaim = meetsConditions(player.snapshot, offer.surfacingConditions);
// Asset helper utilities
const assetHelper = new AssetHelper(assetResolver, fallbackImage);
const rewardAsset = assetHelper.resolveRewardAsset(reward, assetId);
`🌍 Environments
The SDK supports multiple environments:
-
test - Sandbox environment for development
- live - Production environment� Migration Guide
$3
Player Data Structure Update
The player data structure has been updated to provide better separation between core player data and additional game-specific data:
- Old:
IClientPlayerSnapshot (flat structure)
- New: IClientPlayer (structured with snapshot and data properties)Migration Steps:
`typescript
// Before (v0.x)
const player = client.getPlayer(); // IClientPlayerSnapshot
const level = player.levels?.combat?.level;
const gold = player.currencies?.gold?.balance;// After (v1.0+)
const player = client.getPlayer(); // IClientPlayer
const level = player.snapshot.levels?.combat?.level;
const gold = player.snapshot.currencies?.gold?.balance;
// Access additional data (new feature)
const additionalCurrencies = player.data?.currencies;
`Event Handler Updates:
`typescript
// Before
client.on('playerUpdated', (playerSnapshot) => {
updateUI(playerSnapshot.currencies);
});// After
client.on('playerUpdated', (player) => {
updateUI(player.snapshot.currencies);
// Also handle additional data if needed
if (player.data) {
handleAdditionalData(player.data);
}
});
`�📋 Requirements
- Node.js 16+
- TypeScript 4.5+ (if using TypeScript)
- Modern browser with EventSource support
🤝 Contributing
1. Fork the repository
2. Create your feature branch (
git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add amazing feature')
4. Push to the branch (git push origin feature/amazing-feature`)This project is licensed under the AGPLv3 License - see the LICENSE.md file for details.
- GitLab Repository
- Issue Tracker
- Pixels BuildOn Documentation
For support and questions:
- Create an issue on GitLab
- Contact the Pixels team
---
Made with ❤️ by the Pixels team