@gamiforge/sdk
v0.1.0
Published
Gamiforge SDK — gamification client and React UI components
Downloads
77
Maintainers
Readme
@gamiforge/sdk
The official SDK for Gamiforge — add XP, achievements, streaks, and leaderboards to your application in minutes.
Contents
- Prerequisites
- Installation
- Quick Start
- React Integration
- Node.js / Server-Side Usage
- Error Handling
- TypeScript
- License
Prerequisites
To use this SDK you need a Gamiforge account and a provisioned Runtime. Sign up at www.gamiforge.com to get started.
Gamiforge offers two hosting options:
| Option | Description |
|---|---|
| Hosted | Gamiforge provisions and manages the Runtime for you. Your runtimeBaseUrl is provided in the dashboard after creating an app. |
| Self-Hosted | You deploy and run the Runtime in your own infrastructure. Visit www.gamiforge.com to learn more and request a self-hosted license. |
Once your account is set up, create an application in the dashboard to get your runtimeBaseUrl and apiKey.
Installation
npm install @gamiforge/sdk
# or
yarn add @gamiforge/sdk
# or
pnpm add @gamiforge/sdkReact peer dependencies (required only for React integration):
npm install react react-domQuick Start
React
// 1. Import styles once in your app entry point
import '@gamiforge/sdk/styles.css';
// 2. Wrap your app with the provider
import { GamiforgeProvider } from '@gamiforge/sdk/react';
function App() {
return (
<GamiforgeProvider
config={{
runtimeBaseUrl: 'https://your-runtime.gamiforge.io',
apiKey: 'gf_your_api_key_here',
}}
userId={currentUser.id}
>
<YourApp />
</GamiforgeProvider>
);
}
// 3. Track events from any component
import { useTrackEvent } from '@gamiforge/sdk/react';
function LessonButton() {
const { trackEvent, isTracking } = useTrackEvent();
return (
<button
onClick={() => trackEvent('activity.completed', { lessonId: 'lesson_42' })}
disabled={isTracking}
>
Complete Lesson
</button>
);
}Node.js
import { GamiforgeClient } from '@gamiforge/sdk';
const client = new GamiforgeClient({
runtimeBaseUrl: 'https://your-runtime.gamiforge.io',
apiKey: 'gf_your_api_key_here',
});
const result = await client.trackEvent({
eventName: 'activity.completed',
userId: 'user_abc123',
metadata: { lessonId: 'lesson_42', score: 95 },
});
console.log(result.awards); // XP, achievements, level-ups earned
console.log(result.currentState); // Updated user stateReact Integration
Provider Setup
Wrap your component tree with <GamiforgeProvider> near the root of your app. It initializes the SDK client, fetches the user's current state, and provides context to all hooks and components.
import { GamiforgeProvider } from '@gamiforge/sdk/react';
<GamiforgeProvider
config={{
runtimeBaseUrl: 'https://your-runtime.gamiforge.io', // Runtime URL from your Gamiforge dashboard
apiKey: 'gf_your_api_key_here', // API key from your Gamiforge dashboard
timeout: 10000, // Request timeout in ms (default: 10000)
retry: { maxRetries: 2, backoffMs: 500 }, // Retry config (optional)
}}
userId={currentUser.id} // Your app's user identifier
levelThresholds={myLevelConfig} // Optional — overrides the default 5-level config
theme={{ colors: { primary: '#6C5CE7' } }} // Optional — see Theming
>
{/* Mount toast/overlay components once at this level */}
<AchievementToast />
<XPGainIndicator />
<LevelUpModal />
<AwardToast />
<YourApp />
</GamiforgeProvider>Next.js — import styles in your root layout.tsx and mark the provider as a Client Component:
// app/layout.tsx
import '@gamiforge/sdk/styles.css';
// components/GamificationWrapper.tsx
'use client';
import { GamiforgeProvider } from '@gamiforge/sdk/react';
export function GamificationWrapper({ userId, children }) {
return (
<GamiforgeProvider
config={{
runtimeBaseUrl: process.env.NEXT_PUBLIC_GAMIFORGE_RUNTIME_URL!,
apiKey: process.env.NEXT_PUBLIC_GAMIFORGE_API_KEY!,
}}
userId={userId}
>
<AchievementToast />
<XPGainIndicator />
<LevelUpModal />
{children}
</GamiforgeProvider>
);
}Tracking Events
Use useTrackEvent to send events to the Gamiforge Runtime. Awards (XP, achievements, level-ups) are automatically emitted to any mounted UI components.
import { useTrackEvent } from '@gamiforge/sdk/react';
function ActivityButton() {
const { trackEvent, isTracking } = useTrackEvent();
const handleClick = async () => {
const result = await trackEvent('activity.completed', {
// Optional metadata — sent with the event for server-side processing
lessonId: 'lesson_42',
score: 95,
});
console.log(result.awards); // Awards earned this event
console.log(result.currentState); // User's updated state
};
return (
<button onClick={handleClick} disabled={isTracking}>
{isTracking ? 'Saving...' : 'Complete Activity'}
</button>
);
}Hooks
All hooks must be used inside a <GamiforgeProvider>.
useUserState
Access the current user's gamification state.
import { useUserState } from '@gamiforge/sdk/react';
const { xp, level, achievements, streaks, loading, error, refetch } = useUserState();| Return value | Type | Description |
|---|---|---|
| xp | number | Total XP earned |
| level | number | Current level |
| achievements | string[] | Unlocked achievement keys |
| streaks | Record<string, StreakState> | Active streaks by key |
| loading | boolean | True while fetching initial state |
| error | Error \| null | Last fetch error, if any |
| refetch | () => Promise<void> | Manually refresh state |
useTrackEvent
const { trackEvent, isTracking } = useTrackEvent();
// trackEvent(eventName, metadata?) => Promise<EventResponse>
await trackEvent('purchase.completed', { amount: 49.99 });useXPProgress
Calculate progress toward the next level.
const { xp, level, progress, xpToNextLevel, isMaxLevel } = useXPProgress();
// progress: 0–1 (fraction of the way to the next level)
// xpToNextLevel: XP remaining until level-upuseLeaderboard
import { useLeaderboard } from '@gamiforge/sdk/react';
const { entries, loading, error } = useLeaderboard({
type: 'xp', // 'xp' | 'streak'
limit: 10,
windowDays: 7, // Optional: rolling window for XP leaderboards
pollInterval: 30000, // Optional: auto-refresh in ms
});
// entries: Array<{ userId, value, rank }>useAchievementFeed
Subscribe to achievement unlock events.
import { useAchievementFeed } from '@gamiforge/sdk/react';
const { feed } = useAchievementFeed({ maxItems: 5 });
// feed: Array<{ achievementKey, reason, importance, receivedAt }>useAwardFeed
Subscribe to the raw award queue (XP, achievements, level-ups, streaks).
import { useAwardFeed } from '@gamiforge/sdk/react';
const { feed } = useAwardFeed();
// feed: Array<{ award, state, receivedAt }>useGamiforgeClient
Access the underlying GamiforgeClient directly for advanced use cases.
import { useGamiforgeClient } from '@gamiforge/sdk/react';
const client = useGamiforgeClient();
const leaderboard = await client.getLeaderboard({ type: 'xp', limit: 5 });UI Components
Import @gamiforge/sdk/styles.css once in your app for all components to render correctly.
<AchievementToast>
Automatically pops up when an achievement is unlocked.
<AchievementToast
position="top-right" // 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'
duration={5000} // Display duration in ms
/><XPGainIndicator>
Floating "+XP" animation that fires when XP is awarded.
<XPGainIndicator position="top-right" /><LevelUpModal>
Full-screen modal that appears when the user levels up.
<LevelUpModal /><AwardToast>
Generic toast for any award type.
<AwardToast position="bottom-right" duration={4000} /><ProgressBar>
XP progress bar toward the next level.
<ProgressBar
showLabel // Show "Level N" label
showPercentage // Show percentage text
animated // Animate on change
height={8} // Bar height in px
/><StreakIndicator>
Displays the user's current streak.
<StreakIndicator
streakKey="daily_login" // Optional: specific streak to display
showLongest // Also show all-time longest streak
/><Leaderboard>
Ranked list of users by XP or streak.
<Leaderboard
type="xp"
limit={10}
highlightUserId={currentUser.id} // Highlights this user's row
pollInterval={30000} // Auto-refresh in ms
/><UserProgressWidget>
Composite card combining XP bar, level, streak, and achievement count.
<UserProgressWidget title="Your Progress" /><ConfettiBurst>
Trigger a confetti animation programmatically.
import { ConfettiBurst } from '@gamiforge/sdk/react';
<ConfettiBurst active={showConfetti} onComplete={() => setShowConfetti(false)} />Theming
The SDK uses CSS custom properties for all visual styling. There are three ways to customize the theme, applied in this order (highest precedence last):
1. Dashboard appearance config — set once in your Gamiforge dashboard; automatically applied via <GamiforgeProvider>.
2. Theme prop on <GamiforgeProvider> — overrides the dashboard config at the component level:
<GamiforgeProvider
config={...}
userId={userId}
theme={{
colors: {
primary: '#6C5CE7',
primaryLight: '#a29bfe',
success: '#00b894',
warning: '#fdcb6e',
danger: '#d63031',
background: '#ffffff',
surface: '#f8f9fa',
text: '#2d3436',
textSecondary: '#636e72',
border: '#dfe6e9',
},
fontFamily: "'Inter', sans-serif",
borderRadius: '12px',
shadow: '0 4px 20px rgba(0,0,0,0.08)',
}}
>3. CSS custom properties — override directly in your stylesheet for full control:
[data-gamiforge-theme] {
--gf-color-primary: #6C5CE7;
--gf-color-primary-light: #a29bfe;
--gf-color-success: #00b894;
--gf-color-warning: #fdcb6e;
--gf-color-danger: #d63031;
--gf-color-background: #ffffff;
--gf-color-surface: #f8f9fa;
--gf-color-text: #2d3436;
--gf-color-text-secondary: #636e72;
--gf-color-border: #dfe6e9;
--gf-font-family: 'Inter', sans-serif;
--gf-font-size-sm: 0.75rem;
--gf-font-size-base: 0.875rem;
--gf-font-size-lg: 1rem;
--gf-font-size-xl: 1.25rem;
--gf-border-radius: 12px;
--gf-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
--gf-transition-duration: 200ms;
--gf-animation-duration: 400ms;
}Node.js / Server-Side Usage
Use GamiforgeClient directly when tracking events from a backend service (API route, webhook handler, background job, etc.).
import { GamiforgeClient } from '@gamiforge/sdk';
const client = new GamiforgeClient({
runtimeBaseUrl: process.env.GAMIFORGE_RUNTIME_URL!,
apiKey: process.env.GAMIFORGE_API_KEY!,
});
// Track an event
const result = await client.trackEvent({
eventName: 'purchase.completed',
userId: 'user_abc123',
timestamp: new Date().toISOString(), // Optional — defaults to now
metadata: { amount: 49.99, productId: 'pro_plan' },
});
// Fetch user state
const state = await client.getUserState('user_abc123');
// Fetch leaderboard
const leaderboard = await client.getLeaderboard({
type: 'xp',
limit: 10,
windowDays: 7, // Rolling 7-day window
});
// Clean up when done (e.g., in a Lambda handler)
client.destroy();Error Handling
The SDK exports a typed error hierarchy. Catch errors by class to handle them appropriately.
import {
GamiforgeError,
ApiError,
NetworkError,
TimeoutError,
ConfigError,
} from '@gamiforge/sdk';
try {
await client.trackEvent({ eventName: 'test', userId: 'u1' });
} catch (err) {
if (err instanceof ApiError) {
console.error(`API error ${err.statusCode}:`, err.code, err.message);
// err.responseBody contains the full error response body
} else if (err instanceof NetworkError) {
console.error('Network error:', err.message, err.cause);
} else if (err instanceof TimeoutError) {
console.error(`Request timed out after ${err.timeoutMs}ms`);
} else if (err instanceof ConfigError) {
console.error('Bad SDK config:', err.message);
} else {
throw err;
}
}Quota exceeded is handled gracefully — the SDK emits a quotaExceeded event instead of throwing, and trackEvent returns an empty awards list so your UI doesn't crash:
client.events.on('quotaExceeded', ({ message, limit, resetDate }) => {
console.warn(`Event quota exceeded (limit: ${limit}). Resets: ${resetDate}`);
});TypeScript
The SDK is written in TypeScript and ships full type definitions. All public types are exported from the package roots.
import type {
GamiforgeConfig,
TrackEventParams,
EventResponse,
UserState,
Award,
AwardType,
StreakState,
LeaderboardEntry,
LeaderboardParams,
LeaderboardResponse,
LevelThreshold,
} from '@gamiforge/sdk';
import type {
GamiforgeProviderProps,
GamiforgeTheme,
GamiforgeThemeColors,
} from '@gamiforge/sdk/react';License
MIT © Gamiforge
