Live Dashboards
Build HTML artifacts that load fresh data at runtime through Wato-approved connectors, with credentials kept server-side.
A live dashboard is a hosted HTML artifact that loads fresh data at runtime through Wato. The page stays a normal web page; Wato handles authentication, connector access, team policy, and traceability server-side. The browser never sees connector secrets, OAuth tokens, or MCP credentials.
Use a live dashboard when you want a report or operational view that refreshes from approved systems (Linear, Notion, your CRM, …) instead of showing static exported data.
How it works
The model has three parts:
- You declare the connector calls a page wants, as static attributes in the
HTML (
data-wato-call,data-wato-id). - Wato classifies and approves those calls against your team's server-side connector/tool registry and stores an approved view policy. Read calls are approved automatically; write or destructive calls become actions that need review.
- At runtime, the browser SDK exchanges a short-lived session token and may call only the tools in the stored policy. Wato runs the actual connector call server-side and returns the result.
The agent never labels calls
You declare what the page wants to call. Wato decides whether each call is a read or an action using its own tool registry — not labels in your HTML.
Authoring workflow
- Call
wato_get_usage_guide, thenwato_get_live_artifact_primitivesfor the current contract. - Find exact connector and tool names with
mesh_search_tools(includeSchema: true). - Declare each call in HTML with
data-wato-idanddata-wato-call(plusdata-wato-defaults/ form fields for inputs). - Add the config block and the SDK script.
- Bind the page with
wato_bind_dashboard_view, passing the final HTML, a stableviewSlug, a title, and every non-hosted origin the page will run on. - Test the unauthenticated, sign-in callback, authenticated, and partial-failure states.
Declaring calls
Mark each section that needs data with a stable data-wato-id and the
connector.tool to call. Use form fields for values the viewer can change, and
data-wato-defaults only for safe, fixed defaults.
<form data-wato-form="recentDocs">
<input name="query" value="project updates" />
</form>
<section
data-wato-id="recentDocs"
data-wato-call="notion.notion-search"
data-wato-defaults='{"page_size": 10}'
></section>| Attribute | Required | Purpose |
|---|---|---|
data-wato-call | Yes | The connector.tool to call, e.g. notion.notion-search. Must be statically written in the HTML. |
data-wato-id | Recommended | Stable id for this call, referenced by the SDK and in results. |
data-wato-defaults | No | JSON object of safe fixed defaults. Wato still validates keys and bounds server-side. |
Rules:
- Connector and tool names must be statically visible in
data-wato-call. Dynamically constructed calls require an explicit reviewed binding. - Do not hardcode
orgorteamin portable HTML — Wato binds those from the hosted URL, share link, localhost bootstrap, or launch params. - Do not embed connector secrets, OAuth tokens, dashboard tokens, or API keys in the HTML.
- Use form fields for viewer-provided input; use
data-wato-defaultsonly for fixed defaults.
Adding the SDK
Include a static config block and load the Wato dashboard SDK:
<script id="wato-dashboard-config" type="application/json">
{ "apiBaseUrl": "https://mesh.watolabs.com", "viewId": "default" }
</script>
<script src="https://mesh.watolabs.com/api/dashboard/sdk.js"></script>Then initialize the SDK and make calls:
const wato = await window.WatoDashboard.init();
// Preferred: call by the data-wato-id you declared
const docs = await wato.call("recentDocs", { query });
// Or call a connector tool directly
await wato.callTool("notion", "notion-search", { query });
// Run an approved action (write/destructive calls)
await wato.callAction("archive-issue", { issueId });init() returns the resolved config, plus call, callTool, callAction,
and refreshSession. For hosted Wato artifacts, keep viewId: "default" and
omit org/team; Wato derives them from the URL.
Live dashboards never run from file://
A live dashboard must run from an allowed http(s) origin. On localhost it must
resolve an explicit org, team, and view slug; file:// is never valid.
Binding the view
After the HTML is final, bind it so Wato can build the server-side policy before runtime auth works:
wato_bind_dashboard_view({
"viewSlug": "brightcart-renewal-risk",
"title": "BrightCart Renewal Risk",
"html": "<!doctype html>...",
"allowedOrigins": ["http://localhost:5173"]
})| Parameter | Purpose |
|---|---|
viewSlug | Stable, URL-safe id for the view, e.g. brightcart-renewal-risk. |
title | Human-readable dashboard title. |
html | The full HTML containing the static data-wato-call declarations. |
allowedOrigins | Browser origins allowed to bootstrap the view, e.g. http://localhost:5173. Hosted artifacts are handled automatically. |
Wato scans the data-wato-call declarations, verifies them against the team's
approved tool catalog, activates read-only safe calls, and returns
review_required for write, destructive, or unknown calls.
The result tells you what happened:
| Result | Meaning |
|---|---|
status: "active" | The view is bound and read calls are approved. |
status: "review_required" | The binding includes actions or unknown/blocked calls that need approval. |
allowedCalls | The calls that were approved into the policy. |
blockedCalls | Calls that were not allowed (unknown tools, not in the catalog). |
Permission required
Creating or updating a durable binding requires team admin, org admin,
teams:manage, or tools:manage access.
Reads vs. actions
Wato classifies each declared call using its tool registry:
- Reads (search/list/get/fetch…) are approved automatically and stored as the view's
reads. - Writes and destructive calls (create/update/send/delete…) become actions that require confirmation and review before they can run. Until then the binding is
review_required.
Origins and context
- Hosted Wato artifacts: Wato derives
org,team, and the view from the hosted URL. KeepviewId: "default". - Share links: Wato maps a share id to org, team, and view server-side.
- Localhost / custom hosts: include the exact origins in
allowedOrigins, and resolve an explicitorg,team, and view slug (via config or query params).
Note that bootstrap origins (where the page is allowed to load — allowedOrigins) are not the same as the dashboard view itself.
Runtime states to handle
A live dashboard should treat these as normal UI states, not crashes:
| State | What to do |
|---|---|
login_required | Show a real sign-in button that redirects the viewer to Wato auth. |
connector_auth_required | Prompt the viewer to authenticate the connector in Wato. |
token_expired | Refresh the dashboard session and retry once. |
origin_not_allowed | Open from an allowed origin, or update the view's allowedOrigins. |
tool_not_allowed | Only call tools approved into the server-side policy. |
connector_call_failed | Show a fallback for that section; keep the rest of the page live. |
Rendering rules:
- Load each
data-wato-idindependently — one failed call must not blank the page. - Show partial live data when some calls succeed, with a fallback only for the sections whose source failed.
- Surface failed
data-wato-idnames, not raw stack traces.
Reading results
Connector results may be wrapped. Normalize before rendering:
- Prefer
structuredContentwhen present. - Otherwise, if
result.contentcontains a text block with JSON, parsecontent[0].text, then read keys such asissues,projects, orteams.
Done check
Before declaring a live dashboard finished:
wato_bind_dashboard_viewreturnedstatus: "active".allowedCallsare exactly what you expect;blockedCallsis empty (or explained).- Hosted resolves
viewId: "default"; localhost resolves explicitorg/team/view slug. - The page is not opened from
file://. - The unauthenticated state shows a working sign-in button.
- The sign-in callback exchanges the code, removes it from the URL, and caches the session.
- Partial failures keep the working sections visible.
Reference
The MCP tools used here are documented in the Reference:
wato_get_live_artifact_primitives, mesh_search_tools, and
wato_bind_dashboard_view.