Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.chatblocks.ai/llms.txt

Use this file to discover all available pages before exploring further.

Every block has a chatblocks.json manifest at the root of its file set. The manifest is the contract between your code and the platform: it declares the format, the canvas footprint, what data flows in, and what the iframe is allowed to do. The full Zod schema lives in packages/shared/src/manifest.ts. This page covers the shape; the schema there is the source of truth and what the server validates against.

Minimal manifest

A barebones code block with no widget or data binding:
{
  "schemaVersion": 1,
  "format": "code",
  "entry": "src/App.tsx",
  "defaultSize": { "width": 320, "height": 200 }
}
That’s all that’s required. Everything else has sensible defaults.

Top-level fields

FieldTypeRequiredNotes
schemaVersion1yesCurrently always 1. Schema bumps go through a coordinated migration.
format"code" | "embed"no (defaults to "code")See Formats.
entrystringyes for code, must be absent for embedRelative path ending in .js, .jsx, .ts, .tsx, or .html. No URLs, absolute paths, parent traversal, or backslashes.
defaultSize{ width, height }yesCanvas footprint in pixels. Each dimension is an integer in [50, 2000].
constraintsobjectnoMin/max resize bounds. Defaults to 0.6×/2.5× of defaultSize, clamped to [50, 2000].
resizablebooleanno (defaults true)Set false for fixed-shape blocks like a stamp or a specific-aspect-ratio widget.
permissionsarrayno (defaults [])See Permissions.
networkobjectno{ allowedOrigins: [] }. Required when "network" permission is declared.
embedobjectyes for embed, must be absent for codeSee Formats.
widgetobjectnoiOS widget projection. See Widget.
bindingobjectnoLive-data binding. See Binding.

Formats

ChatBlocks has two first-class formats. The bar for adding a new one is a platform invariant the AI generator can’t be trusted to uphold on its own — everything else stays code.
Vibe-coded block. Your file set is built into an iframe-loaded artifact via Vercel Sandbox. Strict CSP, no cross-origin framing, sandboxed iframe.Required: entry must be a relative path to a file in your set. Conventional: src/App.tsx.
{
  "schemaVersion": 1,
  "format": "code",
  "entry": "src/App.tsx",
  "defaultSize": { "width": 320, "height": 200 }
}

Permissions

Declare the capabilities your code block needs. Each is opt-in.
PermissionGrants
viewer.profileRead the viewer’s display name and avatar (when permitted by visibility).
storage.kvPer-block key/value storage scoped to the viewer.
assetsUpload and serve static assets via Convex storage.
eventsEmit custom events into the audit log.
formsRender <form> elements with submission posting back to the platform.
networkMake outbound HTTP requests. Requires network.allowedOrigins to be set.
The network permission and network.allowedOrigins are coupled — declaring one without the other is a validation error. Origins must be HTTPS, origin-only (no path/query/hash/credentials, no wildcards).
{
  "permissions": ["network"],
  "network": {
    "allowedOrigins": ["https://api.example.com"]
  }
}

Binding

Optional. Connects the block to a configured data source so the platform refreshes its widget data on a cron (or push) cadence.
{
  "binding": {
    "dataSourceId": "<id-from-/settings/data-sources>",
    "queryConfig": {
      "type": "stripe.mrr",
      "params": {}
    },
    "projection": {
      "fields": {
        "value": { "source": "amount_cents", "format": "currency" },
        "label": { "literal": "MRR" }
      }
    }
  }
}
The queryConfig.type is one of KNOWN_QUERY_TYPES (see packages/shared/src/binding.ts):
  • stripe.mrr, stripe.balance, stripe.recentCharges
  • postgres.sql
  • webhook.latest, webhook.aggregate, webhook.list
  • mcp.tool
The projection maps raw query output into the widget’s data shape. Each field is either { source, format?, formatOptions? } (pluck from the query result with optional formatting) or { literal } (constant value). Formats: currency, number, percent, percent-with-sign, datetime. Cross-reference: the Connecting data section walks through each connector and the queries it supports.

Constraints reference

constraints.min* and constraints.max* set the block’s resize bounds on a canvas. Defaults are derived from defaultSize:
  • min* = defaultSize.* × 0.6, clamped to ≥ 50.
  • max* = defaultSize.* × 2.5, clamped to ≤ 2000.
Override explicitly when your block has a tighter aesthetic range:
{
  "defaultSize": { "width": 320, "height": 200 },
  "constraints": {
    "minWidth": 280,
    "minHeight": 160,
    "maxWidth": 500,
    "maxHeight": 320
  }
}
The validator enforces min ≤ max for each axis, and defaultSize must lie within [min, max].

Validation errors

When validation fails, the API returns a list of issues, each with a stable code:
CodeMeaning
missing_entrycode format requires entry.
invalid_entryentry path failed the relative-path / extension check.
unexpected_entryembed format must not declare entry.
missing_embedembed format requires embed.url.
invalid_embed_urlURL is not HTTPS, has credentials, or has a non-public hostname.
unexpected_embedcode format must not declare embed.
invalid_constraintmin > max on width or height.
default_size_out_of_boundsdefaultSize falls outside constraints.
duplicate_permissionSame permission listed twice.
missing_network_permissionnetwork.allowedOrigins declared without the "network" permission.
missing_network_origins"network" permission declared without any origins.
invalid_originAn origin failed the HTTPS-origin-only check.
unsupported_permissionsembed format must not declare permissions.
unsupported_networkembed format must not declare network.allowedOrigins.
unrecognized_fieldUnknown top-level field.

What’s next

Widget

The iOS widget projection — six templates, five themes, sample-data schema.

Runtime

What happens at render time — render paths, sandbox, data injection.