Build interactive HTML applications with client-side filtering, custom visualizations, and AI-powered Q&A inside Definite Docs
Data apps are single-file HTML applications that run inside a Doc. They go beyond standard YAML dashboards by giving you full control over the UI: client-side filtering, interactive pivot tables, custom visualizations, and AI-powered natural language querying.A data app is stored as an HTML file in Drive and rendered in a sandboxed iframe within your Doc. Definite auto-injects a window.Definite bridge object so your HTML can query data, run Cube models, and call the AI assistant without any setup.
Use data apps when you need: client-side filtering and drill-down, multi-tab layouts, brush-selectable date histograms, AI-powered Q&A, or fully custom canvas visualizations.Use YAML dashboards when: standard charts, tables, and KPIs are sufficient. They’re faster to build, easier to maintain, and Fi can create them from natural language.
Create a single HTML file with your app logic. Use the Data Bridge API to query data from Definite. Include Tailwind CSS and Inter font for visual consistency.
Copy
Ask AI
<script src="https://cdn.tailwindcss.com"></script><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"><body class="bg-gray-50 p-6 font-[Inter]"> <div id="app"><div id="loading">Loading...</div></div> <script> async function init() { try { const rows = await Definite.query( "SELECT region, SUM(revenue) as rev FROM LAKE.PUBLIC.sales GROUP BY 1 LIMIT 1000" ) document.getElementById("loading").remove() // Build your UI with rows } catch (err) { document.getElementById("loading").textContent = "Error: " + err.message } } init() </script></body>
Always include a loading state and error handling. Bridge queries are async and may take a moment to return.
Create a Doc with a full-screen HTML tile pointing to your uploaded file. No datasets block is needed since the app fetches its own data through the bridge.
if (window.Definite?.fiFast) { const result = await Definite.fiFast({ prompt: "What were our top 5 products by revenue last month?", model: "gemini-3.1-flash-lite-preview", system: "You are a DuckDB SQL expert. Always use the execute_sql tool.", temperature: 0.0, max_output_tokens: 1200, })}
fiFast may not be available in all contexts (e.g., public embeds). Always check window.Definite?.fiFast before calling.
For interactive filtering, pivoting, and drill-down without round-trips to the server, load your data into DuckDB WASM running in the browser.The pattern:
Fetch data via Definite.queryArrow() (Arrow format for performance)
Load it into a local DuckDB WASM instance
Run fast client-side SQL for filters, KPIs, and aggregations
Copy
Ask AI
import * as arrow from 'https://storage.googleapis.com/definite-public/libs/apache-arrow@17.0.0/apache-arrow.esm.js';import * as duckdb from 'https://storage.googleapis.com/definite-public/libs/duckdb-wasm@1.29.0/duckdb-wasm.esm.js';// Fetch data from Definiteconst buffer = await Definite.queryArrow("SELECT * FROM LAKE.PUBLIC.sales LIMIT 200000");// Load into DuckDB WASMconst arrowTable = arrow.tableFromIPC(new Uint8Array(buffer));await conn.insertArrowFromIPCStream(arrow.tableToIPC(arrowTable, 'stream'), { name: 'sales', create: true });// Now query locally for instant resultsconst result = await conn.query("SELECT region, SUM(revenue) as rev FROM sales GROUP BY 1");
Version compatibility is critical. Use Apache Arrow 17.0.0 with DuckDB WASM 1.29.0. Mismatched versions cause silent failures.
When creating tables in DuckDB WASM for use with Perspective.js, rename columns to camelCase and cast types explicitly:
Copy
Ask AI
CREATE TABLE txns AS SELECT transaction_id AS txnId, STRFTIME(created_at, '%Y-%m-%d') AS createdDate, amount::DOUBLE AS amount, ABS(amount)::DOUBLE AS absAmountFROM raw_data
Perspective.js provides interactive pivot tables, charts, and data grids that work with DuckDB WASM. It’s ideal for data apps that need user-configurable visualizations.Supported chart types: Datagrid, Y Line, Y Area, Y Bar, X Bar, Y Scatter, Heatmap, Treemap, Sunburst.
Copy
Ask AI
import perspective from "https://cdn.jsdelivr.net/npm/@perspective-dev/client@4.3.0/dist/cdn/perspective.js";import { DuckDBHandler } from "https://cdn.jsdelivr.net/npm/@perspective-dev/client@4.3.0/dist/esm/virtual_servers/duckdb.js";// Bridge DuckDB WASM to Perspectiveconst handler = new DuckDBHandler(conn);const pspClient = await perspective.worker(perspective.createMessageHandler(handler));
Set fullScreen: true on your HTML tile to remove all Doc chrome (padding, borders, tile headers, sidebar). The HTML fills the entire viewport edge-to-edge.