Updated March 2026
You describe a dashboard in JSON. The platform renders it. No charting library, no frontend code.
Sutrena's dashboard DSL supports seven widget types: metric_card for single numbers, data_table for rows and columns, text_block for text, pie_chart for proportions, bar_chart for comparisons, line_chart for trends, action_table for interactive editable tables. Each widget is a JSON object with a type, title, and type-specific config.
How do you aggregate data? The groupBy field. Group by any form field (like "category" or "rating") to see breakdowns. Or use $submitted_at:day, $submitted_at:week, or $submitted_at:month for time-based trends. Metric cards use a value field with expressions like count(*), sum(fieldName), avg(fieldName), min(fieldName), or max(fieldName). Chart widgets (pie_chart, bar_chart, line_chart) accept an optional aggregate field with the same expressions to aggregate numeric values instead of counting rows.
The DSL is versioned (current: 1) and validated with Zod server-side. Malformed definitions get rejected with clear errors before anything is saved.
Each dashboard is connected to a specific form. It aggregates that form's submission data according to your widget definitions. Dashboards auto-refresh every 30 seconds in the browser, so they work as wall-mounted displays or live status screens.
By default, dashboards are private. Set isPublic to true and you get a shareable URL at sutrena.com/d/{id} that anyone can view without logging in.
Why does this matter for AI agents? An agent can look at a form's fields, decide which charts make sense, and generate the full dashboard JSON in one step. Templates already pair forms with matching dashboards, so creating from a template gives you both instantly.
For developers, the DSL skips the usual setup: no charting library, no data fetching logic, no aggregation queries. Define it in JSON. Sutrena handles the rest.
Dashboards are not limited to form data. Pass a data array for inline JSON (up to 1000 rows) or upload a CSV (up to 100K rows). Inline and CSV dashboards are static — no auto-refresh. For CSV data, date columns support the same groupBy syntax: $column_name:day|week|month.
{
"version": 1,
"widgets": [
{ "type": "metric_card", "title": "Total Responses", "value": "count(*)" },
{ "type": "metric_card", "title": "Average Rating", "value": "avg(rating)" },
{ "type": "pie_chart", "title": "By Category", "groupBy": "category" },
{ "type": "bar_chart", "title": "Revenue by Rating", "groupBy": "rating", "aggregate": "sum(amount)" },
{ "type": "line_chart", "title": "Submissions Over Time", "groupBy": "$submitted_at:day" },
{ "type": "data_table", "title": "Recent Entries", "columns": ["email", "category", "rating"], "limit": 20 }
]
}