Skip to main content
Version: v4 | v5 | v6 (latest)
A powerful JavaScript SDK for building custom applications within the Domo platform
npm version TypeScript domo.js (published as ryuu.js) is the official JavaScript SDK for building Custom Apps inside the Domo platform. Apps run inside iframes — domo.js handles authenticated HTTP requests, secure messaging with the parent window, mobile WebView bridges, and provides high-level helpers for Data, AppDB, Code Engine, Workflows, and AI services. Zero runtime dependencies. ~28KB UMD bundle. TypeScript included.

What’s New in v6

FeatureDescription
domo.intercept()Register request middleware — logging, retries, custom headers
Structured errorsDomoHttpError, DomoAuthError, DomoConnectionError, DomoValidationError, DomoTimeoutError
RequestOptions.schemaRuntime response validation with a custom parse function
domo.debugCategory-based debug logging, persisted via localStorage
Service namespacesdomo.data, domo.appdb, domo.ai, domo.workflow, domo.codeEngine
Optimized bundleReduced bundle size, zero runtime dependencies
For a full list of breaking changes, see Migration from v5.

Quick Start

Get started with ryuu.js in just a few lines:

Features

  • Data API — Query datasets with typed options (fields, filters, aggregations, date graining, beast modes)
  • AppDB — Full CRUD, MongoDB-style queries, bulk operations, partial updates, collection management
  • Code Engine — Run Code Engine functions by manifest alias
  • Workflows — Start and monitor Domo Workflows
  • AI Services — Text generation and text-to-SQL via Domo’s AI Service Layer
  • HTTP API Access — Authenticated requests to Domo datasets, datastores, and APIs
  • Real-time Events — Listen for dataset updates, filter changes, and variable updates
  • Filter Management — Get and set page-level filters programmatically
  • Variable Management — Access and update page variables
  • Custom App Data — Send custom data between apps on the same page
  • Typed Environmentdomo.env with userId, userName, host, platform, enriched from the environment API
  • Navigation — Programmatically navigate within Domo
  • Mobile Support — Full iOS and Android compatibility
  • TypeScript Ready — Complete type definitions with typed callbacks and generics
  • Zero Dependencies — ~28KB UMD bundle with no runtime dependencies
  • Extensibleextend() propagates overrides to all services (data, appdb, ai, etc.)
  • Structured Errors — Typed error classes (DomoHttpError, DomoAuthError, DomoConnectionError, DomoValidationError) with instanceof support
  • Schema Validation — Optional runtime response validation via { schema: { parse } } (works with zod, valibot, etc.)
  • Request Interceptors — Middleware pattern via domo.intercept() for logging, retry, caching
  • Debug Modedomo.debug.enable() for category-based logging of HTTP, messages, filters, variables

Installation

Requirements:
  • Node.js 16+ (for local development with the Domo CLI)
  • Modern browsers: Chrome 80+, Firefox 75+, Safari 13+, Edge 80+
  • Zero runtime dependencies — no npm install required inside your app bundle

NPM

Then import in your application:

CDN / Script Tag

Load the library directly from a CDN. The bundle exposes a global domo object:
When using the Domo CLI, domo init scaffolds a local domo.js file you can reference with <script src="domo.js"></script> instead.

TypeScript

Type definitions are included automatically:

Core Concepts

Architecture

Your Custom App runs in an <iframe> inside a Domo page. domo.js establishes communication between your app and the parent Domo window using two channels:
  • MessageChannel (inbound) — The SDK creates a MessageChannel and transfers port2 to the parent on subscribe. The parent sends filter updates, variable changes, and acks through port2; your app receives them on port1.
  • window.parent.postMessage (outbound) — Outbound messages (filter requests, variable requests, navigate) always use window.parent.postMessage so the parent can verify event.origin for security.
Domo is a static class — you never call new Domo(). All methods are called directly on the class:

ASK-ACK-REPLY Pattern

Async operations like updating filters and variables use a request-tracking pattern:
  1. ASK — Your app sends a request with a unique ID
  2. ACK — Parent acknowledges receipt (optional callback)
  3. REPLY — Parent sends the response when the operation completes (optional callback)

Token Injection

A single MutationObserver watches document.documentElement with subtree: true. For every DOM node added at any depth, it automatically injects the Domo session token (ryuu_sid) into relative href and src attributes. Token is fetched once per batch — you don’t need to manage auth manually.

Environment Context

domo.env provides typed access to the current user, instance, and page context. Properties are populated immediately from iframe query parameters, then enriched in the background from GET /domo/environment/v1 (which provides authoritative server-side values like host):
The loaded property indicates whether the environment API has finished loading. If it fails (e.g. running locally), query params serve as the fallback.
Environment properties come from URL parameters and can be spoofed. For secure user identification, always verify with the API:

Error Handling

v6 replaces generic errors with a structured hierarchy. Import only what you need:
ClassThrown WhenKey Properties
DomoHttpErrorNon-2xx HTTP responsestatus, statusText, body, headers
DomoAuthError401 or 403 responseExtends DomoHttpError
DomoConnectionErrorNetwork failure (fetch rejects)
DomoValidationErrorInvalid input or schema parse failureerrors[]
DomoTimeoutErrorRequest or message timeouturl
Always check DomoAuthError before DomoHttpError in your catch block — DomoAuthError extends DomoHttpError, so an instanceof DomoHttpError check will also match auth errors.
Recommended catch pattern:

Validation Errors

When you pass malformed data to filters or variables, ryuu.js throws a DomoValidationError and logs the expected data model to console.error:

API Reference

Service Namespaces

v6 introduces high-level service namespaces that handle URL construction and request formatting for you.

domo.data

Query datasets connected to your app via their manifest.json alias. Each dataset must be mapped in manifest.json under datasources before it can be queried by alias.
domo.data.query(alias, options?)
Query a dataset by its manifest alias. Supports all Data API query operators. Parameters:
  • alias (string, required) — Dataset alias from manifest.json
  • options (object, optional)
Supported options: fields, filter, avg, count, max, min, sum, unique, groupBy, dateGrain, calendar, orderBy, limit, offset, useBeastMode, format Returns: Promise<any>

domo.data.sql(alias, sql)
Run a SQL query against an aliased dataset. Parameters:
  • alias (string, required) — Dataset alias from manifest.json
  • sql (string, required) — SQL query string. The table name is the dataset alias.
Returns: Promise<any>
data.sql uses a POST request with Content-Type: text/plain. Keep this in mind if you’re using interceptors that inspect the request method. The SQL API does not support page filters or JOINs.

domo.appdb

Persistent document storage scoped to your Custom App. Each document lives in a collection and has a content field plus system-managed metadata.
appdb.create and appdb.update automatically wrap your document in { content: ... } if you pass a plain object — you don’t need to wrap it yourself.
Document CRUD

Query with MongoDB syntax

Partial update (MongoDB operators)

Bulk operations

Collection management & export

domo.ai

Generate text and convert natural language to SQL using Domo’s AI services.
domo.ai.generateText(prompt, options?)
Generate text using Domo’s LLM integration. Parameters:
  • prompt (string, required) — The input prompt
  • options (object, optional) — Model configuration
Returns: Promise<string>

domo.ai.textToSQL(question, options?)
Convert a natural language question into a SQL query. Parameters:
  • question (string, required) — Natural language question
  • options (object, optional)
    • dataSourceSchemas (array) — Dataset schema hints to improve SQL accuracy
Returns: Promise<{ choices: { output: string }[] }>
AI services consume AI credits. See your Domo instance rate card for details.

domo.workflow

Trigger and monitor Domo Workflow automations.
domo.workflow.start(alias, input?)
Trigger a workflow by its alias. Parameters:
  • alias (string, required) — Workflow alias defined in your app
  • input (object, optional) — Input data to pass to the workflow
Returns: Promise<{ id: string }> — The workflow instance

domo.workflow.getInstance(alias, instanceId)
Get the current status of a running workflow instance. Parameters:
  • alias (string, required) — Workflow alias
  • instanceId (string, required) — Instance ID returned by workflow.start()
Returns: Promise<{ state: string, ... }>
Requires a workflowMapping entry in your manifest.json mapping the alias to a Domo Workflow.

domo.codeEngine(alias, input?)

Invoke a Code Engine function by alias. Parameters:
  • alias (string, required) — Function alias from your app manifest
  • input (object, optional) — Input parameters
Returns: Promise<any> — The function’s return value
Requires a packageMapping entry in your manifest.json mapping the alias to a Code Engine function.

Event Listeners

All listener methods return an unsubscribe function. Call it to stop listening.

domo.onFiltersUpdated(callback)

Listen for page-level filter changes. Parameters:
  • callback(filters: Filter[]) => void
Returns: function — Unsubscribe function
Registering onFiltersUpdated sends requestFiltersUpdate(null) on first call, which clears all filters on the parent page. If you need to read current filters without clearing them, see the Filters guide below.
Filter object structure:
Supported operators: String operators:
  • "IN" — Value is in list
  • "NOT_IN" — Value is not in list
  • "CONTAINS" — Value contains string
  • "NOT_CONTAINS" — Value doesn’t contain string
  • "STARTS_WITH" — Value starts with string
  • "NOT_STARTS_WITH" — Value doesn’t start with string
  • "ENDS_WITH" — Value ends with string
  • "NOT_ENDS_WITH" — Value doesn’t end with string
Numeric / Date operators:
  • "EQUALS" — Equals value
  • "NOT_EQUALS" — Not equals value
  • "GREATER_THAN" — Greater than value
  • "GREAT_THAN_EQUALS_TO" — Greater than or equals value
  • "LESS_THAN" — Less than value
  • "LESS_THAN_EQUALS_TO" — Less than or equals value
  • "BETWEEN" — Between two values

domo.onVariablesUpdated(callback)

Listen for page variable changes. Parameters:
  • callback(variables: Variable[]) => void
Returns: function — Unsubscribe function
Variable object structure:

domo.onDataUpdated(callback)

Listen for dataset update events. Called when a dataset connected to your app is refreshed. Parameters:
  • callback(alias: string) => void
Returns: function — Unsubscribe function
Use Case: Refresh your app’s visualizations when underlying data changes without requiring a page reload.

domo.onAppDataUpdated(callback)

Listen for custom data sent by other apps on the same Domo page. Parameters:
  • callback(data: any) => void
Returns: function — Unsubscribe function
Use Case: Enable communication between multiple Custom Apps on the same Domo page.

Emitters

domo.requestFiltersUpdate(filters, pageStateUpdate?, onAck?, onReply?)

Push filter changes to the parent Domo page. Parameters:
  • filters (Filter[] | null, required) — Filters to apply. Pass null to clear all filters.
  • pageStateUpdate (boolean, optional) — If false, only the card-level filter state is updated (default: true)
  • onAck (function, optional) — Called when request is acknowledged
  • onReply (function, optional) — Called when request completes
Returns: string — Request ID
Passing null clears every filter on the parent page for all apps. This is also what onFiltersUpdated triggers automatically on first registration.

domo.requestVariablesUpdate(variables, onAck?, onReply?)

Push variable changes to the parent Domo page. Parameters:
  • variables (Variable[], required)
  • onAck (function, optional)
  • onReply (function, optional)
Returns: string — Request ID

domo.requestAppDataUpdate(data, onAck?, onReply?)

Send custom data to other apps on the same Domo page.

HTTP Methods

All HTTP methods return Promises and support multiple data formats. All methods throw structured errors — see Error Handling. The auth header X-DOMO-Ryuu-Session is injected automatically.

domo.get(url, options?)

Fetch data from a Domo dataset or API endpoint. Parameters:
  • url (string) — API endpoint URL
  • options (object, optional) — Request options
Returns: Promise<ResponseBody> Basic Usage:
Format Options:
Supported formats:
  • 'array-of-objects' (default) — Record<string, any>[]
  • 'array-of-arrays'ArrayResponseBody with .columns and .rows
  • 'csv' — CSV string
  • 'excel' — Blob
  • 'plain' — Plain text string
Query Parameters:
Best Practice: Always filter and paginate large datasets to avoid slow responses:

domo.getAll(urls, options?)

Fetch multiple endpoints in parallel and return results as an array.
With Options:

domo.post(url, body?, options?)


domo.put(url, body?, options?)


domo.delete(url, options?)


domo.domoHttp(method, url, options?, body?)

Low-level method used internally by all other HTTP helpers. Use this for HTTP methods not covered above (e.g. PATCH).

Request Interceptors

domo.intercept() registers middleware that wraps every HTTP request. Interceptors follow an onion model — each interceptor receives the request and a next function to call the next layer.
Interceptors wrap the fetch call — headers and auth tokens are already set when your interceptor runs.

domo.intercept(fn)

Parameters:
  • fn(request: Request, next: (request: Request) => Promise<Response>) => Promise<Response>
Returns: () => void — Call to remove the interceptor The config object passed to each interceptor has { method, url, headers, body }. Headers and auth tokens are already set when interceptors run.
Multiple interceptors are applied in registration order (first registered = outermost):

Schema Validation

Pass a schema option to any HTTP request to validate or transform the response at runtime. If parse throws, domo.js wraps it as DomoValidationError.
Works with any validation library:

domo.navigate(url, isNewWindow?)

Navigate the parent Domo page from inside your app iframe. Parameters:
  • url (string, required) — Domo page URL or route
  • isNewWindow (boolean, optional) — Open in new tab (default: false)
For mobile web platforms, routes are automatically prefixed with /m#. External links are restricted to whitelisted domains — configure in Admin > Network Security > Custom Apps authorized domains.

Utilities

domo.extend(overrides)

Override static methods or properties of the Domo class. Also updates the shared transport so overrides propagate to all service namespaces (data, appdb, ai, etc.).

domo.getRequests() / domo.getRequest(id)

Inspect the ASK-ACK-REPLY request lifecycle for tracked requests (filter updates, variable updates, etc.).

TypeScript Support

All types are exported from ryuu.js:
Typed requests:
Typed filters:
Custom data types:

Mobile Platform Support

domo.js detects the platform and routes messages through the appropriate bridge automatically. No configuration needed.
PlatformBridge used
Desktop / WebMessageChannel + window.parent.postMessage
iOSwebkit.messageHandlers (domofilter, domovariable)
Android / FlutterGlobal objects (window.domofilter, window.domovariable)
Platform detection:
Mobile considerations:
  • Navigation routes are automatically prefixed with /m# on mobile web
  • Test on actual devices or simulators — not just browser DevTools mobile emulation
  • Optimize data fetching: mobile devices have limited memory and CPU

Advanced Usage

Debug Mode

Enable category-based logging to inspect HTTP requests, messages, filters, and variables:
You can also enable debug mode without code changes — useful for debugging a live app:
Debug categories:
CategoryWhat it logs
httpEvery request: method, URL, headers, response status and body
messagesAll MessageChannel and postMessage traffic (inbound and outbound)
filtersFilter update events and subscriptions
variablesVariable update events and subscriptions
allEverything above
Example output:

Retry Logic

Implement retry logic for transient server errors using interceptors or a wrapper function:

Custom Fetch

Provide your own fetch implementation for testing, mocking, or custom network behavior:

Type Guards

Use type guards to validate runtime data before passing it to the SDK:

Filters In Depth

First-registration behavior

onFiltersUpdated clears all parent filters on first registration by sending requestFiltersUpdate(null). All subsequent listeners call connect(true) which skips this. If you need to subscribe without clearing:

Wire format

The filter event name on the wire is "filter" (not "filtersUpdated"). Desktop and mobile use different field names which domo.js normalizes for you:
FieldDesktopMobile
ColumncolumnNamecolumn
Operatoroperatoroperand

Complete Example

A real-world Custom App wiring together data, filters, variables, and navigation:

Migration from v5

Error handling

v5 — errors were thrown as generic Error objects or plain response objects. v6 — errors are typed classes. Update your catch blocks:

Service namespaces (new in v6)

v6 adds high-level service namespaces. You can still use the low-level HTTP methods — the namespaces are additive:

Debug logging

v5 — no built-in debug mode. v6 — use domo.debug.enable():

Interceptors (new in v6)

Unchanged

  • All low-level HTTP methods: domo.get, domo.post, domo.put, domo.delete, domo.getAll
  • Event listener APIs: onFiltersUpdated, onVariablesUpdated, onDataUpdated, onAppDataUpdated
  • Emitter APIs: requestFiltersUpdate, requestVariablesUpdate, requestAppDataUpdate
  • domo.navigate()
  • domo.extend()
  • domo.env shape
  • Static class design — no instantiation
  • npm package name (ryuu.js) and global (Domo)

Getting Help