Craftkitdocs

Admin UI & class catalogue

Stable .ck-* class names you can target for theming.

07 — Embed Admin UI

The partner-facing surface for managing their embed integration.

Lives at app.craftkit.dev/dashboard/{projectSlug}/embed/* once the project is in embed-partner mode.

Information architecture

Project › Embed
  ├─ Overview                  (status + setup checklist + activity)
  ├─ Configuration
  │   ├─ Keys                  (publishable, secret, signing)
  │   ├─ Allowed Origins       (CSP + CORS)
  │   ├─ Catalogs              (named, versioned, diffable)
  │   ├─ Permission Presets    (admin/editor/viewer roles)
  │   └─ Embed Webhooks        (separate from regular webhooks)
  ├─ Sessions                  (live console + session inspector)
  ├─ Usage & Billing
  │   ├─ This period
  │   ├─ Tenants               (per-tenant breakdown)
  │   ├─ Bill-back attribution
  │   ├─ Plans & limits
  │   └─ Invoices
  └─ Test Embed                (sandbox to play with the integration)

Enablement (first visit)

Embed section is disabled by default. First visit shows:

┌──────────────────────────────────────────────────────────────────┐
│ Embed Craftkit in your product                                   │
│                                                                  │
│ Let your customers build templates inside your own UI, with     │
│ variables that map to your data model.                           │
│                                                                  │
│   ✦  Drop-in iframe builder                                      │
│   ✦  Inject your variable catalog                                │
│   ✦  Webhook callbacks on publish                                │
│   ✦  Per-tenant branding & permissions                           │
│                                                                  │
│ Pricing: included on Scale and above. Counts toward your render │
│ quota. View pricing →                                            │
│                                                                  │
│ [Enable Embed for this project]   [Read the integration docs]   │
└──────────────────────────────────────────────────────────────────┘

Overview screen

  • Setup checklist (5 items: keys, origins, catalog, webhook, first session)
  • Live activity sparkline (sessions per hour, last 24h)
  • Recent events feed (last 10)
  • Quick-start code snippet (one curl)
  • "Test embed" button (opens sandbox modal)

Configuration → Keys

Three keypairs:

Type Visibility Use
Publishable (ck_pk_*) Always shown Browser-safe identifier
Secret (ck_live_*) Shown ONCE on creation Server-side only
Signing keys (Ed25519 keypair) Public key always shown Optional: partners verify JWTs themselves

All keys rotatable. Secret keys: support multiple active (Production + Staging), each with name + last-used + revoke. Signing keys: 24h overlap on rotation.

Configuration → Allowed Origins

┌──────────────────────────────────────────────────────────────────┐
│  Allowed origins                                                 │
│                                                                  │
│  Origin                          Environment    Added            │
│  ────────────────────────────────────────────────────────────── │
│  https://app.kleesto.com         Production     Apr 3   ✕       │
│  https://staging.kleesto.com     Staging        Apr 3   ✕       │
│  http://localhost:3000           Development    Apr 3   ✕       │
│                                                                  │
│  [+ Add origin]   Wildcards: https://*.partner.com               │
│                                                                  │
│  CSP snippet:                                                    │
│   frame-src https://embed.craftkit.dev;                          │
│   connect-src https://api.craftkit.dev;                          │
│                                                                  │
│  ⚠  Recent denials (last 24h)                                    │
│   ◾ 2 attempts from https://evil.example.com — blocked           │
│      [Add to allowlist]  [Mark as expected]  [Ignore]            │
└──────────────────────────────────────────────────────────────────┘

Configuration → Catalogs

Named, versioned catalogs. Tree editor with diff/remap tooling.

┌──────────────────────────────────────────────────────────────────┐
│  ▾  partner-default                       v3 · current           │
│      62 fields · 4 namespaces · 2 loops                          │
│      Used in 1,205 sessions this month                           │
│      [Edit]  [View JSON]  [Diff vs v2]  [Test in sandbox]        │
│                                                                  │
│  ▸  partner-eu                            v1 · current           │
│  ▸  partner-default                       v2 · archived          │
└──────────────────────────────────────────────────────────────────┘

Edit view: tree of namespaces → fields, plus diff vs previous version showing add/remove/rename, with remap suggestions when keys change.

Configuration → Permission Presets

Named role bundles (admin, editor, viewer) with permission flags. Backend sends permissions_preset: "editor" instead of 8 individual flags.

Sessions

Live console listing currently-active sessions + recent (last 7d) sessions.

Each row: session id, tenant, actor, template, duration, outcome icon.

Click a session → session inspector with full lifecycle:

  • Created at + IP
  • Token issued + exp
  • Iframe loaded
  • Editor ready
  • Each variable inserted (with timestamp + source)
  • Token refreshes
  • Save/publish events
  • Webhook deliveries (with response status)
  • Errors

Plus [Revoke] button — invalidates all tokens immediately.

Test Embed sandbox

┌──────────────────────────────────────────────────────────────────┐
│  Test embed                                              [✕]    │
│                                                                  │
│  Mock a session and play with the embedded builder right here. │
│                                                                  │
│  Catalog:    [ partner-default v3 ▾ ]                            │
│  Permissions: [ editor ▾ ]                                       │
│  Tenant:     [ Mock Tenant Ltd ▾ ] [+ custom]                    │
│  Branding:   [ ⬛ #B7541C ] [Logo: …]  [ Locale: en-GB ▾ ]       │
│                                                                  │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │  [ Embedded Craftkit builder mounted here, fully working ] │ │
│  │  [ Same iframe, same JWT flow, same catalog injection    ] │ │
│  └────────────────────────────────────────────────────────────┘ │
│                                                                  │
│  Event log                                                       │
│   14:32:11  craftkit.ready                                       │
│   14:32:24  craftkit.variable.inserted  customer.name            │
│   14:32:38  craftkit.template.saved     v1                       │
│   14:32:55  craftkit.template.published v1                       │
│                                                                  │
│  [Open in new tab]  [Copy session URL]  [Reset]                  │
└──────────────────────────────────────────────────────────────────┘

This single button removes 90% of integration friction.

Embed Webhooks (separate from regular webhooks)

Embed lifecycle events:

  • embed.session.created / refreshed / expired / revoked
  • embed.template.saved / published
  • embed.variable.inserted (high-volume, opt-in)
  • embed.security.origin_blocked / permission_denied
  • embed.feedback.submitted
  • embed.quota.exhausted

Retry: exponential backoff 1s → 1024s, max 8 attempts. Idempotency via x-craftkit-event-id header (24h dedupe window).


Stable .ck-* class catalogue (styling contract)

Every class below is a versioned API surface. Partners may target it via appearance.rules or via a stylesheetUrl that loads inside the iframe. Adding a class is non-breaking; renaming, removing, or restructuring its DOM nesting is a breaking change requiring a major version bump of the embed.

Root + chrome

Class DOM context
.ck-embed-root Outermost wrapper. Holds data-theme, data-density, lang. CSS variables live here.
.ck-embed-shell Two-pane shell: catalog rail + canvas.
.ck-embed-canvas-wrap Scrollable canvas pane.
.ck-embed-banner Inline notification banner above the canvas.
.ck-embed-banner-warn Warning variant of banner.
.ck-embed-error Full-iframe error state.
.ck-embed-error-card The card inside the error state.
.ck-embed-error-icon Icon glyph in the error card.
.ck-embed-error-ref Reference id displayed under the error message.

Catalog rail (variable picker)

Class DOM context
.ck-catalog-rail Left rail container.
.ck-catalog-rail-title Section heading inside the rail.
.ck-catalog-search Search input wrapper.
.ck-catalog-namespace A grouping (e.g. "Customer", "Order").
.ck-catalog-namespace-header Header row of a namespace.
.ck-catalog-namespace-count Badge with the field count.
.ck-catalog-field Draggable field row.
.ck-catalog-field-type Type-glyph badge (T/N/D/…).
.ck-catalog-field-label Field label text.
.ck-catalog-field-key Monospace key path next to the label.
.ck-catalog-field-req Required marker.

Toolbar / actions

Class DOM context
.ck-toolbar Toolbar container.
.ck-toolbar-section Group inside the toolbar.
.ck-publish-button The publish CTA — shown unless layout.showPublishButton: false.
.ck-save-hint "Saved …" hint next to publish.

Block palette + canvas

Class DOM context
.ck-block-palette Right-side block insert panel.
.ck-block-palette-button A single insert button (Heading / Text / …).
.ck-canvas Page canvas root.
.ck-page A single page.
.ck-section A page section.
.ck-row A row inside a section.
.ck-block Generic block wrapper.
.ck-block-text, .ck-block-heading, .ck-block-paragraph, .ck-block-variable, .ck-block-image, .ck-block-signature Block-type variants.

Inspector + form primitives

Class DOM context
.ck-inspector Right rail when a block is selected.
.ck-inspector-field A single form row in the inspector.
.ck-input Text input / textarea base.
.ck-input-invalid Invalid input state.
.ck-button Button base — modifiers below.
.ck-button-primary Filled brand button.
.ck-button-secondary Outlined neutral button.
.ck-button-ghost Hover-only button.
.ck-prose Rich-text rendering target inside Tiptap blocks.

State suffixes accepted by rules

:hover, :focus, :focus-visible, :active, :disabled, ::placeholder, --selected, --invalid. Anything else dropped.

See 11-styling.md for the full styling contract.


Last revised: 2026-05-03