Skip to main content

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

SourceAvailable inUse it for
SDK hooks (useShuuka(), etc.)React apps onlyUI state, settings, field values
window.__shuukaCtxAll app typesRuntime context, field values, shared profile payload, API base URL
window.ShuukaApi / window.shkApiAll app typesStorage, entries, access codes
{{placeholder_key}} template tokensSimple/smart template.html onlyInstance 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

KeyProfile cardAdmin pagePublic pageDev mode
appSlug
publicId
billboardAppId
apiBaseUrl
fieldValues
profile
locale
themeMode
isPublicPagefalsefalsetrue
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.profile or window.shuukaConfig.profile
  • smart apps: window.__shuukaCtx.profile or window.shuukaConfig.profile
  • native apps: props.profile in React mounts, mirrored from data-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

KeyTypeDescription
profile.public_idstringPublic profile identifier
profile.nicknamestringPublic handle without @
profile.display_namestringBest display name fallback for the owner
profile.descriptionstringLocalized profile description for the current locale
profile.avatar_urlstringResolved avatar URL
profile.categorystringResolved category label
profile.is_verifiedbooleanVerification status
profile.subscription_planstringCurrent plan, e.g. free, pro, enterprise
profile.current_localestringLocale used to resolve localized fields
profile.available_localesstring[]Available locales when known
profile.locationobjectOptional 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();
KeyTypeDescription
sdkobjectMain SDK instance with UI helpers
uiStateobjectCurrent embed mode, fullsize, and modal state
configobjectRuntime configuration from the host
contextobjectInstalled-app context and metadata

uiState fields

FieldTypeDescription
uiState.isOpenbooleantrue when the app is inside an open modal
uiState.isFullsizebooleantrue when the app is in fullsize mode
uiState.embedModestringCurrent 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();
KeyTypeDescription
valuesobjectCurrent resolved field values
saveValues(updates)functionPersist field value updates
refresh()functionRe-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

MethodArgumentsDescription
sdk.openModal(url, title, mode)`url: string, title: string, mode: 'default''fullscreen'`
sdk.openModal({ route, title, mode, query })options objectOpen 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

MethodArgumentsDescription
sdk.updateHeight()Re-measure the iframe height from the current DOM
sdk.uiSafe.setHeight(height, force)height: number, force: booleanSet explicit iframe height
sdk.enableResize(enabled)enabled: booleanToggle host auto-resize
sdk.uiSafe.enableResize(enabled)enabled: booleanSafe 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

MethodArgumentsDescription
sdk.uiSafe.expandFullsize()Expand from compact card into a larger surface

Declarative actions (rebind)

MethodArgumentsDescription
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_entry mode → one submission per email ever
  • daily_entries mode → 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.