### Example request to start a dashboard export Source: https://github.com/embeddable-hq/handbook/blob/main/pages/deployment/dashboard-export.mdx Server-side fetch call to start a PDF export. Requires an export-enabled token and a published dashboard. Optional parameters include viewport, variables, clientContext, styles, and animationSettleMs. ```ts // Important: Always call this server-side, never from client-side code fetch('https://api..embeddable.com/api/v1/dashboard-exports', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': `Bearer ${apiKey}` // Keep your API key secure }, body: JSON.stringify({ // // required // token: '', // a security token created with `export: true` format: 'PDF', // // optional // viewport: { width: 1280, // render width in px (defaults to 1280) height: 800, // optional; acts as a minimum height (see below) }, variables: { // override the dashboard's variables 'date-range': { from: '2025-01-01', to: '2025-12-31' } }, clientContext: { // same clientContext you'd pass when embedding theme: 'light', timezone: 'Europe/Berlin' }, styles: { // CSS applied to the dashboard element background: '#ffffff' }, animationSettleMs: 500 // extra wait for animations before capture }) }) .then((res) => res.json()) .then(console.log); ``` -------------------------------- ### Push with API key example Source: https://github.com/embeddable-hq/handbook/blob/main/pages/getting-started/development/pushing-code.mdx Example of pushing with an API key, email, and message. ```bash npm run embeddable:push -- --api-key c26624b --email my@email.com --message "My first components and models" ``` -------------------------------- ### Navigate into the cloned directory and install dependencies Source: https://github.com/embeddable-hq/handbook/blob/main/pages/getting-started/get-set-up/set-up-your-workspace.mdx Change into the cloned repository directory and install required npm dependencies. ```bash cd remarkable-pro-boilerplate ``` ```bash npm i ``` -------------------------------- ### Start local development environment Source: https://github.com/embeddable-hq/handbook/blob/main/pages/getting-started/development/local-environment.mdx Run these commands in your terminal to log in to Embeddable and start the local development server. The first command authenticates you, and the second launches the dev environment. ```bash npm run embeddable:login npm run embeddable:dev ``` -------------------------------- ### Start, poll, and download a dashboard export (TypeScript) Source: https://github.com/embeddable-hq/handbook/blob/main/pages/deployment/dashboard-export.mdx Server-side example that starts a PDF export job, polls until completion while respecting the Retry-After header, and downloads the PDF. The download URL expires, so it should be used immediately. ```typescript // Important: Always call this server-side, never from client-side code const BASE = 'https://api..embeddable.com/api/v1/dashboard-exports'; const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': `Bearer ${apiKey}`, }; // 1. Start the job const { jobId } = await fetch(BASE, { method: 'POST', headers, body: JSON.stringify({ token: exportToken, format: 'PDF', viewport: { width: 1280 } }), }).then((r) => r.json()); // 2. Poll until it's done. Respect the Retry-After header rather than a tight loop. async function waitForExport(jobId) { while (true) { const res = await fetch(`${BASE}/${jobId}`, { headers }); const job = await res.json(); if (job.status === 'SUCCEEDED') return job; if (job.status === 'FAILED' || job.status === 'EXPIRED') { throw new Error(`Export ${job.status}: ${job.failureReason ?? ''}`); } const retryAfter = Number(res.headers.get('Retry-After')) || 2; await new Promise((r) => setTimeout(r, retryAfter * 1000)); } } const job = await waitForExport(jobId); // 3. Download the PDF and (for example) save or attach it — don't reuse the URL later, it expires. const pdf = Buffer.from(await fetch(job.downloadUrl).then((r) => r.arrayBuffer())); ``` -------------------------------- ### Package.json dependencies for Cube Cloud authentication Source: https://github.com/embeddable-hq/handbook/blob/main/pages/data/cube-cloud.mdx This example shows the required dependencies for the authentication setup: jsonwebtoken and jwks-rsa. It is a partial package.json, so you should add these to your existing dependencies object. ```json { "dependencies": { "jsonwebtoken": "^9.0.2", "jwks-rsa": "^3.1.0" } } ``` -------------------------------- ### Install Node.js 20 with nvm Source: https://github.com/embeddable-hq/handbook/blob/main/pages/getting-started/development/introduction.mdx Use nvm to install and switch to Node.js version 20 or later, which is required by Embeddable. ```bash nvm install 20 nvm use 20 ``` -------------------------------- ### Documentation page template (Markdown) Source: https://github.com/embeddable-hq/handbook/blob/main/STYLEGUIDE.md A suggested template for structuring documentation pages: start with a title and a simple definition, then explain why it matters, show a practical example, walk through implementation, and separate core concepts from variations. Use short sections and bullets for scanning. ```markdown # Broccoli 🥦 Broccoli is a green vegetable, similar to Cucumbers, but better. ## Why eat Broccoli? ... ## How to use Broccoli A simple way to get started with Broccoli is to ... ... Things to notice: - ... - ... - ... ## Examples ### Garlic Butter Sautéed Broccoli ... ### Broccoli Potato Soup ... ``` -------------------------------- ### Full example: load Google and custom fonts and assign them Source: https://github.com/embeddable-hq/handbook/blob/main/pages/component-libraries/remarkable-pro/styling/fonts.mdx Complete example of a theme provider that loads Google Fonts and a self-hosted font, then assigns them to different UI parts via CSS variables. Includes imports from @embeddable.com/core and @embeddable.com/remarkable-pro. ```ts // embeddable.theme.ts import { defineTheme } from '@embeddable.com/core'; import { Theme } from '@embeddable.com/remarkable-pro'; const themeProvider = (clientContext: any, parentTheme: Theme): Theme => { return defineTheme(parentTheme, { fonts: { google: [ { name: 'Inter' }, { name: 'Roboto', weights: '400;700' }, { name: 'Playfair Display', weights: '400..700' }, ], custom: [ { family: 'BrandFont', src: 'https://cdn.example.com/fonts/brandfont-regular.woff2', }, { family: 'BrandFont', src: 'https://cdn.example.com/fonts/brandfont-bold.woff2', descriptors: { weight: '700' }, }, ], }, styles: { '--em-core-font-family--base': "'Roboto'", '--em-markdown-h1-font-family': "'Playfair Display'", '--em-markdown-h2-font-family': "'Playfair Display'", '--em-kpichart-font-family': "'BrandFont'", }, }) as Theme; }; export default themeProvider; ``` -------------------------------- ### Full loadData implementation example Source: https://github.com/embeddable-hq/handbook/blob/main/pages/component-libraries/build-components/loading-data.mdx A complete example showing the definition of component inputs and the usage of loadData to fetch results based on those inputs. ```ts import { loadData } from '@embeddable.com/core'; import { defineComponent } from '@embeddable.com/react'; import Component from './index'; export const meta = { name: 'GroupedLineChart', label: 'Grouped Line chart', inputs: [ { name: 'ds', type: 'dataset', label: 'Dataset', }, { name: 'xAxis', type: 'dimension', label: 'X-Axis', config: { dataset: 'ds', supportedTypes: ['time'] // Only let user pick time dimensions } }, { name: 'granularity', type: 'granularity', label: 'Granularity' }, { name: 'groupBy', type: 'dimension', label: 'Group by', config: { dataset: 'ds' } }, { name: 'yAxis', type: 'measure', label: 'Y-Axis', config: { dataset: 'ds' } }, ], }; export default defineComponent(Component, meta, { props: (inputs) => { return { ...inputs, results: loadData({ from: inputs.ds, select: [inputs.yAxis, inputs.groupBy, { dimension: inputs.xAxis?.name, granularity: inputs.granularity } ], filters: [ { property: inputs.yAxis, operator: 'gt', value: 0 } ], orderBy: [{ property: inputs.yAxis, direction: 'desc' }], limit: 500, offset: 0 }) }; } }); ``` -------------------------------- ### Core token example Source: https://github.com/embeddable-hq/handbook/blob/main/pages/component-libraries/remarkable-pro/styling/core-tokens.mdx Shows example core tokens for line-height values, using the --em-core- prefix and modifiers like sm, md, l, xl. ```ts '--em-core-line-height--sm': '14px', '--em-core-line-height--md': '16px', '--em-core-line-height--l': '19px', '--em-core-line-height--xl': '38px', ``` -------------------------------- ### Install and Run MCP Server Source: https://github.com/embeddable-hq/handbook/blob/main/endpoints.md Commands to install dependencies and run the MCP server script (mcp_ai_agent.py). Requires Python environment with pip. ```bash pip install fastmcp httpx python mcp_ai_agent.py ``` -------------------------------- ### Install dependencies for MCP server Source: https://github.com/embeddable-hq/handbook/blob/main/pages/self-serve/ai-endpoints.mdx Install the required Python packages fastmcp and httpx to run the MCP server. ```bash pip install fastmcp httpx ``` -------------------------------- ### Metadata Response Example Source: https://github.com/embeddable-hq/handbook/blob/main/endpoints.md Example JSON response for the metadata endpoint. Includes widgets, templateWidgets, starterCanvasWidgets, variables, variableListeners, dashboardParams, datasets, and bundleHash. Note that datasets[].id is used for POST /ai/v1/query, and templateWidgets[].id is used for POST /ai/v1/custom-canvas/create. ```json { "widgets": [ { "id": "", "name": "string", "inputConfiguration": { "": "" } } ], "selfServeWidgets": [ { "..." } ], "templateWidgets": [ { "id": "", "name": "string", "inputConfiguration": { "..." } } ], "starterCanvasWidgets": [ { "id": "", "templateId": "", "inputConfiguration": { "..." }, "filters": {}, "limit": {}, "order": {}, "w": 4, "h": 3 } ], "variables": [ { "id": "", "name": "string", "type": "string", "defaultValue": "string", "array": false } ], "variableListeners": { "": [""] }, "dashboardParams": { "..." }, "datasets": [ { "id": "", "name": "string", "model": "string", "availableInCustomCanvas": true } ], "bundleHash": "string" } ``` -------------------------------- ### Create ExampleDropdown folder Source: https://github.com/embeddable-hq/handbook/blob/main/pages/getting-started/get-set-up/first-component.mdx Create the folder for the component in src/embeddable.com/components. ```bash mkdir src/embeddable.com/components/ExampleDropdown ``` -------------------------------- ### Partitioning Example: Unpartitioned vs Partitioned Table Source: https://github.com/embeddable-hq/handbook/blob/main/pages/data-modeling/caching/level-2-cache/prerequisites.mdx Illustrates the concept of partitioning a large table by time. Shows the unpartitioned table structure, a sample query filter, the partitioned table layout, and the specific partition that the query would scan, demonstrating partition pruning. ```text events (1,000,000 rows) └── All data stored together ``` ```sql WHERE created_at >= '2024-12-01' ``` ```text events ├── events_2024_01 (~83k rows) ├── events_2024_02 (~83k rows) ├── ... ├── events_2024_12 (~83k rows) ``` ```text events_2024_12 ``` -------------------------------- ### Get version metadata response Source: https://github.com/embeddable-hq/handbook/blob/main/pages/deployment/versions-api.mdx Example response from the get version metadata endpoint. Returns the dashboard's definition in the same JSON shape as its YAML dashboards-as-code source, including variables, datasets, and widgets as they existed at that saved version. ```json { "name": "my-embeddable", "title": "My Embeddable", "variables": [ { "name": "date-range", "type": "timeRange", "defaultValue": { "from": "2024-01-01", "to": "2024-12-31" } } ], "datasets": [ { "name": "filtered-data", "model": "daily_listens", "filters": [ { "member": "daily_listens.date", "operator": "inDateRange", "value": "date-range", "valueType": "VARIABLE" } ] } ], "widgets": [ { "component": "BarChart", "position": { "x": 0, "y": 0 }, "dimensions": { "width": 12, "height": 6 }, "inputs": [ { "input": "metric", "inputType": "measure", "value": "daily_listens.count" } ] } ] } ``` -------------------------------- ### Create the ExampleDropdown.emb.ts file Source: https://github.com/embeddable-hq/handbook/blob/main/pages/getting-started/get-set-up/first-component.mdx The code example in this snippet is a bash command that creates a new file. This command should be run from the root of your repository. ```bash command -v ``` -------------------------------- ### GET /ai/v1/models Response 200 OK Source: https://github.com/embeddable-hq/handbook/blob/main/endpoints.md Example JSON response showing the structure of the returned data models, including dimensions and measures with their properties. ```json [ { "name": "orders", "title": "Orders", "connectedComponent": 1, "dimensions": [ { "name": "orders.status", "title": "Status", "nativeType": "string", "description": "Order status", "meta": null, "__type__": "dimension" } ], "measures": [ { "name": "orders.count", "title": "Count", "nativeType": "number", "description": null, "meta": null, "__type__": "measure" } ] } ] ``` -------------------------------- ### Run the command-line tool to set up workspace Source: https://github.com/embeddable-hq/handbook/blob/main/pages/getting-started/get-set-up/set-up-your-workspace.mdx Use this command to automatically set up your workspace, build your code bundle, and push it. Requires Node.js version 22 or later. ```bash npx @embeddable.com/init ``` -------------------------------- ### Get version metadata request Source: https://github.com/embeddable-hq/handbook/blob/main/pages/deployment/versions-api.mdx Example request to fetch version metadata. Must be called server-side; keep the API key secure. The response is logged to the console. ```ts // Important: Always call this server-side, never from client-side code fetch('https://api..embeddable.com/api/v1/embeddables/{embeddableId}/saved-versions/{version}/metadata', { method: 'GET', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': `Bearer ${apiKey}` // Keep your API key secure } }) .then((res) => res.json()) .then(console.log); ``` -------------------------------- ### POST /ai/v1/query - Example Request Source: https://github.com/embeddable-hq/handbook/blob/main/pages/self-serve/ai-endpoints.mdx JSON body for a query against a dataset. Includes dimensions, measures, filters, timeDimensions, order, limit, offset, timezone, and countRows. The datasetId must come from GET /ai/v1/embeddable/metadata. ```json { "datasetId": "", "dimensions": ["orders.status", "orders.createdAt"], "measures": ["orders.count", "orders.revenue"], "filters": [ { "member": "orders.status", "operator": "equals", "values": ["completed"] } ], "timeDimensions": [ { "dimension": "orders.createdAt", "dateRange": ["2024-01-01", "2024-12-31"], "granularity": "month" } ], "order": [["orders.createdAt", "asc"]], "limit": 100, "offset": 0, "timezone": "America/New_York", "countRows": false } ``` -------------------------------- ### GET /ai/v1/embeddable/metadata Source: https://github.com/embeddable-hq/handbook/blob/main/endpoints.md Retrieves the full configuration of the embeddable associated with the security token, including widgets, datasets, variables, and layout parameters. This is the starting point for any agent needing to understand available charts and data sources. ```APIDOC ## [GET] /ai/v1/embeddable/metadata ### Description Returns the full configuration for the embeddable associated with the security token — widgets, datasets, variables, and layout parameters. ### Method GET ### Endpoint /ai/v1/embeddable/metadata ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token: `Bearer ` ### Response #### Success Response (200 OK) - **widgets** (array) - List of widgets, each with id, name, and inputConfiguration. - **selfServeWidgets** (array) - List of self-serve widgets. - **templateWidgets** (array) - List of template widgets, each with id, name, and inputConfiguration. - **starterCanvasWidgets** (array) - Pre-built layout presets with id, templateId, inputConfiguration, filters, limit, order, w, h. - **variables** (array) - List of variables, each with id, name, type, defaultValue, array. - **variableListeners** (object) - Mapping of variableId to list of dependent variable IDs. - **dashboardParams** (object) - Dashboard parameters. - **datasets** (array) - List of datasets, each with id, name, model, availableInCustomCanvas. - **bundleHash** (string) - Hash of the bundle. #### Response Example ```json { "widgets": [ { "id": "", "name": "string", "inputConfiguration": { "": "" } } ], "selfServeWidgets": [ { "..." } ], "templateWidgets": [ { "id": "", "name": "string", "inputConfiguration": { "..." } } ], "starterCanvasWidgets": [ { "id": "", "templateId": "", "inputConfiguration": { "..." }, "filters": {}, "limit": {}, "order": {}, "w": 4, "h": 3 } ], "variables": [ { "id": "", "name": "string", "type": "string", "defaultValue": "string", "array": false } ], "variableListeners": { "": [""] }, "dashboardParams": { "..." }, "datasets": [ { "id": "", "name": "string", "model": "string", "availableInCustomCanvas": true } ], "bundleHash": "string" } ``` ``` -------------------------------- ### Example response — ready to download Source: https://github.com/embeddable-hq/handbook/blob/main/pages/deployment/dashboard-export.mdx When the job is SUCCEEDED, the response includes a temporary downloadUrl and expiration times. ```json { "jobId": "4a752795-ee35-4e6d-9cf9-9972174a28cf", "status": "SUCCEEDED", "downloadUrl": "https://embeddable-dashboard-export...s3...amazonaws.com/4a752795-...?X-Amz-Signature=...", "downloadUrlExpiresAt": "2026-09-10T10:15:00Z", "expiresAt": "2026-09-11T09:00:00Z" } ``` -------------------------------- ### GET /ai/v1/custom-canvas/request-state - Response 200 OK Source: https://github.com/embeddable-hq/handbook/blob/main/pages/self-serve/ai-endpoints.mdx Example response containing the current Custom Canvas state. The version increments on every mutation; components[].id is the widget instance UUID required by update, delete, resize, and reorder endpoints. ```json { "components": [ { "id": "", "templateId": "", "key": "string", "inputConfiguration": { "": "" }, "subInputConfiguration": { "": { "": { "": "" } } }, "filters": { "": [ { "member": "model.field", "operator": "equals", "value": "x", "valueType": "string", "nativeDataType": "string" } ] }, "limit": { "": 100 }, "order": { "": ["model.field asc"] }, "w": 4, "h": 3, "heightResolution": null, "widthResolution": null } ], "version": 5 } ``` -------------------------------- ### Run embeddable:build Source: https://github.com/embeddable-hq/handbook/blob/main/pages/getting-started/development/pushing-code.mdx Build your models and components before pushing. ```bash npm run embeddable:build ``` -------------------------------- ### PUT /ai/v1/custom-canvas/update example request Source: https://github.com/embeddable-hq/handbook/blob/main/pages/self-serve/ai-endpoints.mdx JSON body for replacing an existing widget's configuration. Requires id (from GET /ai/v1/custom-canvas/request-state) and requestId. inputConfiguration is a full replacement; optional fields include subInputConfiguration, filters, limit, order. Response is 204 No Content. ```json { "id": "", "requestId": "", "inputConfiguration": { "datasetId": "", "measure": { "name": "orders.revenue", "title": "Revenue", "nativeType": "number", "description": null, "meta": null, "__type__": "measure" } }, "filters": {}, "limit": {}, "order": {} } ``` -------------------------------- ### Run Cube Data Playground with Docker Compose Source: https://github.com/embeddable-hq/handbook/blob/main/pages/data-modeling/testing-models.mdx Alternative way to start Cube's data playground using Docker Compose with the `cube-playground.yml` file. ```bash docker compose -f ./src/cube-playground.yml up ``` -------------------------------- ### FILTER_PARAMS lambda start value Source: https://github.com/embeddable-hq/handbook/blob/main/pages/data-modeling/filter-params.mdx Advanced usage: pass a lambda function to extract the start of the range as a separate value. The function receives x (start) and y (end). ```text {FILTER_PARAMS.orders.created_at.filter(lambda x, y: f"{x}")} ``` -------------------------------- ### Incremental pre-aggregation configuration with daily partitions Source: https://github.com/embeddable-hq/handbook/blob/main/pages/data-modeling/caching/level-2-cache/advanced-pre-aggregations.mdx Configures a partitioned pre-aggregation with a 365-day build range and incremental refresh. Requires a time_dimension and granularity. With incremental: true and update_window: 3 day, only the last three partitions refresh daily; without update_window, only the last day refreshes. ```yaml pre_aggregations: - name: daily_count_by_countries measures: - CUBE.count dimensions: - CUBE.country time_dimension: CUBE.signed_up_at granularity: day partition_granularity: day build_range_start: sql: SELECT NOW() - INTERVAL '365 day' build_range_end: sql: SELECT NOW() refresh_key: every: 1 day incremental: true update_window: 3 day ``` -------------------------------- ### Example values arrays for security filters Source: https://github.com/embeddable-hq/handbook/blob/main/pages/data-modeling/row-level-security/security-filters.mdx Example values arrays for the 'values' field. Values are always an array; for 'set' and 'notSet' operators, omit this field. These examples show single values, multiple values, and date ranges. ```yaml ["123"] ``` ```yaml ["United States", "Germany"] ``` ```yaml ["2025-08-23"] ``` ```yaml ["2025-01-01", "2025-03-31"] ``` -------------------------------- ### Composite index example for account_id and created_at Source: https://github.com/embeddable-hq/handbook/blob/main/pages/data-modeling/caching/level-2-cache/prerequisites.mdx Shows a composite filter query and the corresponding composite index definition. Column order should match common filter patterns. ```sql WHERE account_id = 42 AND created_at >= ? ``` ```text (account_id, created_at) ``` -------------------------------- ### Example Cube model file structure Source: https://github.com/embeddable-hq/handbook/blob/main/pages/data/using-cube-cloud-with-dbt.mdx This directory structure shows the recommended layout for Cube models, with each dbt model rendered as a separate cube file. It keeps templates simple and models maintainable. ```text model/cubes/ customers.yaml products.yaml orders.yaml ``` -------------------------------- ### Run Cube Data Playground Source: https://github.com/embeddable-hq/handbook/blob/main/pages/data-modeling/testing-models.mdx Executes the command to start Cube's data playground. ```bash npm run cube:playground ``` -------------------------------- ### EXPLAIN Syntax for Query Execution Plans Source: https://github.com/embeddable-hq/handbook/blob/main/pages/data-modeling/caching/level-2-cache/prerequisites.mdx Shows the generic syntax for generating a query execution plan in most databases. Use this to confirm index usage, verify partition pruning, identify full table scans, and validate performance improvements. ```sql EXPLAIN ```