Skip to content

Example apps ​

The eleven examples in civitai/civitai-app-starters are the maintained example set: one small, runnable app per feature area, each with its own block.manifest.json, src/ and README. They depend on the published @civitai/app-sdk / @civitai/blocks-react releases, and that repository's CI typechecks and builds every one, runs civitai app validate --strict on each, and boots each under dev:harness in Chromium to check it renders. Start here. Each README explains the feature and the gotchas built into it, and says where the local mock host differs from production.

Further down, More real-world apps lists larger public apps that are not maintained as examples. Read those once you know the basics.

Each entry below states what was read out of the example itself: the scopes its block.manifest.json declares and the hooks it imports from @civitai/blocks-react.

What is gated today

The examples run anywhere under dev:harness. On civitai.com, the example READMEs say plainly what is closed, and each one cites the civitai source it read:

  • The App Blocks runtime is an invite-only, closed beta. Every spend and bridge call checks the per-user app-blocks-enabled flag (generation-kinds, generate-studio). During the pre-GA preview the host API is enabled per account, so an approved app can still be refused for an account that was never enrolled (kv-storage).
  • Page apps are behind a moderator-only flag. /apps/run/<slug> needs both appBlocks and appBlocksPages, and appBlocksPages is currently limited to moderators (page-app).
  • The legacy shared storage is flag- and approval-gated. Every call, reads included, needs the app-blocks-shared-storage flag (off by default, on for a limited cohort), the app must be approved, and the shared scopes are refused under dev:live (shared-board).
  • kind: 'training' is not available to apps. The host refuses it unless the app-blocks-training-kind flag is on, and that flag is false when unset (generation-kinds).
  • Goods need an approved app. A good and its price come from the latest approved manifest; before approval the purchase route answers 404 (monetize).
  • Posting to a viewer's profile from an app is off for everyone, moderators included (generate-studio).

This list summarises the READMEs at civitai-app-starters ed7d69c. The READMEs are the authority, and gates change.

Eight of the eleven are slot apps

hello-world, settings, buzz-workflow, kv-storage, scopes-api, buzz-purchase, shared-board and monetize render in the model.sidebar_top slot. Concepts explains that slot apps are deferred for third-party builders, so ship a page app: page-app shows the shape, and generate-studio and generation-kinds are page apps that generate. Read the slot examples for the feature they show. One difference to carry over: a slot app's per-generation budget is the buzz_budget_per_gen setting, while a page app sets page.buzzBudgetPerGen in its manifest (buzz-workflow).

Running an example ​

Copy one out on its own, the way you would start a real app from it:

bash
EXAMPLE=hello-world   # any directory name below
npx tiged "civitai/civitai-app-starters/starters/examples/$EXAMPLE" my-block
cd my-block
npm install
npm run dev:harness   # each example pins its own port, listed under its entry

Inside a clone of the starters monorepo, run pnpm install at the root, then pnpm dev:harness in the example's directory.

dev:harness runs the example against the SDK's mock host, with the manifest's scopes passed as declaredScopes. No token and no .env is needed. URL knobs such as ?theme=light and ?viewer=anon change what the mock host sends.

dev:live runs the same example against the real backend with a dev token. Local development covers minting one with civitai app dev-token. The mint is invite-only before GA, and an example that spends needs --spend. It spends your own real Buzz. Some host capabilities are refused in live mode rather than faked; each entry below names the ones that matter for that example.

Pick one ​

If you want to see…Start with
the smallest complete block: lifecycle, theming, resizehello-world
a full-page app: routes, breakpoints, sign-in and consentpage-app
manifest settings and the SettingsForm componentsettings
estimate → submit → poll for a generation, with Buzz billedbuzz-workflow
a real generator page: pickers, LoRAs, img2img, history, publishgenerate-studio
customComfy recipes and chat completions through the same money flowgeneration-kinds
topping up a viewer's Buzz mid-flow, and when not tobuzz-purchase
a per-viewer key-value store (useAppStorage)kv-storage
a cross-viewer shared store (useSharedStorage)shared-board
declared vs granted scopes, and calling REST with the block tokenscopes-api
selling digital goods, gating on entitlements, taking tipsmonetize
many generations in flight at once, with per-cell retryGen Matrix
a multi-turn LLM chat driven by the generation bridgeSensei
the App Blocks HTTP API with collections and tipping scopesPlayable Collections
no React at all: Web Components on the raw transportPanorama 360

The starters examples ​

hello-world ​

starters/examples/hello-world — slot app. Read this first.

Shows the block lifecycle: the host's trust frame, the ready gate before BLOCK_INIT, useBlockResize fitting the iframe to its content, and theming the block itself, dark first, from the host's theme.

  • Scopes — models:read:self
  • Hooks — useBlockContext, useBlockResize
  • Run — npm run dev:harness → localhost:5180

settings ​

starters/examples/settings — slot app.

Shows manifest-declared settings with publisher and viewer scope, reading them from useBlockContext().settings, filling in manifest defaults the host does not send, and the headless SettingsForm from @civitai/blocks-react/ui.

  • Scopes — models:read:self
  • Hooks — useBlockContext, useBlockResize
  • Run — npm run dev:harness → localhost:5181. The mock host sends empty settings, so you see the manifest defaults.

buzz-workflow ​

starters/examples/buzz-workflow — slot app.

Shows the money path: useBuzzWorkflow estimate → submit → poll, one shared body builder so the estimate prices what the submit sends, branching on WorkflowEstimateError.code, caller-driven polling, and a real server-side cancel. Copy it for any generation UI.

  • Scopes — models:read:self, ai:write:budgeted
  • Hooks — useBuzzWorkflow, useBlockContext, useBlockResize
  • Run — npm run dev:harness → localhost:5182, with no Buzz spent. dev:live spends your own Buzz.

kv-storage ​

starters/examples/kv-storage — slot app.

Shows useAppStorage, a key-value store per block instance and viewer: get / set / delete / list / getQuota, the byte and row ceilings, classifying a rejection with classifyAppStorageError, and the anonymous-viewer case.

  • Scopes — models:read:self, apps:storage:read, apps:storage:write
  • Hooks — useAppStorage, useBlockContext, useBlockResize
  • Run — npm run dev:harness → localhost:5183. App Storage refuses under dev:live; the README explains why.
  • Deprecated store — useAppStorage is superseded by a private collection of the document store; it keeps working while apps move.

scopes-api ​

starters/examples/scopes-api — slot app.

Shows declared versus granted scopes, and calling a scope-gated REST endpoint (GET /api/v1/blocks/me) with the block token as a Bearer, sent only to useHostOrigin(), with 401 → refresh → retry once.

  • Scopes — user:read:self, models:read:self
  • Hooks — useBlockToken, useHostOrigin, useBlockContext, useBlockResize
  • Run — npm run dev:harness → localhost:5184. The call returns 401 under the mock token by design; dev:live returns real data.

buzz-purchase ​

starters/examples/buzz-purchase — slot app.

Shows useBuzzPurchase opening the purchase modal when the wallet is short, then retrying with guards. It separates the two limits: buying Buzz raises the wallet (useBuzzBalance), never the per-generation budget on the token.

  • Scopes — models:read:self, ai:write:budgeted, buzz:read:self
  • Hooks — useBuzzPurchase, useBuzzBalance, useBuzzWorkflow, useBlockContext, useBlockResize
  • Run — npm run dev:harness → localhost:5185. The live host refuses the purchase modal, so test the purchase under the harness.

shared-board ​

starters/examples/shared-board — slot app.

Shows useSharedStorage, one app-wide store every viewer reads: append, vote, author-only edit and withdraw, report. A private draft in useAppStorage sits beside it, so the two stores' differences are on screen. Shared storage is flag- and approval-gated (see the box above).

  • Scopes — user:read:self, apps:storage:shared:read, apps:storage:shared:write, apps:storage:read, apps:storage:write
  • Hooks — useSharedStorage, useAppStorage, useViewer, useRequestSignIn, useRequestConsent, useBlockToken, useBlockContext, useBlockResize
  • Run — npm run dev:harness → localhost:5187. This is the only local way to run it: the shared scopes are refused under dev:live.
  • Deprecated store — useSharedStorage is superseded by a shared collection of the document store; it keeps working while apps move.

page-app ​

starters/examples/page-app — page app.

Shows the shape most third-party apps ship: a manifest page with no targets, full width from 375px to 2560px with useBlockBreakpoint, app-scoped routes with useCivitaiRoute and useCivitaiNavigate, and sign-in → consent → useViewer. src/main.tsx wraps the app in <BlockGate>. Page apps are mod-only today (see the box above). It also declares its six useBlockAnalytics events under analytics.events in its manifest, the declaration the platform records custom events against.

  • Scopes — user:read:self, apps:storage:read, apps:storage:write
  • Hooks — useBlockBreakpoint, useCivitaiRoute, useCivitaiNavigate, useHostOrigin, useRequestSignIn, useRequestConsent, useConsentUnavailable, useBlockToken, useViewer, useAppStorage, useBlockAnalytics, useBlockContext
  • Run — npm run dev:harness → localhost:5186. Under dev:live its storage calls are refused, as for every app (why), so exercise storage under dev:harness.

generate-studio ​

starters/examples/generate-studio — page app, the largest example.

Shows real image generation in a page app: checkpoint and LoRA pickers, setup codes, txt2img and img2img, a debounced quote, budget versus wallet, a queue of runs with watch and cancel, the app's own history, publishing outputs, and showing them only as far as the viewer may see them. Its README is a numbered tour of the files. For the multi-LoRA pattern it implements, see Building a LoRA stack.

  • Scopes — ai:write:budgeted, buzz:read:self
  • Hooks — useCheckpointPicker, useResourcePicker, useGenerationResources, useImageUpload, useBuzzWorkflow, useBuzzBalance, useBuzzPurchase, useAppWorkflows, usePublishGenerationOutputs, useGatedImages, useDomainMaturity, useSaveImage, useRequestConsent, useRequestSignIn, useBlockContext, useBlockResize
  • Run — npm run dev:harness → localhost:5188. dev:live spends your own Buzz, and the live host refuses consent, upload, purchase, publish and save.

generation-kinds ​

starters/examples/generation-kinds — page app.

Shows the WorkflowBody kinds beyond textToImage through the same money flow: a registered customComfy recipe and a multi-turn step / chat-completion chat, both page-only, plus useWildcardPack and the sign-in → consent → spend gate. It explains why training is left out.

  • Scopes — ai:write:budgeted
  • Hooks — useBuzzWorkflow, useWildcardPack, useRequestSignIn, useRequestConsent, useConsentUnavailable, useBlockToken, useBlockContext, useBlockResize
  • Run — npm run dev:harness → localhost:5189. The mock host has no text channel, so chat replies appear only under dev:live, which spends your own Buzz.

monetize ​

starters/examples/monetize — slot app.

Shows how an app earns: selling manifest-declared digital goods with useGoodPurchase, gating a feature on useEntitlements in a safe order, and tips with useTip and TipButton. It also says which money rails pay nothing today. Read it with How an app earns.

  • Scopes — goods:read:self, goods:purchase:self, social:tip:self
  • Hooks — useGoodPurchase, useEntitlements, useTip, useTipAllowance, useRequestSignIn, useBlockToken, useBlockContext, useBlockResize
  • Run — npm run dev:harness → localhost:5190. Under dev:live a tip moves your own real Buzz, and your own purchases are refused as self_purchase.

Hook lists verified by hand on 2026-10-07 against civitai-app-starters ed7d69c, from each example's @civitai/blocks-react imports. The scope lists are checked daily (see Keeping this list honest).

More real-world apps ​

Eight Civitai App Blocks maintained outside the starters repository, with public source. They are whole working apps rather than examples, and each shows a part of the platform end to end that the starters examples keep small.

About these repositories

They are individually maintained working apps, not a curated, supported sample set: seven are maintained outside the civitai organization and one inside it. Treat them as references to read, not as an API contract. The reference pages are the contract, and the server is the enforcement boundary.

Verified 2026-10-16: all eight are public, not forks, and not archived. Their scopes are checked daily like the starters examples'. Hook lists verified by hand on 2026-10-16, from each repository's default branch. Read them as a snapshot of that day; the repository is always the authority.

Seven of the eight now import no hooks from @civitai/blocks-react: they call the platform through @civitai/sdk and keep their own same-named hooks (useBuzzWorkflow, useBlockContext, …) in a file of their own, named on each entry. Those entries list an SDK surface — what the app imports from the published packages — instead of a hook list.

Gen Matrix ​

github.com/ZacxDev/civitai-app-gen-matrix — page app.

Read it for a fan-out generation grid: many priced workflows in flight behind one cost estimate and confirm step, with retry scoped to the failed cells.

  • Scopes — ai:write:budgeted, apps:storage:read, apps:storage:write, apps:storage:shared:read, apps:storage:shared:write
  • SDK surface — createHost, initialize, BridgeError (@civitai/sdk); getTransport, sendTypedRequest (@civitai/blocks-react); its hooks are its own, in src/lib/sdk-runtime.ts

Sensei ​

github.com/ZacxDev/civitai-app-sensei — page app.

Read it for a multi-turn LLM assistant on the generation bridge, whose replies drive follow-up catalog queries, with per-user conversation state.

  • Scopes — ai:write:budgeted, buzz:read:self, apps:storage
  • SDK surface — createHost, initialize (@civitai/sdk); getTransport, sendTypedRequest, WorkflowEstimateError, WorkflowSubmitError (@civitai/blocks-react); its hooks are its own, in src/lib/sdk-runtime.ts

Model Benchmarking ​

github.com/ZacxDev/civitai-app-model-benchmarking — page app.

Read it for a priced generation run whose outputs are published into a shared store every viewer reads and writes: the one app here that still runs generation, publishing and gated images through @civitai/blocks-react hooks, next to @civitai/sdk for the rest.

  • Scopes — ai:write:budgeted, buzz:read:self, apps:storage, apps:storage:publish
  • Hooks — useBuzzWorkflow, usePublishGenerationOutputs, useGenerationResources, useResourcePicker, useGatedImages, useCivitaiNavigate, useBlockAnalytics

Playable Collections ​

github.com/ZacxDev/civitai-app-playable-collections — page app.

Read it for privileged reads and writes over the App Blocks HTTP API (/api/v1/blocks/*, block token as Bearer) rather than postMessage hooks, behind one swappable ApiClient the dev harness fakes.

  • Scopes — collections:read:self, collections:read:private, social:tip:self, buzz:read:self, apps:storage:read, apps:storage:write, apps:storage:shared:read, apps:storage:shared:write, apps:storage
  • SDK surface — createHost, initialize (@civitai/sdk); getTransport, sendTypedRequest (@civitai/blocks-react); its hooks are its own, in src/lib/sdk-runtime.ts

Custom Generators ​

github.com/ZacxDev/civitai-app-custom-generators — page app.

Read it for an author → publish → discover → run lifecycle inside one block, with a spend path that can top the viewer up mid-flow, and img2img via useImageUpload.

  • Scopes — ai:write:budgeted, buzz:read:self, apps:storage:read, apps:storage:write, apps:storage:shared:read, apps:storage:shared:write, posts:write:self, apps:store:items:write
  • SDK surface — initialize, getTransport, ApiError (@civitai/sdk); no @civitai/blocks-react dependency; its hooks, useImageUpload among them, are its own, in src/platform/hooks.ts

App Requests ​

github.com/ZacxDev/civitai-app-requests — page app.

Read it for a cross-user post / vote / edit / withdraw board on a shared document-store collection, with no Buzz or generation scope at all.

  • Scopes — apps:storage, apps:storage:publish, user:read:self
  • SDK surface — initialize, StorageError (@civitai/sdk, its document store); no @civitai/blocks-react dependency; its hooks are its own, in src/platform/hooks.ts

Generate from Model ​

github.com/ZacxDev/civitai-block-generate-from-model — slot app.

Read it for a model.sidebar_top slot app that takes the model from host-injected context (requiredContext: ["modelId", "modelVersionId"]) and reads publisher settings through useBlockSettings. Slot apps are deferred for third-party builders, as above.

  • Scopes — models:read:self, ai:write:budgeted, buzz:read:self
  • SDK surface — initialize, getTransport, ApiError (@civitai/sdk); no @civitai/blocks-react dependency; its hooks, useBlockSettings among them, are its own, in src/platform/hooks.ts

Panorama 360 ​

github.com/civitai/app-panorama-360 — page app, no React.

Read it for proof that the block contract does not require React: Web Components on the raw transport, and Comfy on Civitai wired into a real app via @civitai/comfy-run-kit.

Starting a no-React app today? Use the published elements

Panorama 360 predates the published <civitai-*> elements, which is why it defines its own. A new app does not need to: civitai app init now scaffolds a React-free app on @civitai/sdk and the @civitai/components elements by default. Read Panorama 360 for the transport and the Comfy wiring, and start from the Quickstart and the elements guide for the UI.

  • Scopes — ai:write:budgeted
  • SDK surface — getTransport, sendTypedRequest (@civitai/blocks-react); BlockWorkflowSnapshot, WorkflowBody, BuzzAccountType (@civitai/app-sdk/blocks); RunController, BridgeGateway, registerRunElements (@civitai/comfy-run-kit)

Reading one of these next to the docs ​

The examples are whole applications, so here is the shortest path from one back to the contract it uses:

If you are not building yet, Quickstart scaffolds a working page app with the civitai CLI.

Keeping this list honest ​

A daily check reads back each of the eight external repositories linked here and flags one that has been renamed, archived or removed, compares every scope list above with that example's block.manifest.json, and flags a starters example that has no section on this page. The hook lists are checked by hand, which is why each carries the date it was last verified.

Civitai Developer Documentation