State SDK

Save and retrieve user data, game progress, preferences, and more — without setting up a backend server.

Download for Your AI Tool

Download this guide and paste it into Google AI Studio, Lovable, Cursor, Claude, ChatGPT, or any AI coding tool to let them use state management in your app.

Download Guide (.md)

Quick Start

The SDK is automatically injected into your app and accessible via window.gapp.state.

// Save data
await gapp.state.set('theme', 'dark')

// Read data
const theme = await gapp.state.get('theme')
console.log(theme) // 'dark'

// Delete data
await gapp.state.delete('theme')

State Scopes

The SDK supports three state scopes for different use cases.

ScopePurposeWho Can Access
DefaultAuto-select (logged-in = user, anonymous = session)Current user/device
userLogged-in user's personal data, synced across devicesOnly that user
sessionAnonymous user's device-bound dataOnly that device
globalData shared by all users (e.g., leaderboards)Everyone can read

API Reference

Basic Operations

Auto-selects scope based on auth status

gapp.state.set(key, value)

Save data (user scope if logged in, session if anonymous)

await gapp.state.set('theme', 'dark')
gapp.state.get(key)

Read data

const theme = await gapp.state.get('theme')
gapp.state.delete(key)

Delete data

await gapp.state.delete('theme')
gapp.state.list()

List all keys

const keys = await gapp.state.list()

User Scope

Requires login, syncs across devices

gapp.state.user.set(key, value)

Save to user scope

await gapp.state.user.set('preferences', { theme: 'dark' })
gapp.state.user.get(key)

Read from user scope

const prefs = await gapp.state.user.get('preferences')

Session Scope

Device-bound, works for anonymous users

gapp.state.session.set(key, value)

Save to session scope

await gapp.state.session.set('tempData', { draft: '...' })
gapp.state.session.get(key)

Read from session scope

const temp = await gapp.state.session.get('tempData')

Global Scope

Shared by all users of the app

gapp.state.global.get(key)

Read global data

const leaderboard = await gapp.state.global.get('leaderboard')
gapp.state.global.set(key, value)

Write global data

await gapp.state.global.set('leaderboard', scores)

Utility Methods

Helper functions

gapp.state.isAuthenticated()

Check if user is logged in

if (gapp.state.isAuthenticated()) { /* user logged in */ }
gapp.state.migrateSessionToUser()

Migrate anonymous data to logged-in account

await gapp.state.migrateSessionToUser()

Usage Examples

User Preferences

// Load preferences
async function loadPreferences() {
  const prefs = await gapp.state.get('preferences') || {
    theme: 'light',
    fontSize: 14,
    notifications: true
  }
  applyPreferences(prefs)
}

// Save preferences
async function savePreferences(prefs) {
  await gapp.state.set('preferences', prefs)
}

Game Progress

// Save game progress
async function saveGame() {
  const gameState = {
    level: currentLevel,
    score: playerScore,
    inventory: playerInventory,
    timestamp: Date.now()
  }
  await gapp.state.set('saveGame', gameState)
  showMessage('Game saved!')
}

// Load game progress
async function loadGame() {
  const saved = await gapp.state.get('saveGame')
  if (saved) {
    restoreGameState(saved)
  } else {
    startNewGame()
  }
}

Global Leaderboard

// Submit score
async function submitScore(playerName, score) {
  const leaderboard = await gapp.state.global.get('leaderboard') || []

  leaderboard.push({
    name: playerName,
    score: score,
    date: new Date().toISOString()
  })

  // Sort and keep top 100
  leaderboard.sort((a, b) => b.score - a.score)
  const top100 = leaderboard.slice(0, 100)

  await gapp.state.global.set('leaderboard', top100)
}

// Display leaderboard
async function showLeaderboard() {
  const leaderboard = await gapp.state.global.get('leaderboard') || []
  renderLeaderboard(leaderboard)
}

Limits

LimitValue
Max key length100 characters
Allowed key charactersa-z, A-Z, 0-9, _, -
User/Session data limit100 KB per app
Global data limit1 MB per app
Max key count100 keys per scope

FAQ

Q: Will anonymous user data be lost?

A: No. Anonymous data is saved on the server, bound to a device ID (stored in localStorage). As long as browser data isn't cleared, data is kept for 90 days. After logging in, users can migrate anonymous data to their account.

Q: Is the data secure?

A: User scope: Only the logged-in user can access. Session scope: Only the same device can access. Global scope: Everyone can read/write based on app creator's settings.

Q: How do I know if the SDK is ready?

A: Listen for the 'gapp:state:ready' event, or just call the API directly (SDK is usually injected when page loads).

Q: Can I use this SDK outside of iframe?

A: No. The State SDK is only available in apps hosted on gapp.so. If you need external access, use the REST API.