Skip to content

Plugins (advanced)

A tile plugin is the most powerful custom tile: a self-contained HTML

  • JavaScript widget that renders inside a locked-down sandboxed iframe, while Saiku feeds it the tile’s query rows. Use it when neither the built-in tiles nor the declarative custom renderers can draw what you need — a bespoke gauge, an unusual layout, a purpose-built widget.

Plugins are an advanced, administrator-controlled feature. This page is mostly about their trust model, because getting that right matters more than the mechanics.

How a plugin is installed

An operator (not a dashboard user) drops a bundle into a folder on the Saiku server:

${saiku.home}/tile-plugins/
records-bars/
plugin.json # id, label, and an optional option schema
plugin.html # self-contained widget: inline CSS/JS, data: images only
  • plugin.json declares the plugin’s id (a slug like records-bars), a display label, and optionally an optionSchema describing the author-configurable options.
  • plugin.html is the widget itself — a single self-contained HTML document with inline CSS and JavaScript (no remote scripts, styles, or fonts; images must be data: URIs).

The server scans the folder and makes installed plugins pickable. A dashboard author adds one from + Add tile, where each installed plugin appears as its own entry; the persisted tile stores only the plugin’s id, never any markup.

Saiku ships one seed example — records-bars, a simple records bar chart — so a fresh install has a working plugin to look at and copy.

What the sandbox does — and does not — contain

Every plugin frame runs behind two containment layers.

1. An iframe sandbox="allow-scripts" (deliberately without allow-same-origin). The frame runs at the opaque null origin, so plugin code cannot:

  • read the parent page’s DOM, cookies, or localStorage;
  • see the Saiku session, an embed token, or any other-origin data;
  • open popups, submit forms, navigate the top window, or trigger downloads.

2. A strict Content-Security-Policy on the frame (default-src 'none', no connect-src). This blocks background network egressfetch, XHR, WebSocket, EventSource, sendBeacon, remote subresources, and the classic <img src="https://evil…"> beacon.

Closing the self-navigation channel

If you want to shut the self-navigation exfil channel too, an operator sets a restrictive frame-src in the deployment CSP via saiku.security.csp (at the reverse proxy or the launcher’s CSP config). Constraining where plugin frames may navigate is the only way to govern navigation — the per-tile sandbox and CSP cannot, by design.

The plugin ↔ host protocol

The host and plugin communicate only through window.postMessage. On mount, the host injects a per-frame cryptographic nonce; every message a plugin sends must echo that nonce or it’s dropped (a sandboxed frame’s origin is the string "null", so the nonce is the only trustworthy authenticator).

  • Host → plugin: init (the author’s options), data (the query records), theme, and resize.
  • Plugin → host: ready (I’ve loaded), resize (please set my height — clamped by the host), filter (a selection, which the host re-resolves against the live cube — a plugin can’t inject MDX), and error (rendered as plain text only).

The host validates and clamps everything a plugin sends; a malformed or unauthenticated message is ignored rather than acted on.

Plugins in embedded Apps

When an App is embedded, its plugin tiles are served token-scoped: a guest can load exactly the plugins referenced by the embedded App’s tiles and nothing else. The same sandbox + CSP containment applies, and the same self-navigation caveat holds — so the frame-src guidance above is the operator control for embedded Apps too.