Dashboards SDK API
Access the dashboards namespace via sdk.dashboards. A dashboard session
(Dashboard instance) is opened with sdk.dashboards.open() or
sdk.dashboards.view() and communicates over a live Y.js CRDT document.
The visibility field accepts private, workspace, and public. (unlisted
is a retired legacy alias, still accepted on the API and treated as public.)
Top-level: sdk.dashboards
Section titled “Top-level: sdk.dashboards”sdk.dashboards.create()
Section titled “sdk.dashboards.create()”create(options: CreateOptions): Promise<CreateResult>
interface CreateOptions { title: string; description?: string; template?: string; layout?: 'fixed' | 'responsive'; columns?: number; // default 12 rowHeight?: number; // default 80 (px) visibility?: 'private' | 'workspace' | 'public';}
interface CreateResult { id: string; editorUrl: string; // shareout.site/a/{slug} publishedUrl: string; // shareout.site/p/{slug} editorArtifactId: string; publishedArtifactId: string;}const result = await sdk.dashboards.create({ title: 'Sales Dashboard', visibility: 'public',});sdk.dashboards.open()
Section titled “sdk.dashboards.open()”Open a dashboard for editing. Requires authentication. Returns a connected
Dashboard instance.
open(id: string): Promise<Dashboard>sdk.dashboards.view()
Section titled “sdk.dashboards.view()”Open a dashboard in published/view mode. No authentication required for
public dashboards.
view(id: string): Promise<Dashboard>sdk.dashboards.list()
Section titled “sdk.dashboards.list()”list(): Promise<DashboardInfo[]>
interface DashboardInfo { id: string; title: string; widgetCount: number; editorUrl: string; publishedUrl: string; visibility: 'private' | 'workspace' | 'public'; createdAt: string; updatedAt: string;}sdk.dashboards.delete()
Section titled “sdk.dashboards.delete()”delete(id: string): Promise<boolean>Returns false if not found, throws on other errors.
Dashboard instance
Section titled “Dashboard instance”Returned by open() and view(). The connection is established automatically
by both methods; you do not need to call connect() manually.
connect(): Promise<void> // re-connect after disconnectdisconnect(): void // disconnect but keep documentdestroy(): void // full cleanupdashboard.meta
Section titled “dashboard.meta”Dashboard-level settings. Properties set here cascade to all widgets unless a widget specifies an override.
meta.get()
Section titled “meta.get()”get(): DashboardMeta
interface DashboardMeta { id: string; title: string; description: string;
// Layout layout: 'fixed' | 'responsive'; columns: number; rowHeight: number; gap: number; padding: number;
// Cascading visual defaults (inherited by widgets) defaultFont: { heading: string; body: string; mono: string }; defaultColors: { background: string; surface: string; text: string; textSecondary: string; accent: string; positive: string; negative: string; neutral: string; };
// Data defaults refreshInterval: number | null; // auto-refresh in seconds timezone: string; dateFormat: string; numberFormat: { locale: string; currency?: string };
createdBy: string; updatedAt: string;}meta.set()
Section titled “meta.set()”set(changes: Partial<DashboardMeta>): voiddashboard.meta.set({ title: 'Q4 Sales Dashboard', defaultColors: { background: '#0f172a', surface: '#1e293b', text: '#f8fafc', accent: '#3b82f6', }, refreshInterval: 300,});meta.observe()
Section titled “meta.observe()”observe(handler: (meta: DashboardMeta) => void): () => voidReturns an unsubscribe function.
dashboard.widgets
Section titled “dashboard.widgets”widgets.list()
Section titled “widgets.list()”list(): Widget[]
interface Widget { id: string; type: WidgetType; title: string; dataSource: string | null; query?: DataQuery; config: WidgetConfig; overrides?: WidgetOverrides; owner: string | null; locked: boolean;}
type WidgetType = 'kpi' | 'chart' | 'table' | 'text' | 'image' | 'embed' | 'filter' | 'html';
interface DataQuery { filter?: Record<string, any>; sort?: { field: string; order: 'asc' | 'desc' }; limit?: number; transform?: string; // JavaScript transform expression}
interface WidgetOverrides { surface?: string; font?: { heading?: string; body?: string; mono?: string };}widgets.get()
Section titled “widgets.get()”get(id: string): Widget | nullwidgets.add()
Section titled “widgets.add()”add(type: WidgetType, config: WidgetConfig, position?: LayoutItem): Widget
interface LayoutItem { x: number; // column start (0-indexed) y: number; // row start w: number; // width in columns h: number; // height in rows minW?: number; maxW?: number; minH?: number; maxH?: number;}Config shapes per type — see KPI config, Chart config, Table config below.
widgets.update()
Section titled “widgets.update()”update(id: string, changes: Partial<Widget>): voidwidgets.delete()
Section titled “widgets.delete()”delete(id: string): booleanwidgets.duplicate()
Section titled “widgets.duplicate()”duplicate(id: string): Widgetwidgets.observe()
Section titled “widgets.observe()”observe(handler: (widgets: Widget[]) => void): () => voidwidgets.getContent() / widgets.setContent()
Section titled “widgets.getContent() / widgets.setContent()”For html and text widgets. getContent() returns a Y.Text for
collaborative binding; setContent() replaces content directly.
getContent(id: string): Y.TextsetContent(id: string, html: string): voidwidgets.setOwner() / widgets.lock() / widgets.unlock()
Section titled “widgets.setOwner() / widgets.lock() / widgets.unlock()”setOwner(id: string, userId: string | null): voidlock(id: string): voidunlock(id: string): voidLocked widgets can only be edited by their owner.
dashboard.layout
Section titled “dashboard.layout”Grid position management.
get(): LayoutItem[]update(widgetId: string, position: Partial<LayoutItem>): voidmove(widgetId: string, x: number, y: number): voidresize(widgetId: string, w: number, h: number): voidobserve(handler: (layout: LayoutItem[]) => void): () => voiddashboard.dataSources
Section titled “dashboard.dataSources”type DataSourceType = 'static' | 'api' | 'sql' | 'shareout' | 'csv' | 'websocket';
interface DataSource { id: string; name: string; type: DataSourceType; config: DataSourceConfig; refreshInterval?: number; lastRefreshed?: string;}Methods
Section titled “Methods”list(): DataSource[]add(config: Omit<DataSource, 'id'>): DataSourceupdate(id: string, changes: Partial<DataSource>): voiddelete(id: string): booleanrefresh(id: string): Promise<void>refreshAll(): Promise<void>getData(id: string): any[]getFilteredData(id: string): any[]observe(id: string, handler: (data: any[]) => void): () => void// Static datadashboard.dataSources.add({ name: 'Sales Data', type: 'static', config: { data: salesArray },});
// REST API with auto-refreshdashboard.dataSources.add({ name: 'Live Metrics', type: 'api', config: { url: 'https://api.example.com/metrics', method: 'GET', headers: { Authorization: 'Bearer ...' }, }, refreshInterval: 60,});
// ShareOut tabledashboard.dataSources.add({ name: 'Customers', type: 'shareout', config: { tableId: 'customers' },});dashboard.filters
Section titled “dashboard.filters”Filter definitions
Section titled “Filter definitions”interface FilterDefinition { id: string; type: 'select' | 'multiselect' | 'daterange' | 'numberrange' | 'search'; label: string; dataSource?: string; field?: string; options?: { value: string; label: string }[]; defaultValue?: FilterValue; affects: string[]; // widget IDs or '*' for all}
type FilterValue = | string | string[] | { from: string; to: string } | { min: number; max: number };Methods
Section titled “Methods”getDefinitions(): FilterDefinition[]addDefinition(def: Omit<FilterDefinition, 'id'>): FilterDefinitionupdateDefinition(id: string, changes: Partial<FilterDefinition>): voiddeleteDefinition(id: string): booleangetState(): FilterState // { [filterId]: FilterValue }setValue(filterId: string, value: FilterValue): voidreset(): void // reset all to defaultsobserve(handler: (state: FilterState) => void): () => voiddashboard.presets
Section titled “dashboard.presets”Saved filter combinations for quick access.
interface FilterPreset { id: string; name: string; description?: string; icon?: string; color?: string; filters: FilterState; isDefault: boolean; isPinned: boolean; isShared: boolean; createdBy: string; createdAt: string;}list(): FilterPreset[]create(preset: Omit<FilterPreset, 'id' | 'createdAt'>): FilterPresetupdate(id: string, changes: Partial<FilterPreset>): voiddelete(id: string): booleanapply(id: string): voidsetDefault(id: string | null): voidgetDefault(): FilterPreset | nullpin(id: string): voidunpin(id: string): voidgetPinned(): FilterPreset[]observe(handler: (presets: FilterPreset[]) => void): () => voiddashboard.presets.create({ name: 'Q4 2026', icon: '📊', filters: dashboard.filters.getState(), isPinned: true, isShared: true, isDefault: false,});
dashboard.presets.apply('preset-q4-2026');dashboard.presets.setDefault('preset-this-week');dashboard.interactions
Section titled “dashboard.interactions”Cross-widget interactions: clicking one widget filters others.
interface InteractionConfig { id?: string; trigger: { widgetId: string; event: 'click' | 'select' | 'hover'; field?: string; }; action: { type: 'filter' | 'navigate' | 'highlight' | 'custom'; target: string | string[]; // widget IDs or '*' config: any; };}define(config: InteractionConfig): string // returns interaction IDremove(id: string): voidlist(): InteractionConfig[]trigger(widgetId: string, event: 'click' | 'select' | 'hover', data: Record<string, unknown>): voidonInteraction(handler: (event: InteractionEvent) => void): () => voidonWidgetInteraction(widgetId: string, handler: (event: InteractionEvent) => void): () => voiddashboard.interactions.define({ trigger: { widgetId: 'sales-chart', event: 'click', field: 'region' }, action: { type: 'filter', target: ['sales-table', 'kpi-revenue'], config: { filterField: 'region' }, },});dashboard.presenter
Section titled “dashboard.presenter”Presenter mode syncs focus, pointer, and cycling to all viewers in real time.
start(options?: PresenterOptions): Promise<void>stop(): voidstate(): DashboardPresentationStateisActive(): booleanisPresenter(): boolean
// Widget focusfocusWidget(widgetId: string): voidclearFocus(): voidnextWidget(): voidpreviousWidget(): void
// Auto-cyclingstartCycle(options?: CycleOptions): voidstopCycle(): void
// Timertimer.elapsed(): numbertimer.setCountdown(seconds: number): voidtimer.remaining(): number | nulltimer.pause(): voidtimer.resume(): void
// Pointerpointer.enable(): voidpointer.disable(): voidpointer.move(x: number, y: number): void
subscribe(handler: (state: DashboardPresentationState) => void): () => voidawait dashboard.presenter.start({ countdown: 1800 }); // 30-min timerdashboard.presenter.focusWidget('kpi-revenue');dashboard.presenter.startCycle({ interval: 30, loop: true });dashboard.versions
Section titled “dashboard.versions”versions.list(): Promise<Version[]>versions.create(name: string, description?: string): Promise<Version>versions.restore(versionId: string): Promise<void>versions.diff(fromId: string, toId: string): Promise<VersionDiff>versions.delete(versionId: string): Promise<boolean>versions.subscribe(handler: (versions: Version[]) => void): () => voidawait dashboard.versions.create('Before meeting', 'Snapshot before live edits');const versions = await dashboard.versions.list();await dashboard.versions.restore(versions[2].id);dashboard.publish
Section titled “dashboard.publish”getUrl(): string // shareout.site/p/{slug}setVisibility(v: 'private' | 'workspace' | 'public'): voidunpublish(): voidrepublish(): voiddashboard.presence
Section titled “dashboard.presence”Ephemeral user presence over WebSocket (not persisted in the Y.js document).
set(state: Partial<DashboardPresenceState>): voidget(): Map<string, DashboardPresenceState>subscribe(handler: (users: Map<string, DashboardPresenceState>) => void): () => voiddashboard.undo
Section titled “dashboard.undo”Per-user undo stack scoped to the current user’s own changes.
undo.manager(): Y.UndoManagerundo.canUndo(): booleanundo.canRedo(): booleanundo.undo(): voidundo.redo(): voiddashboard.transact()
Section titled “dashboard.transact()”Batch multiple changes into a single undo step.
transact(fn: () => void): voiddashboard.transact(() => { const widget = dashboard.widgets.add('kpi', config, position); dashboard.widgets.setOwner(widget.id, currentUserId);});// Both changes appear as one undo stepEvents
Section titled “Events”dashboard.on(event: DashboardEvent, handler: Function): voiddashboard.off(event: DashboardEvent, handler: Function): void
type DashboardEvent = | 'widget:added' | 'widget:deleted' | 'widget:updated' | 'layout:changed' | 'filter:changed' | 'data:refreshed' | 'presentation:start' | 'presentation:end' | 'sync' | 'status';sdk.dashboards.helpers
Section titled “sdk.dashboards.helpers”Formatting and data utilities.
helpers.formatNumber(value: number, options?: Intl.NumberFormatOptions): stringhelpers.formatCurrency(value: number, currency?: string): stringhelpers.formatPercent(value: number, decimals?: number): stringhelpers.formatDate(date: Date | string, format?: string): string
helpers.getColorScale(type: 'sequential' | 'diverging' | 'categorical', name?: string): string[]helpers.getSemanticColor(type: 'positive' | 'negative' | 'neutral' | 'warning'): string
helpers.aggregate(data: any[], groupBy: string, aggs: Aggregation[]): any[]helpers.pivot(data: any[], rows: string, cols: string, values: string): any[]helpers.timeSeries(data: any[], dateField: string, interval: 'day' | 'week' | 'month'): any[]Widget config types
Section titled “Widget config types”KPI config
Section titled “KPI config”interface KPIConfig { value: string; label: string; format: 'number' | 'currency' | 'percent' | 'custom'; formatOptions?: Intl.NumberFormatOptions; comparison?: { value: string; type: 'absolute' | 'percent'; invertColors?: boolean; }; sparkline?: { field: string; type: 'line' | 'bar' | 'area' }; icon?: string; size?: 'sm' | 'md' | 'lg';}Chart config
Section titled “Chart config”interface ChartConfig { chartType: 'line' | 'bar' | 'area' | 'pie' | 'donut' | 'scatter' | 'heatmap' | 'gauge' | 'funnel' | 'treemap'; xAxis?: { field: string; type: 'category' | 'time' | 'value'; label?: string }; yAxis?: { field: string; label?: string; min?: number; max?: number }; series?: { field: string; name?: string; color?: string }[]; nameField?: string; valueField?: string; legend?: { show: boolean; position: 'top' | 'bottom' | 'left' | 'right' }; tooltip?: { show: boolean }; animation?: boolean;}Table config
Section titled “Table config”interface TableConfig { columns: TableColumn[]; pageSize?: number; sortable?: boolean; filterable?: boolean; exportable?: boolean; selectable?: boolean; condensed?: boolean; striped?: boolean;}
interface TableColumn { field: string; header: string; width?: string; align?: 'left' | 'center' | 'right'; format?: 'text' | 'number' | 'currency' | 'percent' | 'date' | 'boolean' | 'link' | 'image' | 'badge'; sortable?: boolean; filterable?: boolean;}Text config
Section titled “Text config”interface TextConfig { content: string; contentType: 'markdown' | 'html'; align?: 'left' | 'center' | 'right'; padding?: number;}HTML config
Section titled “HTML config”interface HTMLConfig { content: string; scripts?: boolean; // default false}Data model
Section titled “Data model”The Y.js document backing each dashboard has the following top-level maps:
| Map | Type | Contents |
|---|---|---|
meta | Y.Map | Dashboard metadata and cascading visual properties |
widgets | Y.Map<string, Widget> | Widget definitions keyed by widget ID |
widgetContent | Y.Map<string, Y.Text> | Collaborative HTML/text content for html and text widgets |
layout | Y.Map<string, LayoutItem> | Grid positions keyed by widget ID |
dataSources | Y.Map<string, DataSource> | Data connection configs |
filters | Y.Map<string, FilterValue> | Current filter state |
filterDefs | Y.Array<FilterDefinition> | Filter definitions |
filterPresets | Y.Map<string, FilterPreset> | Saved filter combinations |
interactions | Y.Map<string, InteractionConfig> | Cross-widget interaction configs |
presentationState | Y.Map | Live presenter state (synced to all viewers) |
Presence state is ephemeral — it is not in the Y.js document; it travels over the WebSocket only.
Version snapshots are stored separately as Y.js encoded state vectors in the
dashboard_versions table, not embedded in the live document.