App Lifecycle
This page explains how Shuuka initializes and runs an app — from platform bootstrap to runtime readiness.
App Types and Initialization
There are two distinct app execution paths:
| App type | Entry file type | SDK injection | How to use SDK |
|---|---|---|---|
| Simple / Smart HTML app | template.html fragment | Automatic — platform injects and initializes the SDK | Use window.__shuukaCtx and window.ShuukaApi directly |
| React bundle app | index.html shell | Manual — import SDK in source code | Import from @shuuka/sdk/index.sdk.js and use ShuukaProvider |
Simple / Smart App Lifecycle
For apps where runtime_kind is simple or smart:
1. Platform builds the profile page
2. Platform resolves App Instance Settings (groups + placeholders)
3. Platform replaces {{placeholder_key}} tokens in template.html server-side
4. Platform injects window.__shuukaCtx and window.ShuukaApi into the page
5. Platform injects and initializes the Shuuka SDK automatically
6. Your inline <script> runs
7. window.__shuukaCtx and window.ShuukaApi are ready immediately
You can safely read window.__shuukaCtx at any point after your script runs — the context is available synchronously:
(function () {
var ctx = window.__shuukaCtx || {};
var shkApi = ctx.shkApi || window.ShuukaApi;
var title = ctx.fieldValues && ctx.fieldValues.campaign_title || 'Giveaway';
// ... your code
})();
What template.html is
template.html is an HTML fragment, not a full document. It must not contain <html>, <head>, or <body> tags. It is injected as a card inside the profile page.
Use document.currentScript.closest('.your-root-class') to scope all DOM queries to your card — multiple app instances may exist on the same page.
React App Lifecycle
For React bundle apps, the lifecycle has more steps:
1. Platform loads the theme runtime
2. Profile page mounts
3. Platform serves your index.html entry
4. Your HTML shell loads your hashed JS bundle
5. React mounts
6. ShuukaProvider initializes
7. ShuukaProvider sends shuuka:ready to the parent
8. Platform responds with shuuka:ctx containing the full context
9. SDK hooks (useShuuka, useSettings, etc.) become available
10. Your components receive data and render
ShuukaProvider
Wrap your entire React app tree in ShuukaProvider:
import { HashRouter } from 'react-router-dom';
import { ShuukaProvider } from '@shuuka/sdk/index.sdk.js';
export default function App() {
return (
<HashRouter>
<ShuukaProvider autoResize={false}>
<AppContent />
</ShuukaProvider>
</HashRouter>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
autoResize | boolean | true | Whether the SDK automatically recalculates iframe height on render |
children | ReactNode | — | Your app tree |
Set autoResize={false} when you manage height manually via sdk.updateHeight() or sdk.uiSafe.setHeight().
When hooks are safe to call
SDK hooks are only valid inside a component tree wrapped by ShuukaProvider. The hooks wait for the SDK to receive context from the platform before returning live values.
function AppContent() {
const { sdk, uiState } = useShuuka();
const settings = useSettings();
// sdk may be null on the first render, before the platform context arrives.
// Guard accordingly:
if (!sdk) return <div>Loading…</div>;
return <div>{settings?.campaign_title}</div>;
}
SDK Initialization in a React App
If you need the SDK outside of ShuukaProvider (e.g. in an admin page HTML file that bootstraps React), initialize directly:
// In a standalone admin page HTML file
var ctx = window.__shuukaCtx || {};
var shkApi = ctx.shkApi || window.ShuukaApi;
// The platform injects context before </head> in admin pages,
// so shkApi is available synchronously when your script runs.
For React admin pages that use ShuukaProvider, the same rules apply as above.
Admin Page Lifecycle
Admin pages are full HTML documents injected inside the owner's authenticated dashboard:
1. Owner opens the app admin area
2. Platform selects the tab and loads the HTML file declared in admin_pages[].entry
3. Platform injects window.__shuukaCtx (with accessToken) before </head>
4. Platform injects window.ShuukaApi before </head>
5. Your page scripts run
6. context and shkApi.admin.* are ready immediately
The bearer accessToken inside window.__shuukaCtx.accessToken is the same token shkApi.admin.* uses automatically. Do not extract and reuse it manually.
Public Page Lifecycle
Public pages live at /platform-app/{slug}/{publicId}/{path} and are served to unauthenticated visitors:
1. Visitor navigates to the public page URL
2. Platform serves your file from public/ inside the bundle
3. Platform injects window.__shuukaCtx with isPublicPage: true (no accessToken)
4. Platform injects window.ShuukaApi (public-only methods work; admin methods fail)
5. Your page scripts run
Only shkApi.public.* methods are valid on public pages. Calling shkApi.admin.* from a public page will return 401 Unauthorized.
Dev Mode Lifecycle
Dev mode bypasses the normal bundle serving and proxies your local dev server:
1. Owner opens a profile or admin page with ?dev_theme active (or dev app registered)
2. Platform fetches your local file (template.html or admin/page.html) server-side
3. Platform injects window.__shuukaCtx and window.ShuukaApi into the <head>
4. Platform serves the combined HTML through its own origin
5. Your scripts run — context is available immediately, no handshake needed
Your local dev server must be running and reachable from the API server. The backend fetches with a 5-second timeout.
Read Developer Mode for setup and limitations.
Key Lifecycle Facts
| Fact | Details |
|---|---|
| Context injection timing | window.__shuukaCtx is available synchronously when your script runs in simple/smart apps and admin pages. In React apps, context arrives via shuuka:ctx postMessage after ShuukaProvider mounts. |
| Template tokens are server-side | {{placeholder_key}} replacements happen before the page is served. No async call is needed for the initial render. |
| SDK is injected, not imported, in simple apps | Do not add a script tag for the SDK in template.html for simple/smart apps. The platform injects it. |
| Admin pages use full HTML | admin/*.html must have <!DOCTYPE html>, <head>, and <body>. They are not fragments. |
| Public pages are unauthenticated | accessToken is never present on public pages. Only shkApi.public.* works. |
document.currentScript scope | In template.html, always use document.currentScript.closest('.your-root') — never document.querySelector('.your-root') without scoping. |
Troubleshooting Initialization
See Troubleshooting for common issues such as context not being injected, SDK hooks returning null, and API calls failing with 401.