Build, ship, learn
Belfort generates production-ready WebView paywalls and runs the analytics and remote-config backend that serves them. The path from a source app to a live release is one loop: generate, publish, activate, and measure.
http://localhost:9300; the default development password is change-me.Run Belfort locally
From the repository root, copy the local defaults, install the workspaces, start the complete Docker stack, and prepare Postgres and ClickHouse.
cp .env.example .env npm install docker compose -f docker-compose.yml -f docker-compose.full.yml -f docker-compose.minio.yml up -d --build npm run db:migrate npm run ch:migrate npm run db:seed:docker
Generate a paywall
Build the @belfort/cli workspace and its dependencies, save your model credential once, then point Belfort at an iOS, Android, Capacitor, React Native, Flutter, or Unity source tree. The generated release is written to ./paywall-out.
npx turbo run build --filter=@belfort/cli... node packages/cli/dist/cli.js init node packages/cli/dist/cli.js run ./path/to/your/app --out ./paywall-out
Publish and activate
Publish the generated bundle with a management secret and activate it in the same command. The seeded key below is product-scoped. With an organization-scoped key, also pass --product <slug-or-id>.
BELFORT_SECRET=bsk_dev_write_secret \ BELFORT_ENDPOINT=http://localhost:9400 \ node packages/cli/dist/cli.js publish ./paywall-out --activate
Install the SDK
Open a product in the dashboard, choose Info → Install, select the target platform, and download the stamped integration archive. The same screen includes copyable, product-specific instructions and the public client key.
- iOS ships a local Swift package that hosts the paywall in a WKWebView.
- Android ships a Kotlin library that hosts the bundle in a WebView.
- React Native, Capacitor, Flutter, and Unity currently receive an HTTP integration kit.
INTEGRATION.md and the dashboard Install tab come from the same source, so the platform instructions and credentials stay aligned.Calls to action
Restore purchases, Terms, and Privacy have no Hide option in the dashboard editor. Each one can be left at its default, handed to your app, bound to a URL, or bound to another paywall.
Restore uses the Belfort SDK by default. The SDK runs its configured billing restore path and reports the outcome. Other unbound actions are returned to your app; the SDK does not open a page or present another paywall for them:
- With the standard Swift configuration, automatic billing restores through RevenueCat when configured, otherwise StoreKit.
- Terms, privacy, and any other unbound action arrive on
onCtawith that action's key (terms,privacy, or a custom id from the design). - Restore set to Unbound — app handles it arrives there too, as
restore. Use it when your app runs its own restore flow; the SDK stays out of the way and reports nothing of its own.
Bind to Open URL or Open paywall only when Belfort should own the tap. Declared custom controls can also be hidden; built-ins have no Hide option in the dashboard editor. Wire app-handled actions in the SDK configuration:
onCta: { id in
switch id {
case "restore": runMyOwnRestore()
case "terms": openTerms()
case "privacy": openPrivacy()
default: break
}
}Client and secret keys
The public client key starts with bk_. It identifies one product, ships in the app, and is sent as the belfort-client-id header for config and telemetry requests.
Management secret keys start with bsk_. They can publish bundles and mutate Belfort resources, so they belong only in trusted server or CLI environments—never in a mobile app.
Fetch config and report events
The native SDKs derive /v1/config and /v1/track from the API base URL. HTTP-kit integrations call the same endpoints directly with the product's public client key.
GET http://localhost:9400/v1/config?platform=ios&deviceId=device-123 belfort-client-id: bk_… POST http://localhost:9400/v1/track belfort-client-id: bk_… content-type: application/json
Belfort skills
Install the belfort management skill to give supported coding agents the CLI commands, authentication rules, and resource model for operating a Belfort deployment.
npx skills add blubblub/Belfort --skill belfort -g
The source is skills/belfort/SKILL.md. A global install is stored at ~/.agents/skills/belfort/ and made available to the agents you select.
Paywall design skills
Generation and critique skills ship with the CLI under packages/cli/skills/, so they need no separate install. belfort run exposes them read-only inside each generated workspace at .scratch/.claude/skills/.
Core concepts
Products and paywalls
A product represents one app. Its paywalls are versioned generated bundles that Belfort can publish, activate, and measure independently.
Triggers and experiments
A trigger is a named placement such as onboarding or feature_unlock. Experiments split a trigger's traffic across paywall variants and record conversion and revenue for each one.
Release notes
Every tagged release, newest first. The dashboard shows each of these once, the first time you sign in after it ships; this is where they stay.
0.2.0 — release: 0.2.0 27 August 2026
New
- Rebuild a published paywall on today's runtime without touching its design
- Answer a failed purchase, and let a paywall own its restore and legal links
- Backfill every paywall version's own layout tree
- Ask for the work email on the Belfort sign-in page
- Shrink the paywall corpus to transcript-free latest versions
- Test the builder harness against the production paywall corpus
- Edit any paywall, including one the agent wrote
- Run custom HTML embeds in the app, and style text elements one at a time
- Paste custom HTML blocks in the paywall editor
- Style every text element in the paywall editor
- Open legacy paywall versions in the editor
- Add the visual paywall editor
- Terraform the horizontally-scaled architecture + rehearsal runbook
- Upgrade the dashboard to Next.js 16 LTS and React 19
- Move "Report a bug" into the sidebar, under Documentation
- Report every crash to Sentry and let anyone report a bug from any page
- Log every defect users hit and file it as a GitHub issue
- Show everyone what shipped since they were last here
- Give member rows one actions menu and roles that save themselves
Fixed
- Resolve a RevenueCat SKU that is not on the current offering
- Speak a failed purchase in the host locale, not English
- Keep the preview iframe attached when its source changes
- Stop a bound restore, terms or privacy from vanishing on its way to the paywall
- Rebuild a saved design that imports its art through the reference tree
- Let a paywall switch to any of its versions, not just the two the gates allowed
- Open the editor on the version's own layout, never its skeleton default
- Let the version's own layout drive a rebuild, not its skeleton id
- Keep a paywall's final selection in step with the version it serves
- Land a chat edit on a paywall that kept no editable source
- Seed the chat SKU picker from the version, not the whole catalog
- Harden paywall generation verification
- Stop local runs reporting into the production Sentry project
- Keep versions editable when the templates move on
- Accept the footer chrome the visual scrim actually receives
- Let the paywall templates keep their own React 18 types
- Edit paywall text in its own font, not the dashboard's
- Restore the skeleton fidelity check
- Key the editor canvas cache on the templates it was built from
- Stop editor banner borders from rendering as white lines
- Cache /v1/config resolution snapshots and public API keys in Redis
- Stop cold navigations from stalling the dashboard
- Wait for every agent question before marking a version ready
- Keep paywall headlines free of placeholder tokens
- Keep the dashboard shell mounted and stop blocking tabs on Logto and ClickHouse
- Send an expired session to the sign-in page instead of an error page
0.1.0 — First tracked release 13 August 2026
New
- Verify every built paywall shows Restore purchases
- Raise the agent's questions in the chat that asked them
- Test a paywall's placeholders from the chat preview
- Show the submitted refinement immediately in the paywall chat
- Match loading skeletons to each page and cover remaining routes
- Show instant loading states on dashboard navigation
- Carry preview placeholder values in the preview URL
- Add personalized paywalls and remote SDK delivery
- Show a run in progress wherever the agent is working
- Give invited people a row and a role
- Keep generation failures as cases and replay them
- Add the plan slots an instruction asks for
- Let an organization have several owners
- Resend a pending invitation
- Mail team invitations through Resend
- Spin the organization switcher while it switches
- Grey the set's language save while an experiment holds it
- Hold a paywall still while an experiment runs on it
- Put any SKU in any paywall slot
- Spin the preview while it reloads
- Pick languages as pills you can search, tick and drop
- Give organizations a page of their own to be born on
- Serve one paywall in many languages
- Add multi-tenant accounts and organizations backed by Logto
- Answer memory questions from the overview, with Other always offered
- Answer open memory questions over the agent chat
- Quick-answer open memory questions inline or via the agent
- Raise unanswered memory questions in the agent pane
- Edit product SKUs from the product overview
- Show product SKUs on the product overview
- Make paywall SKU slots editable
- Make an unset SKU store prompt the user to set it
- Type each SKU by billing system and route it at purchase time
- Let the agent write product SKUs into product memory
- Enforce SKU realization before paywall confirmation
- Drop SKUs that have no slot in the design instead of failing
- Replace Claude Opus 4.8 with Claude Opus 5 in the agent catalog
- Make Verify again an agent harness run, not a quick check
- Verify that every SKU also has a plan slot in the design
- Verify a version's SKU integrity again from the preview pane
- Render the builder preview from the SKU selection, gated to sell at least one
- Main-first SKU slots with design-adaptive dropdowns below the preview
- Hover SKU overlay with click-to-toggle in the version preview
- Select SKUs when building the next paywall version
- Support multiple connected users
- Move provider API keys from products to the organization
- Retire repo source scans and auto-resolve superseded paywall reviews
- Animate modal transitions
- Mark versions that have a saved editable source
- Land on the final version's versions tab after removing a version
- Recommendations review page, deduped scan confirmations, real scan CTA
- Allow removing a non-final version from a paywall
- Rebuild source-less refine bases from their saved design
- Move new-version action into paywall overflow menu
- Move documentation above account menu
- Add agent image tools and provider BYOK
- Refresh docs and Belfort identity
- Preview all experiment variants on live triggers, restyle Live pill
- Show live paywall preview on trigger detail page
- Per-turn agent model picker in the paywall chat composer
- Persist agent chat conversations with history and resume
- Keep paused needs_input runs visible in the Agent card
- Show animated agent working dots
- Rebuild the CLI as `belfort` with full management API coverage
- Add secret-key management REST API over the full surface
- Redesign agent chat composer
- Add product agent chat with configurable model
- Add organization GitHub integrations
- Complete GitHub product source flow
- Refine Belfort brand mark
- Redesign Belfort public site
- Add public Belfort docs
- Add public Belfort landing page
- Move sign out into user menu
- Add persistent MinIO storage for local Docker
- Drive any paywall change from a chat instruction (brief-steer)
- Honor user colour steering prompts in generation and refine
- Restore the Agent panel above paywalls, matched to the reference
- Make paywall rows open on click, drop the Open button
- Redesign product screen to top metrics + trigger-grouped paywalls
- Visual wireframe thumbnails for the template picker
- Redesign the create-paywall dialog as a 4-mode chooser
- Title the new-paywall dialog "Create a new Paywall"
- Simplify the create dialog; generate from a prompt or skeleton alone
- Generate from a reference paywall alone (no app source)
- Allow changing the final version until the paywall is serving
- Version selector spans the whole set, not one conversation
- Pin chat messages to the bottom of the conversation
- Make the paywall chat panel fill the viewport
- Bigger preview, collapsible rail, pinned versions strip
- Chat-first paywall set page with always-on preview
- One paywall with many versions + confirm→ship lifecycle
- Attach image/video/audio files to the Improve chat
- Analyze a dropped paywall image and confirm choices before generating
- Drag-and-drop zone for the paywall source upload
- Merge Versions into the Improve tab
- Branching "Improve" conversations with history
- Redesign the paywall tab bar as a segmented control
- Chat to iteratively improve a draft paywall
- Cross-app reference design templates + GitHub product source
- Log every paywall generation in the agent feed
- Inject product SKU prices via a synthetic .storekit
- Trigger paywall generation from a source-code upload
- Three backend trigger placements with distinct paywalls
- Group the product paywall list by trigger
- Product triggers (named placement slots) with per-trigger A/B
- Device-accurate paywall preview with device selector
- Live paywall preview beside the funnel
- Paywall.remote variant + fix nested bundle-asset upload paths
- Add server-side analytics + remote-config backend (npm workspaces + Turborepo)
Fixed
- Show a spinner while a paywall conversation loads
- Stop refusing refinements over the SKU catalog
- Open list rows in a new tab on cmd-click
- Show progress while confirming paywalls
- Make multi-plan paywall refinements reliable
- Auto-repair paywalls that miss the highlighted SKU
- Stop pinning the base skeleton on paywall refinements
- Keep one-plan skeletons out of multi-plan paywall designs
- Span the chat SKU slot pickers across the product's version catalog
- Accept sibling-version SKUs in paywall refinement and slot switching
- Keep loading skeletons visible and anchor the spinner in the topbar
- Make the ClickHouse paywall vocabulary migration runnable
- Let a retry keep the request it is retrying
- Stop cutting a design down to one plan
- Fill an asked-for period once, not with every SKU that shares it
- Ask a design for one plan slot, not for an exact set
- Only refuse a localhost invite link when it is really wrong
- Tidy the members panel — one row of actions, no self-recovery
- Point invite links at the dashboard, not localhost
- Let the slots switch between every SKU the product sells
- Stop the empty additional-SKUs box overflowing its border
- Keep the additional-SKU list from swallowing the save click
- Stop product memory restating the product's locales
- Save languages with the control the SKU card uses
- Preview only the languages the paywall actually serves
- Show a SKU the same way wherever it is picked
- Let people answer product questions the way they actually talk
- Give the agent chat enough turns to answer from source
- Answer the user when the agent omits the action key
- Support configured RevenueCat package SKUs
- Label the paywall Versions tab "Design"
- Show "Not set" for a SKU with no billing system
- Use the shared Select for the SKU billing system
- Merge agent SKU writes and record them as agent_chat
- Label verification harness as rebuild
- Allow switching restored SKUs in previews
- Disable cleared paywalls without archiving
- Restore provider key vertical stack
- Open failed agent conversations
- Handle deleted paywall lineage roots
- Let maintained repo-scan confirmations surface in Needs confirmation
- Record the failure activity last so feeds show failed generations as failed
- Keep saved paywall sources self-contained
- Shorten completed activity copy to "Paywall complete"
- Headline agent activity rows with the action, not the source
- Derive Needs Confirmation from live state, not activity events
- Scan push webhooks only for repositories that source a product
- Read product source through GitHub integration
- Connect existing GitHub installation
- Show source save progress
- Remove all E2E product artifacts
- Show readable experiment language labels
- Default agent activity to five rows
- Make paywall bundle publishing durable
- Remove topbar platform chip and product-header API keys link
- Render the template wireframes with literal colors
- Show the whole paywall in version thumbnails
- Stop badging confirmed paywall versions as DRAFT
- Review queue is per paywall, not per version
- Org-scope paywall-generation procedures and harden uploads
- Correctness, security & reliability fixes from review
- Hide preview scrollbars, nest screen in bezel corners
- Serve the active seed paywall bundle in dev
- Keep the backend paywall closable on notched devices