App Platform Values
This page is the complete reference for all values, context fields, and API helpers available to app developers at runtime.
Runtime Sources Summary
| Source | Available in | Use it for |
|---|---|---|
SDK hooks (useShuuka(), etc.) | React apps only | UI state, settings, field values |
window.__shuukaCtx | All app types | Runtime context, field values, shared profile payload, API base URL |
window.ShuukaApi / window.shkApi | All app types | Storage, entries, access codes |
{{placeholder_key}} template tokens | Simple/smart template.html only | Instance settings baked into the HTML server-side |
window.__shuukaCtx — Complete Reference
Every app page (profile card, admin page, public page, dev mode) receives this global object injected before the page finishes loading.
window.__shuukaCtx = {
// Identifiers
appSlug: "giveaway", // manifest slug
publicId: "abc123XY", // profile owner's public identifier
billboardAppId: 42, // this specific installed app instance ID
billboardUserId: 7, // user ID of the billboard owner
// API routing
apiBaseUrl: "https://api.shuuka.com/en", // always use this, not a hardcoded path
// Current state
isPublicPage: false, // true on /platform-app/... public pages; false in admin pages
locale: "en", // active locale, e.g. "en", "de"
themeMode: "dark", // "dark" or "light" (from the active profile theme)
// Configuration from the active profile
fieldValues: { // resolved app instance settings (from placeholders)
campaign_title: "Summer Giveaway",
entry_mode: "single_entry"
},
profile: {
public_id: "abc123XY",
nickname: "creator-name",
display_name: "Creator Name",
description: "Localized profile bio for the active locale",
avatar_url: "https://cdn.shuuka.com/avatar.jpg",
category: "Artist",
is_verified: true,
subscription_plan: "pro",
current_locale: "en"
},
appData: { // installed app definition metadata
id: 1,
name: "Giveaway",
version: "1.2.0",
unique_key: "giveaway"
},
links: [ // profile owner's active social links
{ id: 1, type: "instagram", title: "Instagram", url: "https://instagram.com/...", icon_url: "/social_icons/shuuka-Instagram.png", active: true }
],
// Authentication (admin pages only)
accessToken: "eyJ...", // bearer token for admin API calls (admin pages only)
// SDK flag
suppressIframeShadow: true, // do not add box-shadow to document.body; card wrapper handles it
// Convenience alias
shkApi: { ... } // same object as window.ShuukaApi
};
Availability by page type
| Key | Profile card | Admin page | Public page | Dev mode |
|---|---|---|---|---|
appSlug | ✓ | ✓ | ✓ | ✓ |
publicId | ✓ | ✓ | ✓ | ✓ |
billboardAppId | ✓ | ✓ | ✓ | ✓ |
apiBaseUrl | ✓ | ✓ | ✓ | ✓ |
fieldValues | ✓ | ✓ | ✓ | ✓ |
profile | ✓ | ✓ | ✓ | ✓ |
locale | ✓ | ✓ | ✓ | ✓ |
themeMode | ✓ | — | — | ✓ |
isPublicPage | false | false | true | — |
accessToken | — | ✓ | — | ✓ (admin tabs) |
links | ✓ | — | — | ✓ |
appData | ✓ | ✓ | ✓ | ✓ |
Safe access pattern
Always guard against the context not yet being set:
var ctx = window.__shuukaCtx || {};
var shkApi = ctx.shkApi || window.ShuukaApi;
var appId = ctx.billboardAppId || 0;
var publicId = ctx.publicId || '';
var locale = ctx.locale || 'en';
var profile = ctx.profile || {};
fieldValues — Reading Instance Settings
fieldValues contains the resolved App Instance Settings for this app instance. For simple and smart apps, these are the values the profile owner configured via the groups and placeholders sidebar.
var ctx = window.__shuukaCtx || {};
var fieldValues = ctx.fieldValues || {};
// Read a simple value
var title = fieldValues.campaign_title || 'Default Title';
// For translatable fields, values may be nested by locale:
var locale = ctx.locale || 'en';
var msg = (fieldValues[locale] && fieldValues[locale].welcome_message)
|| fieldValues.welcome_message
|| 'Welcome!';
Template tokens in template.html are pre-replaced server-side — you do not need JavaScript to read them for the initial render. Use fieldValues only for dynamic operations (e.g. updating the UI after the page loads, or building API calls).
profile — Shared Profile Payload
Every runtime now receives a normalized profile object so apps can reuse profile identity data instead of duplicating avatar, display name, bio, or verification fields in app settings.
Use this object in:
- simple apps:
window.__shuukaCtx.profileorwindow.shuukaConfig.profile - smart apps:
window.__shuukaCtx.profileorwindow.shuukaConfig.profile - native apps:
props.profilein React mounts, mirrored fromdata-profile
Example:
var profile = (window.__shuukaCtx && window.__shuukaCtx.profile)
|| (window.shuukaConfig && window.shuukaConfig.profile)
|| {};
var displayName = profile.display_name || profile.displayName || profile.nickname || '';
var avatarUrl = profile.avatar_url || profile.avatarUrl || '';
var bio = profile.description || profile.bio || '';
Canonical fields
| Key | Type | Description |
|---|---|---|
profile.public_id | string | Public profile identifier |
profile.nickname | string | Public handle without @ |
profile.display_name | string | Best display name fallback for the owner |
profile.description | string | Localized profile description for the current locale |
profile.avatar_url | string | Resolved avatar URL |
profile.category | string | Resolved category label |
profile.is_verified | boolean | Verification status |
profile.subscription_plan | string | Current plan, e.g. free, pro, enterprise |
profile.current_locale | string | Locale used to resolve localized fields |
profile.available_locales | string[] | Available locales when known |
profile.location | object | Optional country, region, city values when known |
Compatibility aliases
The runtime also includes camelCase mirrors for the main fields, such as publicId, displayName, avatarUrl, categoryName, verifyStatus, and subscriptionPlan, so legacy code can migrate gradually.
Theme note
This profile object is the app-runtime contract. It is additive and does not replace theme-side templateData.user. Themes still use [[user.*]] and templateData.user; apps should use profile.
window.shuukaConfig
Some values are also available via a separate global:
window.shuukaConfig = {
apiBaseUrl: "https://api.shuuka.com/en",
suppressIframeShadow: true,
profile: {
nickname: "creator-name",
display_name: "Creator Name"
},
theme: { // active theme configuration (SDK theme mode only)
config: {
background: { color: "#0a0a0f", mode: "solid" },
layout: { structure: "centered" },
iframe: { border_radius: 16, shadow: "md" }
}
}
};
The theme.config object reflects the full resolved theme config. Use it if your app needs to read the parent theme's design values (e.g. to match card radius or accent color). Prefer CSS custom properties injected by the theme for visual styling.
SDK Hooks (React Apps)
useShuuka()
Returns the main SDK instance and runtime state.
import { useShuuka } from '@shuuka/sdk/index.sdk.js';
const { sdk, uiState, config, context } = useShuuka();
| Key | Type | Description |
|---|---|---|
sdk | object | Main SDK instance with UI helpers |
uiState | object | Current embed mode, fullsize, and modal state |
config | object | Runtime configuration from the host |
context | object | Installed-app context and metadata |
uiState fields
| Field | Type | Description |
|---|---|---|
uiState.isOpen | boolean | true when the app is inside an open modal |
uiState.isFullsize | boolean | true when the app is in fullsize mode |
uiState.embedMode | string | Current embed mode identifier |
useSettings()
Returns the resolved App Global Settings values from settings.json.
import { useSettings } from '@shuuka/sdk/index.sdk.js';
const settings = useSettings();
// { site_name: "My App", welcome_message: "Hello", show_count: true, ... }
useShuukaFieldValues()
Returns the current App Instance Settings values and helpers to update them.
import { useShuukaFieldValues } from '@shuuka/sdk/index.sdk.js';
const { values, saveValues, refresh } = useShuukaFieldValues();
| Key | Type | Description |
|---|---|---|
values | object | Current resolved field values |
saveValues(updates) | function | Persist field value updates |
refresh() | function | Re-fetch current values |
useShuukaReady()
Provides SDK bootstrap helpers after the runtime is ready.
import { useShuukaReady } from '@shuuka/sdk/index.sdk.js';
const { ensureSdk, isReady } = useShuukaReady();
useTranslations()
Returns localized strings from the app's lang/*.json translation files.
import { useTranslations } from '@shuuka/sdk/index.sdk.js';
const t = useTranslations();
// t('button.submit') → "Submit" (or translated equivalent)
sdk UI Helpers
All UI helpers live on the sdk object returned by useShuuka().
Modals
| Method | Arguments | Description |
|---|---|---|
sdk.openModal(url, title, mode) | `url: string, title: string, mode: 'default' | 'fullscreen'` |
sdk.openModal({ route, title, mode, query }) | options object | Open a modal with options |
sdk.openModalRoute(path, options) | path: string, { title, fullscreen, query } | Open a hash-router path in a modal |
sdk.closeModal() | — | Close the current modal |
// Open a modal from the current app base URL
sdk.openModalRoute('/details', { title: 'Details', fullscreen: false });
// Open a modal at a custom URL
const base = window.location.href.split('#')[0];
sdk.openModal(`${base}#/result`, 'Result', 'default');
Height management
| Method | Arguments | Description |
|---|---|---|
sdk.updateHeight() | — | Re-measure the iframe height from the current DOM |
sdk.uiSafe.setHeight(height, force) | height: number, force: boolean | Set explicit iframe height |
sdk.enableResize(enabled) | enabled: boolean | Toggle host auto-resize |
sdk.uiSafe.enableResize(enabled) | enabled: boolean | Safe wrapper for auto-resize toggle |
// After content changes that alter the app height:
sdk.updateHeight();
// After revealing a form that has a known height:
sdk.uiSafe.setHeight(480, true);
Fullsize
| Method | Arguments | Description |
|---|---|---|
sdk.uiSafe.expandFullsize() | — | Expand from compact card into a larger surface |
Declarative actions (rebind)
| Method | Arguments | Description |
|---|---|---|
sdk.rebindActions() | — | Re-scan the DOM for data-shuuka-action="..." elements after dynamic DOM changes |
shkApi Complete Reference
shkApi (also available as window.ShuukaApi) is the stable builder-facing API client. Use it instead of raw fetch() with hardcoded platform routes.
Public endpoints — no authentication required
Use in template.html (profile card) and public/ pages.
Submit an entry
shkApi.public.entries.submit({
formId: 'giveaway', // identifies which form within this app
inputValues: { full_name: 'Jane', email: '[email protected]' },
displayValue: 'jane', // public-safe nickname — never use real name or email here
metadata: { consent: true },
accessToken: token // optional: only when access code gating is active
})
.then(r => r.json())
.then(d => {
if (d.success) // entry recorded — d.entry_id has the ID
if (d.message === 'already_entered') // duplicate — show friendly message
});
Deduplication:
single_entrymode → one submission per email everdaily_entriesmode → one submission per email per calendar day
Read a public storage key
shkApi.public.storage.get('winner')
.then(r => r.json())
.then(d => {
// d.key = 'winner'
// d.value = { display_nickname: 'jane', confirmed: true, confirmed_at: '...' }
// null if key does not exist or is private
});
// Shorthand — just the value:
shkApi.public.storage.getValue('winner').then(r => r.json()).then(d => d.value);
Verify an access code
shkApi.public.access.verify('SUMMER2025')
.then(r => r.json())
.then(d => {
if (d.success) {
const token = d.token; // store in memory ONLY, expires in 15 minutes
}
});
// 401 = invalid code, 429 = too many attempts (5/IP/hour)
Admin endpoints — authenticated (admin pages only)
Use in admin/*.html pages. The bearer token is injected automatically by shkApi.
List entries (paginated)
shkApi.admin.entries.list({ formId: 'giveaway', perPage: 20, page: 1 })
.then(r => r.json())
.then(d => {
// d.data = array of entry objects (input_values decrypted)
// d.meta = { total, per_page, current_page, last_page }
//
// Entry object shape:
// { id, display_value, input_values: { full_name, email }, entry_date }
});
Random draw
shkApi.admin.entries.randomSelect({ formId: 'giveaway', excludeIds: [7, 12] })
.then(r => r.json())
.then(d => {
// d.success = true
// d.entry_id = 45
// d.display_value = 'jane'
// d.total_pool = 141 (eligible entries after exclusions)
});
Export entries as CSV
// Navigate the browser to download the file:
window.location.href = shkApi.admin.entries.exportUrl({ formId: 'giveaway' });
// Or fetch programmatically:
shkApi.admin.entries.export({ formId: 'giveaway' });
Read a storage key (admin — decrypted)
shkApi.admin.storage.get('winner')
.then(r => r.json())
.then(d => {
// d.key = 'winner'
// d.value = { ... }
// d.is_public = true/false
});
shkApi.admin.storage.getValue('winner').then(r => r.json()).then(d => d.value);
Write / update a storage key
shkApi.admin.storage.set(
'winner',
{ display_nickname: 'jane', entry_id: 45, confirmed: true, confirmed_at: new Date().toISOString() },
{ isPublic: true } // isPublic: true makes key readable via the public endpoint
)
.then(r => r.json())
.then(d => { /* d.success */ });
All values are encrypted server-side. Never mark sensitive data (emails, full names) as isPublic: true.
Delete a storage key
shkApi.admin.storage.delete('winner');
Set access code
shkApi.admin.access.set({ code: 'SUMMER2025' });
// Code is bcrypt-hashed before storage — it cannot be retrieved, only verified
URL helpers
When you need a bare URL (e.g. for a download link or a <a href>):
shkApi.raw.publicBaseUrl() // base public route
shkApi.raw.adminBaseUrl() // base admin route
shkApi.public.storage.url('winner') // GET URL for a public storage key
shkApi.public.entries.url() // POST URL for entry submission
shkApi.public.access.url() // POST URL for access code verification
shkApi.admin.entries.exportUrl({ formId: 'giveaway' }) // CSV export download URL
shkApi.admin.storage.url('winner') // GET/PUT/DELETE URL for an admin storage key
Public Page Routing
Files in the public/ subfolder of your bundle are served at:
/platform-app/{appSlug}/{publicId}/{path}
Build a URL to your public result page from inside the app:
var ctx = window.__shuukaCtx || {};
var url = '/platform-app/' + ctx.appSlug + '/' + ctx.publicId + '/public/result';
window.open(url, '_blank');
Public pages receive window.__shuukaCtx with isPublicPage: true. No authentication is injected. Use only shkApi.public.* endpoints on public pages.
Builder Rule
Do not write code against raw internal platform API routes. Use shkApi as the stable builder contract. Internal routes may change; shkApi does not.