omni-embed

SKILL.md

Omni Embed

Embed Omni dashboards in external applications using signed iframe URLs. The @omni-co/embed SDK handles URL signing and theme customization. Omni's postMessage events enable two-way communication between the parent app and embedded iframe.

Tip: Use omni-content-explorer to find dashboards to embed, and omni-admin to manage embed user permissions and user attributes for row-level security.

Prerequisites

npm install @omni-co/embed
export OMNI_BASE_URL="https://yourorg.embed-omniapp.co"   # Embed domain
export OMNI_EMBED_SECRET="your-embed-secret"               # Admin → Embed
export OMNI_API_KEY="your-api-key"                         # For user/content API calls

The embed secret is found in Admin → Embed in your Omni instance. The OMNI_BASE_URL for embedding uses the .embed-omniapp.co domain, not the standard .omniapp.co domain.

API Discovery

When unsure whether an endpoint or parameter exists, fetch the OpenAPI spec:

curl -L "$OMNI_BASE_URL/openapi.json" \
  -H "Authorization: Bearer $OMNI_API_KEY"

Use this to verify endpoints, available parameters, and request/response schemas before making calls.

Signing Embed URLs

Use embedSsoDashboard() from the @omni-co/embed SDK to generate a signed URL server-side, then load it in an iframe client-side.

import { embedSsoDashboard, EmbedSessionMode } from "@omni-co/embed";

const embedUrl = await embedSsoDashboard({
  contentId: "dashboard-uuid",
  secret: process.env.OMNI_EMBED_SECRET,
  host: "yourorg.embed-omniapp.co",       // Hostname only, no https://
  externalId: "user@example.com",
  name: "Jane Doe",
  userAttributes: { brand: ["Acme"] },     // For row-level security
  mode: EmbedSessionMode.SingleContent,
  prefersDark: "false",
});

Parameters

Parameter Required Description
contentId Yes Dashboard UUID (from URL or Admin → Dashboards)
secret Yes Embed secret from Admin → Embed
host Yes Embed hostname only — no protocol, no port
externalId Yes Unique user identifier (typically email)
name Yes Display name for the user
userAttributes No Record<string, string[]> for row-level security
mode No SingleContent (default) or Application (enables create)
prefersDark No "true" or "false" — controls light/dark mode
customTheme No Theme object (see Custom Themes below)
entity No Entity name for workspaces (see Entity Workspaces below)

Gotcha: The host parameter must be a bare hostname (e.g., yourorg.embed-omniapp.co). Including a protocol (https://) or port (:3000) causes Omni to return 400.

Custom Themes

Pass a customTheme object to embedSsoDashboard() to style the embedded dashboard content (tile backgrounds, text colors, controls, buttons). This controls what's inside the iframe — parent app styling is separate.

const embedUrl = await embedSsoDashboard({
  // ...signing params
  prefersDark: "false",
  customTheme: {
    "dashboard-background": "#FEF2F2",
    "dashboard-tile-background": "#FFF5F5",
    "dashboard-key-color": "#E60000",
    "dashboard-key-text-color": "#ffffff",
    // ...
  },
});

Property Reference

Page:

Property Description
dashboard-background Dashboard page background
dashboard-page-padding Dashboard page padding

Tiles:

Property Description
dashboard-tile-margin Spacing around tiles
dashboard-tile-background Tile background color
dashboard-tile-shadow Tile box shadow
dashboard-tile-text-body-color Primary text color in tiles
dashboard-tile-text-secondary-color Secondary text color in tiles
dashboard-tile-border-color Tile border color
dashboard-tile-border-radius Tile border radius
dashboard-tile-border-style Tile border style
dashboard-tile-border-width Tile border width
dashboard-tile-title-font-size Title font size
dashboard-tile-title-font-weight Title font weight
dashboard-tile-title-text-color Title text color
dashboard-tile-title-font-family Custom title font (woff2 URL)
dashboard-tile-text-body-font-family Custom body font
dashboard-tile-text-code-font-family Custom code font

Controls (filter dropdowns):

Property Description
dashboard-control-background Filter control background
dashboard-control-radius Filter control border radius
dashboard-control-border-color Filter control border color
dashboard-control-text-color Filter control text color
dashboard-control-placeholder-color Placeholder text color
dashboard-control-label-color Label text above controls
dashboard-control-outline-color Focus outline color

Control Popovers (dropdown menus):

Property Description
dashboard-control-popover-background Popover background
dashboard-control-popover-text-color Popover text color
dashboard-control-popover-secondary-text-color Secondary text in popovers
dashboard-control-popover-link-color Link color in popovers
dashboard-control-popover-divider-color Divider color
dashboard-control-popover-radius Popover border radius
dashboard-control-popover-border-color Popover border color
dashboard-filter-input-background Filter input background
dashboard-filter-input-radius Filter input border radius
dashboard-filter-input-border-color Filter input border color
dashboard-filter-input-text-color Filter input text color
dashboard-filter-input-placeholder-color Placeholder text
dashboard-filter-input-icon-color Icon color in filter inputs
dashboard-filter-input-outline-color Focus outline for filter inputs
dashboard-filter-input-accent-color Checkbox, radio, and toggle color
dashboard-filter-input-accent-invert-color Checkmark/dot color inside inputs
dashboard-filter-input-token-color Multi-select token background
dashboard-filter-input-token-text-color Multi-select token text color

Buttons:

Property Description
dashboard-key-color Primary action color (Update buttons)
dashboard-key-text-color Text color on primary buttons
dashboard-button-radius Button border radius
dashboard-button-transparent-text-color Transparent button text color
dashboard-button-transparent-interactive-color Transparent button hover color
dashboard-menu-item-interactive-color Menu item hover background

Supported CSS Values

  • Hex colors: "#FEF2F2", "#E60000"
  • Box shadows with rgba: "0 2px 8px rgba(230, 0, 0, 0.1)"
  • Custom fonts via URL: "url(https://fonts.gstatic.com/...) format('woff2')"
  • Empty strings to clear defaults: ""
  • linear-gradient() and rgba() for backgrounds work in Omni's UI theme editor but may fail when passed via the SDK — use solid hex colors for reliability

Theming Tips

For effective branding, tint backgrounds throughout rather than only coloring buttons:

  • dashboard-background → light brand tint (like Tailwind's color-50)
  • dashboard-tile-background → slightly lighter than page background
  • dashboard-tile-title-text-color → brand primary (titles in brand color)
  • dashboard-control-label-color → brand primary (labels in brand color)
  • dashboard-tile-border-color → medium-light brand tint (like color-200)
  • dashboard-key-color → brand primary
  • dashboard-filter-input-accent-color → brand primary (checkboxes, toggles)

Embed Events

Omni communicates with the parent app via postMessage. All Omni events have source: "omni".

Listening for Events

window.addEventListener("message", (event) => {
  if (event.data?.source !== "omni") return;

  switch (event.data.name) {
    case "dashboard:loaded":
      // Dashboard ready
      break;
    case "error":
      // Handle error
      break;
    case "dashboard:tile-drill":
      // Handle drill action
      break;
  }
});

Event Reference

dashboard:loaded — Fired when the embedded dashboard finishes loading.

{ "source": "omni", "name": "dashboard:loaded" }

dashboard:filters — Fired when filter state changes inside the embedded dashboard.

{
  "source": "omni",
  "name": "dashboard:filters",
  "payload": { /* filter state */ }
}

error — Fired when a detectable error occurs on the embedded page.

{
  "source": "omni",
  "name": "error",
  "payload": {
    "href": "https://...",
    "message": "Error description"
  }
}

dashboard:tile-drill — Fired when a user drills on any dashboard tile (charts, tables, maps). No Omni-side configuration required.

{
  "source": "omni",
  "name": "dashboard:tile-drill",
  "payload": {
    "userId": "string",
    "dashboard": {
      "filters": {
        "filterName": {
          "filter": {},
          "asJsonUrlSearchParam": "string"
        }
      },
      "href": "string",
      "urlId": "string",
      "path": "string",
      "title": "string"
    },
    "tile": {
      "id": "string",
      "title": "string",
      "appliedFilters": {
        "filterName": {
          "filter": {},
          "asJsonUrlSearchParam": "string"
        }
      }
    },
    "drill": {
      "field": "string",
      "fieldLabel": "string",
      "drillQueryLabel": "string",
      "rowToDrill": { "field_name": "value" }
    }
  }
}

Use drill.rowToDrill for the data from the drilled row. Use asJsonUrlSearchParam from tile.appliedFilters or dashboard.filters to sign and embed a different dashboard with those filters applied.

page:changed — Fired when the URL changes inside the iframe (including after saving a new dashboard).

{
  "source": "omni",
  "name": "page:changed",
  "payload": {
    "pathname": "string",
    "type": "string"
  }
}

Custom visualization events — Fired when a user clicks a configured table row or markdown link. Requires setup in Omni: set the table column's Display to LinkEmbed event and enter an event name. For markdown, use <omni-message> tags.

{
  "source": "omni",
  "name": "<your-event-name>",
  "payload": {
    "data": "comma-separated values"
  }
}

Table setup: field dropdown → Display tab → Display as: Link → URL: Embed event → enter event name.

Markdown setup:

<omni-message event-name="product-click" event-data="{{products.name.raw}},{{products.retail_price.raw}}">
  Click here
</omni-message>

Sending Events to the Iframe

dashboard:filter-change-by-url-parameter — Push a filter from the parent app into the embedded dashboard.

iframe.contentWindow.postMessage({
  source: "omni",
  name: "dashboard:filter-change-by-url-parameter",
  payload: {
    filterUrlParameter: 'f--<filter_id>={"values":["value1","value2"]}'
  }
}, iframeOrigin);

Get the filterUrlParameter string by opening the dashboard in Omni, changing filter values, and copying the f-- parameter from the URL.

Entity Workspaces

Entity workspaces let embed users create and save their own dashboards within a scoped folder.

import {
  embedSsoDashboard,
  EmbedSessionMode,
  EmbedEntityFolderContentRoles,
  EmbedUiSettings,
  EmbedConnectionRoles,
} from "@omni-co/embed";

const embedUrl = await embedSsoDashboard({
  // ...standard signing params
  entity: "acme",
  entityFolderContentRole: EmbedEntityFolderContentRoles.EDITOR,
  mode: EmbedSessionMode.Application,
  uiSettings: {
    [EmbedUiSettings.SHOW_NAVIGATION]: false,
  },
  connectionRoles: {
    "connection-uuid": EmbedConnectionRoles.RESTRICTED_QUERIER,
  },
});
Parameter Description
entity Entity name — scopes the user's folder (e.g., derived from email domain)
entityFolderContentRole EDITOR lets users create/edit dashboards in their entity folder
mode Must be Application to enable create features
uiSettings Control Omni's built-in UI (e.g., hide Omni's sidebar if you provide your own)
connectionRoles Grant query access: RESTRICTED_QUERIER for data exploration

Embed Users and Permissions

When building permission-aware experiences (e.g., a sidebar that only shows dashboards a user can access), use these REST API calls. Note: API calls use the .omniapp.co domain, not the .embed-omniapp.co embed domain.

Look Up an Embed User

curl -L "$OMNI_API_BASE/api/scim/v2/embed/users?filter=embedExternalId%20eq%20%22user@example.com%22" \
  -H "Authorization: Bearer $OMNI_API_KEY"

Returns the Omni user ID for the given externalId. If no user is found, the user hasn't accessed any embedded dashboards yet.

List Documents by User Permission

curl -L "$OMNI_API_BASE/api/v1/documents?userId={omniUserId}" \
  -H "Authorization: Bearer $OMNI_API_KEY"

Response uses records array (not documents):

{
  "pageInfo": {
    "hasNextPage": false,
    "nextCursor": null,
    "pageSize": 20,
    "totalRecords": 5
  },
  "records": [
    {
      "identifier": "fb007aa3",
      "name": "Sales Dashboard",
      "hasDashboard": true,
      "folder": {
        "id": "...",
        "name": "Sales",
        "path": "sales/regional"
      }
    }
  ]
}

Use identifier as the contentId for embed signing. Filter for hasDashboard: true to get embeddable dashboards only.

List Folders for Friendly Names

Entity folders have technical paths like omni-system-sso-embed-entity-folder-poc. Map paths to display names:

curl -L "$OMNI_API_BASE/api/v1/folders" \
  -H "Authorization: Bearer $OMNI_API_KEY"

Build a path → name mapping from the response to display user-friendly folder names.

Domain Mapping

The embed domain (.embed-omniapp.co) and API domain (.omniapp.co) are different:

Embed: yourorg.embed-omniapp.co  →  used for iframe URLs
API:   yourorg.omniapp.co        →  used for REST API calls

When your app stores the embed domain, convert it for API calls by replacing .embed-omniapp.co with .omniapp.co.

Docs Reference

Related Skills

  • omni-content-explorer — find dashboards to embed
  • omni-content-builder — create dashboards before embedding them
  • omni-admin — manage embed user permissions, user attributes for RLS, and connections
  • omni-model-explorer — understand available fields for embed event data
Weekly Installs
6
GitHub Stars
4
First Seen
12 days ago
Installed on
claude-code6
opencode4
antigravity4
github-copilot4
codex4
zencoder4