Product

Product overview Agents Automations Apps Code (Beta) Integrations Governed Runtime Security

Where Renly runs

Windows app Android app Inside other AI apps

Solutions

Finance Sales Operations People and HR Marketing Enterprise

Resources

Pricing Docs Academy Blog Compare Support

AI governance and capability

AI governance framework AI governance assessment AI capability maturity AI maturity assessment
Book a demo Sign in
Docs / Renly Apps / Custom blocks

Custom blocks

When the standard components cannot show something, a maker can add a custom block: their own HTML and script, run in a sandbox with no network, fed only by the queries, aggregates and actions it declares. The host runs those as the person viewing the page, so a block can never see or change more than that person could.

The sandbox

  • The block renders in an iframe with an opaque origin and sandbox="allow-scripts". It cannot read Renly's cookies or storage.
  • Its content security policy is the one Sites use: no network (connect-src 'none'), with scripts and styles allowed only from cdnjs, jsDelivr, unpkg and the Tailwind CDN, and images from https hosts.
  • The frame is loaded through a render URL bound to the app, the published version (or the draft for a maker's preview), the interface, page, component and viewer. It expires after 10 minutes and is fetched again as needed; a newer published version replaces a stale frame.
  • A block that navigates itself away is closed, with a Reload button.

The bridge: window.renly

The host injects a small, frozen bridge before anything else in the document. Every message between the block and the page carries a per-render nonce, and each side accepts messages only from the other's window.

CallWhat it does
window.renly.run(operationId, params)Runs one of the block's declared operations as the viewer and resolves with plain JSON. A query takes { cursor, search }; an aggregate takes nothing; an action takes { recordId, inputs, expectedVersion }. Errors reject with the server's plain message.
window.renly.onTheme(cb)Calls back with the current theme on ready and on every light or dark change: { mode, colors: { background, surface, text, muted, border, accent, positive, negative, warning }, series: [8 colours], font }. The same values are set as --renly-* CSS variables.
window.renly.resize(height?)Sets the frame's height, 80 to 2,000 pixels; with no value, fits the content.
window.renly.operationsThe declared operations, so a block can check what it has.
<canvas id="chart"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
<script>
  (async () => {
    const by = await window.renly.run('open-by-status');          // a declared aggregate
    new Chart(document.getElementById('chart'), {
      type: 'bar',
      data: { labels: by.groups.map(g => g.label), datasets: [{ data: by.groups.map(g => g.value) }] },
    });
    window.renly.onTheme(t => document.body.style.color = t.colors.text);
    window.renly.resize();
  })();
</script>

Declared operations

  • A block declares operations in the designer: a query (rows), an aggregate (a number or a breakdown) or an action (one of the interface's declared actions). An operation id the block did not declare is refused, and a block cannot name a query or action that is not in the app.
  • A query runs as a table of every field the viewer may read; an aggregate runs as a metric. Row scope, field access and source routing are exactly what those components get.
  • An action runs through the page's action runner, so the person sees the action's inputs and the confirmation for deletes and archives, and the write rules apply. One action at a time per block. The audit entry records that it came from a custom block.

Limits

  • 30 bridge calls a minute per viewer per block, data and actions together, counted across servers. Over the limit, calls fail with a Retry-After; the page applies the same limit before calling, and this limit never pauses the rest of the app.
  • HTML up to 200,000 characters. Height from the component (default 320 pixels) or the block's own resize.

In the designer, and with the App Builder

The custom block editor has a monospace HTML editor, a height, and an operations editor (records, a number or breakdown, an action), with a live preview of the saved draft's block. A new block starts as a Chart.js bar chart fed by one aggregate. The App Builder knows the bridge and the no-network rule, so Build with AI can write a block for you.

An accepted trade-off, the same as for Sites: images from any https host are allowed and a block can navigate itself, so a block could carry data it was given to a host its maker chose. A block is written by a maker of the app, versioned with it, and only ever sees what the viewer may see.