# AI Hub Source: https://docs.omni.co/administration/ai-hub Monitor how your organization uses Omni AI — adoption, answer quality, and credit usage — from a single admin space. The AI Hub is an admin space for managing and monitoring how your organization uses Omni's AI. It brings your AI settings together with adoption, answer quality, and credit usage in one place. From here you can configure AI features and see what people are asking, whether the AI is answering well, and where activity is concentrated. ## Requirements * **Organization Admin** permissions are required to access the AI Hub * Your organization must have Omni AI enabled. ## Accessing the AI Hub Select **AI Hub** in the [sidebar](/administration/settings/sidebar) of your Omni instance. ## Configure AI settings Omni's AI features are enabled by default. Use these settings to selectively enable or disable features, customize the AI chat interface, or connect a different model provider. Enable or disable individual AI features. Enable or disable individual [MCP Server](/ai/mcp) settings. Customize the appearance of the AI chat interface. Configure an alternative AI model provider. ## Dashboards The dashboards in the AI Hub allow you to see how your users are using AI. Use the model selector dropdown in the sidebar to filter the dashboards to a specific shared model. To be included in the dashboards, a model must have at least 50 AI prompts across at least 5 sessions in the last 30 days. Data refreshes once per day. This means that the current day's activity will be available on the following day. | Dashboard | What it shows | | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Overview** | Start here to gauge overall adoption and health at a glance. | | **Quality** | How well the AI is answering questions: analysis of user feedback. Read the questions users asked and spot where the AI struggles or where your model needs more context. | | **Usage** | Activity broken down by user and surface, so you can see who is using AI the most and where activity is concentrated. Useful for understanding adoption and attributing usage. | | [**Credit tracking**](/ai/settings/usage#detailed-usage) | How AI credits are being consumed across your organization, broken down by feature and user. This reflects activity across all models; using the model selector will not change the results. | ## Improve answer quality Once you've reviewed the Quality dashboard, use these tools to act on what you've learned. Apply prioritized recommendations to improve your model's AI context, based on user feedback. Run prompt sets through your model to score AI accuracy and catch regressions before they reach users. ## Next steps * [AI credit tracking](/ai/settings/usage) — Monitor AI credit usage across your organization * [Optimize your models for AI](/modeling/develop/ai-optimization) — Improve answer quality by adding context to your model * [AI data privacy](/ai/security) — Learn how Omni's AI features process data # Usage analytics Source: https://docs.omni.co/administration/analytics Gain insight into how Omni is being used in your organization. The **Analytics** dashboard, accessed by clicking the **Analytics** option in the [sidebar](/administration/settings/sidebar) of your Omni organization, is an embedded instance of Omni, in Omni. Along with giving admins information about how their users are using Omni, this section of the app also contains product updates and details about experimental and beta features. ## Requirements **Organization Admin** permissions are required to access the Analytics dashboard and use production topics in analyses. ## Pre-built dashboards Analytics comes with several ready-to-use dashboards, built on curated production topics modeled from system activity. These dashboards are continuously updated as new data becomes available. | **Dashboard** | **Description** | | ----------------------------------------- | --------------------------------------------------------------------------------------------------- | | **Overview** | High-level summary of user activity | | **Users** | User logins, frequency of activity, and engagement across Omni. | | **Content** | Workbook and dashboard usage | | **Model** | Model-level performance metrics such as query execution times, join complexity, and usage frequency | | **Schedules** | Scheduled deliveries, success/failure rates, and destination types. | | **AI** | Logs of AI interactions, including prompts, responses, and linked sessions | | **[Credit Tracking](/ai/settings/usage)** | AI token consumption across features, users, and groups | | **Changelog** | Weekly updates of Omni releases, including new features and fixes | | **Features** | Available experimental and beta features, including whether they're enabled in your instance | ## Data freshness The data in the Analytics dashboard and the underlying production topics may be on a slight delay, compared to live usage. ## Building your own analyses Beyond the pre-built dashboards, Organization Admins can explore or build their own analyses using the same production topics the Analytics dashboard is built on. The content built from these topics will remain separate from the other content in your instance unless you choose to share it. ### Sharing and deliveries URL sharing is not currently supported in Analytics. While you can share and schedule content built from production topics, there are a few things to keep in mind: * **Content can be directly shared only with other Admin users**. Non-admin users can't log in to the Analytics workspace, so they won't be able to view the content. * **Deliveries and alerts are supported for content built on production topics**. When creating an Analytics-based delivery, note that: * You can add email-only recipients * Other Admin users must open the Analytics dashboard at least once to appear as a selectable recipient * Slack destinations are not supported # Using Amazon S3 for Omni audit logs Source: https://docs.omni.co/administration/audit-logs/amazon-s3 Track Omni user activity in your instance with structured logs, accessible in an Amazon S3 bucket. Reach out to Omni support to have audit logs enabled for your instance. Audit logs are detailed records of the activity your users are taking in Omni, which can be useful for security and performance analysis. Events included in logs are structured as JSON payloads and sent in batches to an Omni-owned cloud storage bucket a few minutes after they're written. ## Requirements To follow the steps in this guide, you'll need: * To have audit logs enabled in your Omni instance * Permissions in AWS that allow you to manage IAM roles ## Setup After audit logs are enabled in your instance, complete the following: Reach out to Omni support with the name of the AWS IAM role you want to use. Omni support completes the configuration on the Omni side. ## Next steps * Learn about the [event types](/administration/audit-logs/event-types) supported for audit logs * Check out your instance's [Analytics section](/administration/analytics) # Using Azure Blob Storage for Omni audit logs Source: https://docs.omni.co/administration/audit-logs/azure-blob-storage Track Omni user activity in your instance with structured logs, accessible in an Azure Blob Storage container via a Microsoft Entra application or a SAS token. Reach out to Omni support to have audit logs enabled for your instance. Audit logs are detailed records of the activity your users are taking in Omni, which can be useful for security and performance analysis. Events included in logs are structured as JSON payloads and sent in batches to your cloud storage a few minutes after they're written. For Azure, Omni hosts the storage: Omni creates a dedicated storage account and blob container for your instance. You can read your logs using either of two access methods: | | **Microsoft Entra application** (recommended) | **SAS token** | | --------------------- | --------------------------------------------------------------------- | ------------------------------------------ | | Credentials exchanged | None — you authenticate with your own application's credential | Omni shares a read-only SAS token with you | | Best for | Custom tooling, Azure SDKs, anything that can authenticate with Entra | Tools that only support SAS authentication | ## Option 1: Microsoft Entra application (recommended) Omni grants a Microsoft Entra application that you own read access to your container. You read your logs by authenticating with your own application's credential — there are no storage account keys or SAS tokens to manage, and no credentials are exchanged between you and Omni. ### Requirements To follow the steps in this guide, you'll need: * To have audit logs enabled in your Omni instance * A **multitenant** Microsoft Entra application registered in your tenant, with a client secret or certificate * Permissions to register an application in your tenant and read its application (client) ID ### Setup After audit logs are enabled in your instance, complete the following: In the [Microsoft Entra admin center](https://entra.microsoft.com), navigate to **App registrations > New registration**. * Set **Supported account types** to **Accounts in any organizational directory (multitenant)**. This is required so Omni can create a service principal for your application in Omni's tenant and grant it access. * Under **Certificates & secrets**, add a client secret or certificate. This credential stays in your tenant and is never shared with Omni. * Copy the **Application (client) ID**. No API permissions are required — you can ignore (or remove) the default `User.Read` permission. Reach out to Omni support with the following: * **Application (client) ID** — the UUID of your multitenant application * **Tenant ID** — your Entra tenant ID (the application's home tenant) Omni provisions a service principal for your application in Omni's tenant, creates your blob container, grants that service principal the `Storage Blob Data Reader` role on it, and starts delivering audit logs. Omni support will share: * **Omni's tenant ID** — you authenticate against this tenant (see below) * The **storage account name** and **container name** for your logs ### Reading the logs Once configured, audit logs are automatically delivered to your container. Authenticate as your application using the client secret or certificate from Step 1. Authenticate against **Omni's tenant ID** (the tenant that hosts the storage), not your own home tenant. Your application's service principal — and the read-access grant — live in Omni's tenant, so a token issued by your own tenant is rejected with a `403` even though access is configured correctly. With the Azure CLI: ```bash theme={null} # Sign in as your application, pointed at Omni's tenant. az login --service-principal \ --username \ --password \ --tenant \ --allow-no-subscriptions # List your audit log blobs. --auth-mode login uses your signed-in identity. az storage blob list \ --account-name \ --container-name \ --auth-mode login \ --output table ``` You can also use a tool like [Azure Storage Explorer](https://azure.microsoft.com/products/storage/storage-explorer) or the Azure SDKs — in each case, set the tenant/authority to Omni's tenant ID and the token scope to `https://storage.azure.com/.default`. ### Hardening Your application only needs to read your audit logs. To keep its footprint minimal: * **Least privilege is enforced on Omni's side.** Your application's service principal is granted only the `Storage Blob Data Reader` role, scoped to your single audit-log container — no write access and no access to any other container or account. * **Prefer a certificate over a client secret** for the application credential, and rotate it regularly. * **Restrict which tenants can use your application.** In the app registration's **Authentication (Preview)** blade, set **Supported account types** to multiple tenants and choose **Allow only certain tenants (Preview)**, then add Omni's tenant ID (and your own). This pins your multitenant application so it can only be used in your tenant and Omni's, rather than any tenant that discovers it. This setting is in preview at the time of writing. ## Option 2: SAS token If your tooling can't authenticate with Entra, Omni can instead share a read-only [shared access signature (SAS) token](https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview) for your dedicated storage account. ### Setup Reach out to Omni support and request SAS-based audit log access. Omni provisions your dedicated storage account and container, and shares: * The **storage account name** and **container name** for your logs * The **SAS token** (read and list permissions only, HTTPS only) ### Reading the logs With the Azure CLI: ```bash theme={null} az storage blob list \ --account-name \ --container-name \ --sas-token "" \ --output table ``` ### Considerations * **Treat the token like a password.** Anyone holding it can read your audit logs until it is revoked. * **Revocation**: if the token is exposed, contact Omni support — Omni rotates the storage account key, which immediately invalidates all outstanding tokens. ## Next steps * Learn about the [event types](/administration/audit-logs/event-types) supported for audit logs * Check out your instance's [Analytics section](/administration/analytics) # Audit log event types Source: https://docs.omni.co/administration/audit-logs/event-types Reference for all audit log event types and their payload fields. This page describes the fields included in each audit log event type. Payloads can contain Omni metadata, which can be safely ignored. ## API request events Occurs on every API request made to Omni. Event type: `API_REQUEST` The API path that was called (e.g., `/api/v1/query/run`). The type of the event. This will be `API_REQUEST`. Audit log marker. This will be `AUDIT`. The HTTP method used (e.g., `GET`, `POST`). The unique identifier for the Omni organization. The HTTP response status code as a string (e.g., `"200"`, `"403"`). Whether the request succeeded, as a string. Either `"true"` or `"false"`. The time the event occurred. A uuid that can be used to trace the event across other log entries. ## Query context events Occurs when a user loads a document (workbook or dashboard). Event type: `QUERY_CONTEXT` The unique ID of the workbook or dashboard within Omni, found within the URL for the document. If applicable, the value will be the value of the entity field in an embed URL generated for a user. The type of the event. This will be `QUERY_CONTEXT`. Additional detail passed from the log. The unique identifier for the Omni organization. The unique identifier for the Omni user associated with the event. The maximum number of query execution events that a query context event can trigger. Can be used to calculate cache hit rate as the denominator. The URL of the page where the event was issued. The source of the query context event. Possible values: * `DASHBOARD` * `WORKBOOK` * `QUERY_DOWNLOAD` * `SUGGESTIONS` * `SUMMARY_VALUES` * `AI_FETCH_FIELD_VALUES` **Deprecated**. Use `query_source` instead. The first 6 characters of this field are overwritten with `stdout` in delivered audit logs (e.g., `DASHBOARD` becomes `stdoutARD`). The `query_source` field contains the correct uncorrupted value. This field is retained for backwards compatibility only. The time the event occurred. A uuid that can be used to trace the event across other log entries. For example, from a query context or dashboard download event to the query execution events that were subsequently run. The URL of the page where the event occurred. ## Query execution events Occurs when a user runs a query, which may be sent back to the warehouse. Event type: `QUERY_EXECUTE` The time the event occurred. The ID of the connection or connection environment used to execute the query. The total length of query execution within the warehouse. The type of the event. This will be `QUERY_EXECUTE`. The ID of the corresponding job in the warehouse where the query was executed. Detail passed from the infrastructure back to the user, if applicable. A uuid for the query being executed within Omni. Used for query killing purposes. The unique identifier for the Omni organization. The query that was executed. A uuid that can be used to trace the event across other log entries. For example, from a query context or dashboard download event to the query execution events that were subsequently run. Indicates if the query executed successfully. **Note**: This doesn't indicate the success of the job, only the individual query. ## Dashboard download events Occurs when a user downloads a full dashboard. Event type: `DASHBOARD_DOWNLOAD` The unique ID of the workbook or dashboard within Omni, found within the URL for the document. If applicable, the value will be the value of the entity field in an embed URL generated for a user. The type of the event. This will be `DASHBOARD_DOWNLOAD`. Additional detail passed from the log. The unique identifier for the Omni organization. The unique identifier for the Omni user associated with the event. The time the event occurred. A uuid that can be used to trace the event across other log entries. For example, from a query context or dashboard download event to the query execution events that were subsequently run. The URL of the page where the event occurred. ## User invite events Occurs when a new user is invited to the organization. Event type: `USER_INVITE` The type of the event. This will be `USER_INVITE`. The ID of the invited user. Additional detail passed from the log. The unique identifier for the Omni organization. The unique identifier for the Omni user associated with the event. The time the event occurred. A uuid that can be used to trace the event across other log entries. ## Connection events ### Connection created Occurs when a new data connection is created. Event type: `CREATE_CONNECTION` Details about the Omni user associated with the event. The ID of the connection that was created. The warehouse dialect for the connection (e.g., `BIGQUERY`, `SNOWFLAKE`, `POSTGRES`). The type of the event. This will be `CREATE_CONNECTION`. A JSON object of the connection's non-sensitive field values at creation time. Sensitive fields (credentials, keys, secrets) are redacted. The name of the connection. The unique identifier for the Omni organization. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### Connection updated Occurs when a data connection's settings are modified. Event type: `UPDATE_CONNECTION` Details about the Omni user associated with the event. A comma-separated list of field names that were changed. A JSON object mapping each changed field name to a `from` and `to` value. Sensitive fields (credentials, keys, secrets) are redacted on both sides. The ID of the connection that was updated. The warehouse dialect for the connection. The type of the event. This will be `UPDATE_CONNECTION`. The name of the connection. The unique identifier for the Omni organization. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### Connection deleted Occurs when a data connection is deleted (archived). Event type: `DELETE_CONNECTION` Details about the Omni user associated with the event. The ID of the connection that was deleted. The warehouse dialect for the connection. The type of the event. This will be `DELETE_CONNECTION`. The name of the connection. The unique identifier for the Omni organization. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### Connection restored Occurs when a previously deleted connection is restored. Event type: `RESTORE_CONNECTION` Details about the Omni user associated with the event. The ID of the connection that was restored. The warehouse dialect for the connection. The type of the event. This will be `RESTORE_CONNECTION`. The name of the connection. The unique identifier for the Omni organization. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### Connection base role updated Occurs when the base role for a connection changes. Event type: `UPDATE_CONNECTION_BASE_ROLE` Details about the Omni user associated with the event. The ID of the connection associated with the role change. The type of the event. This will be `UPDATE_CONNECTION_BASE_ROLE`. Additional detail passed from the log. The name of the updated base connection role. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### Connection credentials updated Occurs when credentials (password, private key) are rotated on a connection. Event type: `UPDATE_CONNECTION_CREDENTIALS` Details about the Omni user associated with the event. The ID of the connection whose credentials were updated. A comma-separated list of credential types that were updated. Possible values include `password` and `privateKey`. Credential values are never included in the audit log. The type of the event. This will be `UPDATE_CONNECTION_CREDENTIALS`. The unique identifier for the Omni organization. The time the event occurred. A uuid that can be used to trace the event across other log entries. ## Organization action events ### Delivery personalization updated Occurs when the organization's [**Delivery personalization** setting](/administration/content-permissions#delivery-personalization) is changed. Event type: `UPDATE_DELIVERY_PERSONALIZATION_MODE` The type of the event. This will be `UPDATE_DELIVERY_PERSONALIZATION_MODE`. The updated value of the setting. This will be one of `configurable`, `always`, or `never`. The unique identifier for the Omni organization. The number of deliveries updated as a result of the change. ## Role events ### Organization role updated Occurs when a user's organization-level role changes. Event type: `UPDATE_ORGANIZATION_ROLE` Details about the Omni user associated with the event. The type of the event. This will be `UPDATE_ORGANIZATION_ROLE`. The ID of the organization membership record for the user whose role changed. The unique identifier for the Omni organization. The name of the new organization role. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### User model role updated Occurs when a user's model-level role changes. Event type: `UPDATE_USER_MODEL_ROLE` Details about the Omni user associated with the event. The type of the event. This will be `UPDATE_USER_MODEL_ROLE`. The ID of the model associated with the role change. The unique identifier for the Omni organization. The name of the new model role. The membership ID of the user whose role was updated. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### User group model role updated Occurs when a user group's model-level role changes. Event type: `UPDATE_GROUP_MODEL_ROLE` Details about the Omni user associated with the event. The ID of the connection associated with the role change. The type of the event. This will be `UPDATE_GROUP_MODEL_ROLE`. The ID of the model associated with the role change. The unique identifier for the Omni organization. The name of the new model role. The ID of the user group whose role was updated. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### Custom role created Occurs when a custom role is created. Event type: `CREATE_CUSTOM_ROLE` Details about the Omni user associated with the event. The built-in role the custom role is based on. The display name of the custom role. The type of the event. This will be `CREATE_CUSTOM_ROLE`. The internal name of the custom role. The unique identifier for the Omni organization. The ID of the newly created custom role. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### Custom role updated Occurs when a custom role's definition is modified. Event type: `UPDATE_CUSTOM_ROLE` Details about the Omni user associated with the event. The built-in role the custom role is based on. Present when the base role has not changed. The previous base role. Present only when the base role changed. The new base role. Present only when the base role changed. The display name of the custom role. The type of the event. This will be `UPDATE_CUSTOM_ROLE`. The internal name of the custom role. The unique identifier for the Omni organization. The ID of the custom role. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### Custom role deleted Occurs when a custom role is deleted. Event type: `DELETE_CUSTOM_ROLE` Details about the Omni user associated with the event. The built-in role the custom role was based on. The display name of the custom role. The type of the event. This will be `DELETE_CUSTOM_ROLE`. The internal name of the custom role. The unique identifier for the Omni organization. The ID of the deleted custom role. The time the event occurred. A uuid that can be used to trace the event across other log entries. ### Custom role reordered Occurs when a custom role's priority order is changed relative to another role. Event type: `REORDER_CUSTOM_ROLE` Details about the Omni user associated with the event. The built-in role the custom role is based on. The type of the event. This will be `REORDER_CUSTOM_ROLE`. The unique identifier for the Omni organization. The internal name of the role being reordered. The internal name of the role that `roleName` is being positioned relative to. The time the event occurred. A uuid that can be used to trace the event across other log entries. ## Content permission events ### Content permission granted Occurs when a user or group is granted access to a document or folder. Event type: `GRANT_CONTENT_PERMIT` The permission action granted (e.g., `view`, `edit`). Details about the Omni user associated with the event. The ID of the document the permission was granted on, if applicable. The type of the event. This will be `GRANT_CONTENT_PERMIT`. The ID of the folder the permission was granted on, if applicable. The unique identifier for the Omni organization. The role granted. The time the event occurred. A uuid that can be used to trace the event across other log entries. A comma-separated list of user group IDs the permission was granted to, if applicable. A comma-separated list of user IDs the permission was granted to, if applicable. The ID of the workbook the permission was granted on, if applicable. ### Content permission revoked Occurs when a user's or group's access to a document or folder is removed. Event type: `REVOKE_CONTENT_PERMIT` Details about the Omni user associated with the event. The ID of the document the permission was revoked on, if applicable. The type of the event. This will be `REVOKE_CONTENT_PERMIT`. The ID of the folder the permission was revoked on, if applicable. The unique identifier for the Omni organization. The time the event occurred. A uuid that can be used to trace the event across other log entries. A comma-separated list of user group IDs whose permission was revoked, if applicable. A comma-separated list of user IDs whose permission was revoked, if applicable. The ID of the workbook the permission was revoked on, if applicable. ### Content ownership transferred Occurs when ownership of a document or folder is transferred from one user to another. Event type: `TRANSFER_CONTENT_OWNERSHIP` Details about the Omni user associated with the event. The ID of the document whose ownership was transferred, if applicable. The type of the event. This will be `TRANSFER_CONTENT_OWNERSHIP`. The ID of the folder whose ownership was transferred, if applicable. The user ID of the new owner. The unique identifier for the Omni organization. The user ID of the previous owner. The time the event occurred. A uuid that can be used to trace the event across other log entries. The ID of the workbook whose ownership was transferred, if applicable. ## Embed membership events ### Embed membership created Occurs when an embedded user's membership is created. Event type: `CREATE_EMBED_MEMBERSHIP` Details about the Omni user associated with the event. The type of the event. This will be `CREATE_EMBED_MEMBERSHIP`. The ID of the newly created embed membership. The unique identifier for the Omni organization. The time the event occurred. A uuid that can be used to trace the event across other log entries. The ID of the embedded user. ### Embed membership deleted Occurs when an embedded user's membership is deleted. Event type: `DELETE_EMBED_MEMBERSHIP` Details about the Omni user associated with the event. The type of the event. This will be `DELETE_EMBED_MEMBERSHIP`. The ID of the deleted embed membership. The unique identifier for the Omni organization. The time the event occurred. A uuid that can be used to trace the event across other log entries. The ID of the embedded user. # Using Google Cloud Storage for Omni audit logs Source: https://docs.omni.co/administration/audit-logs/google-cloud-storage Configure Google Cloud Storage as the destination for your Omni audit logs to track user activity with structured event data. Reach out to Omni support to have audit logs enabled for your instance. Audit logs are detailed records of the activity your users are taking in Omni, which can be useful for security and performance analysis. Events included in logs are structured as JSON payloads and sent in batches to your cloud storage bucket a few minutes after they're written. ## Supported authentication methods Audit logs can be delivered to a Google Cloud Storage (GCS) bucket using one of two authentication methods: * **Workload Identity Federation** - Workload Identity Federation allows Omni's audit log delivery service to authenticate to your GCS bucket using AWS IAM credentials through GCP Workload Identity Federation. This is the recommended authentication method for GCS as it eliminates the need to manage long-lived service account keys. * **Service account key** - This method uses a service account JSON key file for authentication. While straightforward, it requires managing long-lived credentials. ## Option 1: Workload Identity Federation This approach provides enhanced security by: * Eliminating the need to share or rotate service account keys * Using temporary, automatically rotating credentials * Leveraging your existing AWS and GCP IAM policies ### Requirements * An existing GCS bucket where audit logs will be delivered * Permissions to create and configure a Workload Identity Pool in your GCP project * Permissions to create and configure a service account with write access to your GCS bucket ### Setup Work with Omni support to configure Workload Identity Federation. The setup involves: Omni support will provide you with the AWS Account ID and AWS IAM role ARN that will authenticate to your GCS bucket. Create a [Workload Identity Pool and AWS provider](https://docs.cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#gcloud_1) in your GCP project. Create a [GCP service account](https://docs.cloud.google.com/iam/docs/service-accounts-create) with write permissions (`objectCreator` role) to your GCS bucket. Configure the Workload Identity Pool to allow the Omni AWS IAM role you received in step 1 to impersonate your GCP service account. Provide Omni support with the following: * Project number * Pool ID * Provider ID * Service account email Omni support completes the configuration on the Omni side. Once configured, audit logs will be automatically delivered to your GCS bucket without requiring any credential management. ## Option 2: Service account key This approach uses a service account JSON key file to authenticate to the GCS bucket. The [Workplace Identity Federation approach](#option-1-workload-identity-federation) is recommended over using a service account key. ### Requirements * An existing GCS bucket where audit logs will be delivered * Permissions in GCS that allow you to create a service account key ### Setup Create a [service account key](https://docs.cloud.google.com/iam/docs/keys-create-delete) in GCS. Provide Omni support with the name of your GCS bucket and the service account key you created in the previous step. Omni support completes the configuration on the Omni side. Once configured, audit logs will be automatically delivered to your GCS bucket. ## Next steps * Learn about the [event types](/administration/audit-logs/event-types) supported for audit logs * Check out your instance's [Analytics section](/administration/analytics) # Audit logs Source: https://docs.omni.co/administration/audit-logs/index Set up audit logging in Omni to track user activity with structured event logs delivered to Amazon S3, Google Cloud Storage, or Azure Blob Storage. Audit logs are detailed records of the activity your users are taking in Omni, which can be useful for security and performance analysis. Events included in logs are structured as JSON payloads and sent in batches to cloud storage a few minutes after they're written. ## Delivery destinations Audit logs can be delivered to Amazon S3, Google Cloud Storage, or Azure Blob Storage. Send event logs to an Amazon S3 bucket, either Omni-hosted or customer-hosted Send event logs to a Google Cloud Storage bucket Read event logs from an Omni-hosted Azure Blob Storage container ## Data retention By default, logs are retained for at least one year. Contact Omni support if you need a shorter retention period. ## Event types Each audit log entry includes an event type that identifies the user action that triggered it. See the [event types reference](/administration/audit-logs/event-types) for a full list of supported events and their payload fields. # Microsoft Entra authentication Source: https://docs.omni.co/administration/authentication/entra/index Connect Omni to Microsoft Entra for secure SAML single sign-on and automated user provisioning. You can connect Omni to Microsoft Entra to manage authentication and user access through your organization’s existing identity provider. Entra supports **SAML** for single sign-on and **SCIM** for automated user provisioning. You can also sync additional **user attributes** like name, title, or department to keep Omni profiles up to date. ## Integration overview Connecting Entra to Omni allows you to: 1. **Authenticate users** through Entra using SAML. 2. **Control when and how users are provisioned** in Omni. 3. **Sync user profile data** such as display name and department through attribute mappings. ### User provisioning options Omni supports two approaches for provisioning users: | Option | How it works | When to use | | ---------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | **SCIM provisioning** | Users are created in Omni when assigned to the Omni app in Entra. | You want users provisioned immediately upon assignment, regardless of whether they've logged in. | | **First-login provisioning** | Users are created in Omni only when they first log in via SAML. | You want to control seat usage by provisioning users only when they actually access Omni. | You can use first-login provisioning with or without SCIM. Refer to the [SAML setup guide](/administration/authentication/entra/saml) for more details. ## Getting started Follow these steps to get set up. You can complete SAML only, or add SCIM and attribute sync for a fully automated experience. | Step | Description | Link | | ---- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | 1 | **Set up SAML SSO** to let users sign in to Omni with their Entra credentials. | [SAML setup →](/administration/authentication/entra/saml) | | 2 | **Enable SCIM provisioning** to automatically create, update, and deactivate users in Omni. | [SCIM setup →](/administration/authentication/entra/scim) | | 3 | **Sync user attributes** like name, title, and department between Entra and Omni. | [Sync attributes →](/administration/authentication/entra/user-attributes) | ## Notes and troubleshooting * **Admin access required:** You’ll need Entra admin permissions to configure SAML and SCIM. * **Test before rollout:** Try SSO with a test user before enabling it organization-wide. * **Sync frequency:** SCIM updates usually occur within a few minutes of changes in Entra. If you run into issues, check your Entra app configuration or see [Omni's troubleshooting SSO guide](/administration/authentication/troubleshooting). ## Related * [Omni SAML configuration overview](/administration/authentication) * [Managing users and groups in Omni](/administration/users) * [Entra documentation](https://\[idp-docs-link]/) # Microsoft Entra SAML authentication Source: https://docs.omni.co/administration/authentication/entra/saml Configure service provider (SP)-initiated SAML authentication between Microsoft Entra and Omni. When enabled, users in your organization can log into Omni using their Microsoft Entra credentials. ## Requirements To follow the steps in this guide, you'll need: * **Omni Organization Admin permissions** * **Permissions in Microsoft Entra that allow you to:** * Access the admin panel * Add & configure Microsoft Entra applications * Assign users to applications ## Setup In your Omni instance, navigate to **Settings > Authentication** and locate the **SAML** section. Leave this page open - you'll need it to complete the setup. 1. Log in to the Microsoft Entra admin panel. 2. Navigate to **Applications > Enterprise Applications**. 3. Click **New application**, then **Create your own application**. 4. Name the application `Omni`. 5. Select the **Integrate any other application you don't find in the gallery (Non-gallery)** option. 6. Click **Create**. 1. Click the Entra Omni application you created in the previous step. 2. Navigate to the **Manage > Single sign-on configuration** section. 3. Select **SAML sign-on** as the method. 4. In the **Basic SAML configuration** section, click **Edit** and modify these settings: * **Identifier (Entity ID)** - Enter the full hostname of your Omni instance, e.g. `blobsrus.omniapp.co`. Do not include `https://`. * **Reply URL (Assertion Consumer Service URL)** - Copy and paste the value of the **Single sign-on URL** field from the Omni Authentication settings you opened in step 1. 5. Save the changes to the settings. Next, edit the application's **Attributes & Claims**. This requires **three claims**, outlined as follows: | | **Claim 1** | **Claim 2** | **Claim 3** | | -------------------- | ---------------------------------------------------------------------------------------------- | ----------------- | ---------------- | | **Description** | User's email address | User's first name | User's last name | | **Name** | `email_address` | `first_name` | `last_name` | | **Namespace** | Leave blank | Leave blank | Leave blank | | **Source** | Attribute | Attribute | Attribute | | **Source attribute** | The attribute you use to identify a user's email address. Usually `user.email` or `user.mail`. | `user.first_name` | `user.surname` | The name for a claim must **match exactly** the value in the **Name** row in the above table. For example, `first_name` is valid but `firstName` is not. Create and configure the claims for the application until you have one for each of the claims outlined in the previous table. In this step, you'll assign the Entra Omni application to yourself. This will allow you to test the setup in Omni before rolling everything out to your organization. Follow the steps in the [Entra documentation](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-assign-users#assign-a-user-account-to-an-enterprise-application) to assign yourself to the Omni application. 1. In the Entra Omni application's settings, locate the **SAML Certificates** section. 2. Click the **Base64** download link to [download the certificate](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/tutorial-manage-certificates-for-federated-single-sign-on#autogenerated-certificate-for-gallery-and-non-gallery-applications). 3. Locate the certificate file on your computer and change the extension to `.txt`. This will allow you to open it. 4. Keep the file open - you'll need it to complete the next step. Navigate back to the Omni authentication settings (**Settings > Authentication**) to complete the setup: * **Display Name** - Enter a name to customize the login button, for example `Microsoft Entra`. Leave blank to show the default **Log in with SAML** button. * **Entity ID / Issuer** - Copy and paste the **Microsoft Entra ID Identifier** value from Entra * **SSO (Sign on) URL** - Copy and paste the **Login URL** value from Entra * **Certificate** - Copy and paste the contents of the certificate you downloaded in step 4. The certificate must include `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----`, for example: ```txt wrap theme={null} -----BEGIN CERTIFICATE-----[Your certificate contents]-----END CERTIFICATE----- ``` If the certificate you paste into Omni doesn't have these values, add them in the **Certificate** field so that it looks like the above example. * **Automatically provision new users on first login from this SAML provider** - Toggle this setting to **on** if: * You want to provision users only when they first access Omni **and** * You don't plan to set up SCIM provisioning * **Enable SAML login** - Toggle this setting to **on** to enable SAML authentication When finished, click **Save SAML changes**. Test your SAML setup by logging out of Omni. On the Omni login page, you should see a login button. Click the button to log in using SAML. By default, the login button will read **Log in with SAML**. Set a **Display Name** in the [Omni authentication settings](#omni-auth-settings) to customize this text. User groups can be pushed from Microsoft Entra to Omni using SCIM. Check out the [Entra-Omni SCIM guide](/administration/authentication/entra/scim) for more information. Once you confirm everything is working as expected, you can assign the Omni application to other people and groups in your organization. Follow the steps in the [Entra documentation](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-assign-users#assign-a-user-account-to-an-enterprise-application) to assign users to the Omni application. ## What's next? Setting up SAML allows your users to authenticate to Omni using their Microsoft Entra credentials. With this setup completed, you can also: * [Configure SCIM to auto-provision users & user groups in Omni](/administration/authentication/entra/scim) * [Use SCIM to sync user attributes from Microsoft Entra to Omni](/administration/authentication/entra/user-attributes) # Auto-provisioning Omni users with Microsoft Entra SCIM Source: https://docs.omni.co/administration/authentication/entra/scim Automatically manage Omni accounts for your users with Microsoft Entra SCIM provisioning. When SCIM (System for Cross-domain Identity Management) is enabled, you can automatically provision and de-provision Omni accounts for your users and synchronize Omni user groups with groups in Microsoft Entra (formerly Active Directory / Azure AD). ## Requirements To follow the steps in this guide, you'll need: * **To have Microsoft Entra SAML authentication set up**. If you don't, refer to the [Microsoft Entra SAML authentication setup guide](/administration/authentication/entra/saml) before proceeding. * **Omni Organization Admin permissions** * **Permissions in Microsoft Entra that allow you to:** * Access the Entra admin panel * Modify Entra applications ## Limitations Omni [system user attributes](/administration/users/attributes#default-system-user-attributes) are read-only and cannot be assigned via SCIM. ## Steps Omni users created via SCIM will have **Organization Member** permissions. Organization Admins must be created in **Settings > Users** or have their permissions [manually upgraded](/administration/users/permissions). 1. Follow [these steps](/api/authentication) to create a new API key named **Entra SCIM**. 2. Copy the key somewhere handy - you'll need it to complete the setup. This guide assumes that you have an existing Omni application in Microsoft Entra. Refer to the [SAML setup guide](/administration/authentication/entra/saml) if you have not yet created an Omni application. 1. Log in to the Microsoft Entra admin panel. 2. Navigate to **Applications > Enterprise Applications**. 3. Locate and open the Omni application. 4. In the Omni application, navigate to **Manage > Provisioning**. 5. For the **provisioning mode**, select **Automatic Provisioning Mode**. 6. Configure the **Admin credentials section** as follows: * **Tenant URL** - Enter the URL you use to log into Omni, appended with `/api/scim/v2`. For example, if your Omni login URL is `https://blobsrus.omniapp.co`, you would enter `https://blobsrus.omniapp.co/api/scim/v2`. * **Secret Token** - Paste the Omni API key you created in step 1 7. Click **Test connection** and proceed if successful. In this step, you'll configure the user and user group mappings to provision in Omni. 1. In the **Mappings** section, click the type of object you want to map - users or user groups. 2. Remove all default attribute mappings **except the following**: * **For users** - Remove all mappings except `userName`, `active`, and `displayName` * **For user groups** - Remove all mappings except `displayName` and `members` 3. Click **Save**. Map **only** the attributes listed above. Microsoft Entra includes every mapped attribute in each sync request, and Omni's SCIM validation will reject any provisioning or de-provisioning request that contains attributes beyond those it supports. Leaving Entra's default mappings in place (for example `name.givenName`, `emails`, or `externalId`) will cause both user provisioning and de-provisioning to fail. The only supported user attributes are `userName`, `active`, and `displayName`, and for groups `displayName` and `members`. To sync additional user attributes, map them under the Omni user attribute namespace as described in the [Syncing Entra user attributes guide](/administration/authentication/entra/user-attributes). 1. In Omni, navigate to **Settings > Authentication**. 2. Enable **Automatically provision new users on first login from this SAML provider**. This ensures that users assigned to the Omni app in Entra are automatically created in Omni when they first log in via SAML. 3. Click **Save SAML changes**. **Note**: when users are removed from Entra they will be de-provisioned and revoked in Omni which has implications for the schedules and content they own. See the [Revoke Membership](/administration/users/delete) page for more details. ## What's next? After you finish setting up SCIM, you can go a step further and sync your custom user attributes from Entra to Omni. Refer to the [Syncing Entra user attributes guide](/administration/authentication/entra/user-attributes) for more information. # Syncing Microsoft Entra user attributes to Omni with SCIM Source: https://docs.omni.co/administration/authentication/entra/user-attributes Sync user attributes from Microsoft Entra to Omni via SCIM. Custom user attributes can be synced from Microsoft Entra (formerly Active Directory / Azure AD) to Omni, allowing you to fully centralize your user management in Microsoft Entra. In this guide, we'll demonstrate how to sync a user attribute named `blob_entity` from Microsoft Entra to Omni. ## Requirements To follow the steps in this guide, you'll need: * **To set up SCIM provisioning with Entra**. Refer to the [Omni Entra SCIM guide](/administration/authentication/entra/scim) for more information. * **Organization Admin** permissions in Omni * **Permissions in Microsoft Entra** that allow you to: * Access the admin panel * Create user profile attributes * Modify applications ## Limitations Omni [system user attributes](/administration/users/attributes#default-system-user-attributes) are read-only and cannot be assigned via SCIM. ## Setup In Omni, navigate to **Settings > Attributes** and [create a new attribute](/administration/users/attributes). Our example attribute, `blob_entity`, has the following settings: * **Name** - `Blob Entity` * **Reference** - `blob_entity` * **Type** - `string` 1. Log in to your Entra admin panel. 2. Navigate to **Entra ID > Enterprise apps**. 3. Click the Omni application. 4. In the sidebar, click **Provisioning** under the **Manage** heading. 5. Open the **Mappings** section. 6. In this section, select the user you want to add an attribute to. 7. At the bottom of the page, select **Show advanced options**. 8. Select **Edit attribute list for customappsso**. 9. Enter the following for the attribute: * **Name** - Enter the **reference** of the attribute you created in Omni in step 1, prefixed with the following: ```txt theme={null} urn:omni:params:1.0:UserAttribute: ``` For example, for the `blob_entity` attribute, you'd enter `urn:omni:params:1.0:UserAttribute:blob_entity`. * **Type** - Select the **type** of the attribute you created in Omni: `string` or `integer` * **Multi-value?** - Select this option if the Omni attribute is configured to support multiple values. 10. Configure the remaining fields as needed. 11. Save the changes. 1. A message should display after you click **Save** - click **Yes**. 2. In the **Attribute Mapping** page that opens, click **Add New Mapping**. 3. In the **Target attribute** dropdown, select the attribute you created in step 2. 4. Configure the remaining fields to map the appropriate value to the attribute. 5. Click **OK**, then **Save**. ## What's next? The Omni application should be set to automatically provision users and groups - see the [Entra SCIM guide](/administration/authentication/entra/scim) - meaning that the next time the app syncs, the attributes should be created as [user attributes in Omni](/administration/users/attributes). # Managing users with Google Workspace SAML Source: https://docs.omni.co/administration/authentication/google-workspace Integrate Omni with Google Workspace for user authentication via the SAML protocol. ## Limitations * User and user group provisioning via SCIM is not currently supported for Google Workspace * User sessions expire after 24 hours, after which users will then need to reauthenticate ## Requirements To follow the steps in this guide, you'll need: * Omni [Organization Admin permissions](/administration/users/permissions) * Google Workspace [Super Administrator permissions](https://support.google.com/a/answer/2405986?sjid=8929730596146089385-NA) ## Setup In your Omni instance, navigate to **Settings > Authentication** and locate the **SAML** section. Leave this page open - you'll need it to complete the setup. 1. Log in to your Google Workspace Admin console. 2. In the navigation bar, click **Apps > Web and mobile apps**. 3. Click the **Add app** dropdown, then **Add custom SAML app**. 4. Name the app `Omni Analytics`. You can also add a description and logo. 5. Click **Continue**. 6. On the **Google Identity Provider details** page, copy the following information somewhere handy - you'll need it to complete the setup in Omni: * SSO URL * Entity ID * Certificate - **Note**: You will need to download the certificate. 7. Click **Continue**. 8. In the **Service Provider Details window**, fill in the following: * **ACS URL** - Copy and paste the **Single sign-on URL** value from the Omni Authentication settings (step 1) * **Entity ID** - Enter the full hostname of your Omni instance, e.g. `blobsrus.omniapp.co`. Do not include `https://`. * **Name ID format** - Set to `Email` * **Name ID** - Set to `Basic Information > Primary email` 9. Click **Continue**. 10. Click **Add mappings** and add the following mappings: * `First name` to `first_name` * `Last name` to `last_name` 11. Click **Finish**. Navigate back to the Omni Authentication settings (**Settings > Authentication**) to complete the setup: * **Display Name** - Enter a name to customize the login button, for example `Google Workspace`. Leave blank to show the default **Log in with SAML** button. * **Entity ID / Issuer** - Copy and paste the **Entity ID** value from Google Workspace * **SSO (Sign on) URL** - Copy and paste the **SSO URL** value from Google Workspace * **Certificate** - Copy and paste the contents of the certificate you downloaded in step 2. The certificate must include `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` values, for example: ```txt wrap theme={null} -----BEGIN CERTIFICATE----- [certificate contents] -----END CERTIFICATE----- ``` * **Enable SAML for users** - Toggle this setting to **on** When finished, click **Save SAML changes**. In the Google Workspace Admin console, use the **User access section** in the Omni app to grant users access. Refer to [Google's documentation](https://support.google.com/a/answer/6087519?hl=en#zippy=%2Cstep-turn-on-your-saml-app) for more information. The email addresses your users use to sign in to Omni must match the email addresses they use to sign in to your Google domain. Test your SAML setup by logging out of Omni. On the Omni login page, you should see a login button. Click the button to log in using SAML. By default, the login button will read **Log in with SAML**. Set a **Display Name** in the [Omni authentication settings](#omni-auth-settings) to customize this text. If the setup is successful, finish the setup by rolling out SAML authentication to the rest of your organization. # Set up Identity Providers (IdP) for authentication Source: https://docs.omni.co/administration/authentication/index Configure SSO, SAML, or OIDC for your Omni organization Omni supports authentication with identity providers through SAML and OIDC. This allows your users to sign in using your organization's existing identity management system. Select your identity provider below to get started. ## Identity providers Set up SSO with Google Workspace Set up SSO with Microsoft Entra ID horizontal Set up SSO with Okta Set up SSO with Rippling Configure OAuth using OIDC ## SAML and SCIM For Microsoft Entra, Okta, and Rippling, Omni supports both SAML and SCIM: * **SAML** - Enables single sign-on authentication * **SCIM** - Enables automatic user provisioning and de-provisioning. **Note**: While custom user attributes can be synced using SCIM, Omni's [default system user attributes](/administration/users/attributes#default-system-user-attributes) are read-only and cannot be assigned via SCIM. ## Need help? If you run into issues during setup, check the [SSO troubleshooting guide](/administration/authentication/troubleshooting) for common problems and solutions. # Configuring OIDC authentication Source: https://docs.omni.co/administration/authentication/oidc Configure OpenID Connect (OIDC) authentication for your Omni organization. OpenID Connect (OIDC) is an authentication protocol built on top of OAuth 2.0. When enabled, users in your organization can log into Omni using credentials from any OIDC-compliant identity provider. ## Requirements To follow the steps in this guide, you'll need: * **Omni Organization Admin permissions** * **Access to your OIDC identity provider** with permissions to: * Create or configure applications * Access client credentials and discovery endpoints ## Limitations **User sessions will expire after 24 hours**. This is not currently configurable. ## Setup In your OIDC identity provider, obtain the following information: * **Issuer URL** - The issuer URL of your OIDC server * **Client ID** - The unique identifier for your Omni application * **Client Secret** - The secret key for authenticating your application Keep this information handy - you'll need it to complete the setup in Omni. The exact steps to obtain these values will vary depending on your identity provider. Consult your provider's documentation for specific instructions on creating an OIDC application. In your OIDC identity provider's application settings, you'll need to configure the **Redirect URI** (also called **Callback URL**). The redirect URI should be in the following format: ```html wrap theme={null} https://[your-omni-subdomain].omniapp.co/auth/oidc/callback ``` For example, if you log in to `https://blobsrus.omniapp.co`, your redirect URI would be: ```html wrap theme={null} https://blobsrus.omniapp.co/auth/oidc/callback ``` In Omni, navigate to **Settings > Authentication > OIDC Configuration** to complete the setup: * **Display name** - Enter a name, for example `Blobs R Us auth` * **Issuer URL** - Paste the issuer URL from your OIDC provider. * **Client ID** - Copy and paste the Client ID from your OIDC provider * **Client Secret** - Copy and paste the Client Secret from your OIDC provider * **Automatically provision new users on first login from this OIDC provider** - Toggle this setting to **on** if you want to provision users only when they first access Omni * **Enable OIDC for users** - Toggle this setting to **on** to enable OIDC authentication When finished, click **Save OIDC changes**. Test your OIDC setup by logging out of Omni. On the Omni login page, you should see a **Log in with OIDC** button. Click the button to log in using OIDC. If the setup is successful, you can proceed to assign the application to other users in your organization through your identity provider. **Note**: when users are removed from your OIDC system they will be de-provisioned and revoked in Omni which has implications for the schedules and content they own. See the [Revoke Membership](/administration/users/delete) page for more details. # Okta authentication Source: https://docs.omni.co/administration/authentication/okta/index Connect Omni to Okta for secure SAML single sign-on and automated user provisioning. You can connect Omni to Okta to manage authentication and user access through your organization’s existing identity provider. Okta supports **SAML** for single sign-on and **SCIM** for automated user provisioning. You can also sync additional **user attributes** like name, title, or department to keep Omni profiles up to date. ## Integration overview Connecting Okta to Omni allows you to: 1. **Authenticate users** through Okta using SAML. 2. **Control when and how users are provisioned** in Omni. 3. **Sync user profile data** such as display name and department through attribute mappings. ### Supported features Omni supports the following Okta provisioning features: * **Push users** - Users in Okta that are assigned to the Omni application in Okta are automatically added as users in Omni. * **Update user attributes** - When user attributes are updated in Okta, they will be updated in Omni. * **Remove/deactivate users** - When users are removed or deactivated in Okta, their membership to your Omni organization will be revoked. * **Reactivate users** - Reactivating a user will create a new user in Omni with a new external ID. * **Push groups** - Groups and their members in Okta can be pushed to Omni as Omni groups and group members. ### User provisioning options Omni supports two approaches for provisioning users: | Option | How it works | When to use | | ---------------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | **SCIM provisioning** | Users are created in Omni when assigned to the Omni app in Okta. | You want users provisioned immediately upon assignment, regardless of whether they've logged in. | | **First-login provisioning** | Users are created in Omni only when they first log in via SAML. | You want to control seat usage by provisioning users only when they actually access Omni. | You can use first-login provisioning with or without SCIM. Refer to the [SAML setup guide](/administration/authentication/okta/saml) for more details. ### Limitations Omni does not currently support the following Okta provisioning features: * Sync password * Enhanced group push Additionally, note that user sessions will expire after 24 hours. This is not currently configurable. ## Getting started Follow these steps to get set up. You can complete SAML only, or add SCIM and attribute sync for a fully automated experience. | Step | Description | Link | | ---- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | 1 | **Set up SAML SSO** to let users sign in to Omni with their Okta credentials. | [SAML setup →](/administration/authentication/okta/saml) | | 2 | **Enable SCIM provisioning** to automatically create, update, and deactivate users in Omni. | [SCIM setup →](/administration/authentication/okta/scim) | | 3 | **Sync user attributes** like name, title, and department between Okta and Omni. | [Sync attributes →](/administration/authentication/okta/user-attributes) | ## Notes and troubleshooting * **Admin access required:** You’ll need Okta admin permissions to configure SAML and SCIM. * **Test before rollout:** Try SSO with a test user before enabling it organization-wide. * **Sync frequency:** SCIM updates usually occur within a few minutes of changes in Okta. If you run into issues, check your Okta app configuration or see [Omni's troubleshooting SSO guide](/administration/authentication/troubleshooting). ## Related * [Omni SAML configuration overview](/administration/authentication) * [Managing users and groups in Omni](/administration/users) * [Okta documentation](https://\[idp-docs-link]/) # Configuring Okta SAML authentication Source: https://docs.omni.co/administration/authentication/okta/saml Configure service provider (SP)-initiated SAML authentication between Okta and Omni. When enabled, users in your organization can log into Omni using their Okta credentials. ## Requirements To follow the steps in this guide, you'll need: * **Omni Organization Admin permissions** * **Permissions in Okta that allow you to:** * Access the Admin console * Add & configure Okta applications ## Limitations * **User sessions will expire after 24 hours**. This is not currently configurable. * **Users will not be able to click the Omni tile in Okta to log in**. This is because Omni's current integration with Okta is not Identity service provider (IdP) initiated, but SP-initiated. ## Setup 1. Log in to your Okta Admin console. 2. Navigate to **Applications > Applications > Browser App Catalog**. 3. Search for the `Omni Analytics` application. 4. Click **Add integration**. 5. On the page that displays, enter your Omni **subdomain**. For example, if you log in to `https://blobsrus.omniapp.co`, you would enter `blobsrus`. 6. Click **Save**. Navigate to the Okta Omni application and then complete the following: 1. In the Okta Omni application, open the **Sign on** tab. 2. In the **SAML 2.0** section, click **More details**: 3. Keep this section open - you'll need the **Sign on URL**, **Issuer**, and **Signing certificate** handy to complete the next step. In this step, you'll assign the Okta Omni application to yourself. This will allow you to test the setup in Omni before rolling everything out to your organization. 1. In the Okta Omni application, open the **Assignments** tab. 2. Click the **Assign** button, then **Assign to people**. 3. In the dialog that displays, click the **Assign** link next to your user. 4. You'll be directed to confirm details about the user, including the email address and display name. Modify these settings as needed. 5. When finished, click **Save and Go back**. 6. Click **Done**. In Omni, navigate to **Settings > Authentication** to complete the setup: * **Display Name** - Enter a name to customize the login button, for example `Okta`. Leave blank to show the default **Log in with SAML** button. * **Entity ID / Issuer** - Copy and paste the **Issuer** value from Okta * **SSO (Sign on) URL** - Copy and paste the **Sign on URL** value from Okta * **Certificate** - Use the **Copy** button next to the **Certificate** field in Okta, then paste the contents in Omni. The certificate must include `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----`, for example: ```txt wrap theme={null} -----BEGIN CERTIFICATE----- [Your Okta certificate contents] -----END CERTIFICATE----- ``` After you paste the certificate into Omni, add these values above and below the certificate so that it looks like the above example. * **Automatically provision new users on first login from this SAML provider** - Toggle this setting to **on** if: * You want to provision users only when they first access Omni **and** * You don't plan to set up SCIM provisioning * **Enable SAML login** - Toggle this setting to **on** to enable SAML authentication When finished, click **Save SAML changes**. Test your SAML setup by logging out of Omni. On the Omni login page, you should see a login button. Click the button to log in using SAML. By default, the login button will read **Log in with SAML**. Set a **Display Name** in the [Omni authentication settings](#omni-auth-settings) to customize this text. User groups can be pushed from Okta to Omni using SCIM. Check out the [Okta-Omni SCIM guide](/administration/authentication/okta/scim) for more information. Once you confirm everything is working as expected, you can assign the Okta Omni application to other people and groups in your organization. **Not sure what permissions to use?** Refer to the [Connection permissions guide](/administration/users/permissions) for more information. In Okta: 1. In the Okta Omni application, open the **Assignments** tab. 2. Click the **Assign** button, then **Assign to people**. 3. In the dialog that displays, click the **Assign** link next to the user. 4. You'll be directed to confirm details about the user, including the email address and display name. Modify these settings as needed. 5. When finished, click **Save and Go back**. 6. Click **Done**. Users will now be able to navigate to Omni in their browser and use SAML to log in. ## What's next? Setting up SAML allows your users to authenticate to Omni using their Okta credentials. With this setup completed, you can also: * [Configure SCIM to auto-provision users & user groups in Omni](/administration/authentication/okta/scim) * [Use SCIM to sync user attributes from Okta to Omni](/administration/authentication/okta/user-attributes) # Auto-provisioning Omni users with Okta SCIM Source: https://docs.omni.co/administration/authentication/okta/scim Automatically manage Omni accounts for your users with Okta SCIM provisioning. When SCIM (System for Cross-domain Identity Management) is enabled, you can automatically provision and de-provision Omni accounts for your users and synchronize Omni user groups with groups in Okta. ## Requirements To follow the steps in this guide, you'll need: * **To have Okta SAML authentication set up**. If you don't, refer to the [Okta SAML authentication setup guide](/administration/authentication/okta/saml) before proceeding. * **Omni Organization Admin permissions** * **Permissions in Okta that allow you to:** * Access the Admin console * Modify Okta applications ## Limitations * Omni [system user attributes](/administration/users/attributes#default-system-user-attributes) are read-only and cannot be assigned via SCIM * Omni does not currently support the following Okta provisioning features: * Sync password * Enhanced group push Additionally, pushing an Okta group to Omni will **not** automatically provision accounts for users who are group members. You'll need to use the **Assignments** tab to assign the group to the users. Refer to the [Okta SAML setup guide](/administration/authentication/okta/saml) for more information. ## Steps Omni users created via SCIM will have **Organization Member** permissions. Organization Admins must be created in **Settings > Users** or have their permissions [manually upgraded](/administration/users/permissions). 1. Follow [these steps](/api/authentication) to create a new API key named **Okta SCIM**. 2. Copy the key somewhere handy - you'll need it to complete the setup. This guide assumes that you have an existing Omni application in Okta. If you don't, make sure you've finished setting up [Okta SAML authentication](/administration/authentication/okta/saml) before continuing. 1. Log in to the Okta Admin console. 2. Navigate to the Omni application. 3. Click the **Provisioning** tab. 4. In the **Integration** tab, click the **Configure API Integration** button. 5. Check the **Enable API Integration** box. 6. In the **API Token** field, paste your Omni API key: 7. Click **Test credentials** to verify the setup. If the API credential test is successful, additional options will display in the application's **Provisioning** tab. 1. In the **Provisioning** tab, click the **To app** option. Then: 2. Click the **Edit** link to the right of the **Provisioning to app** heading. 3. Check the **Enable** boxes for **Create users**, **Deactivate users**, and **Update user attributes**. 4. Click **Save**. 5. Navigate to the **Sign on** tab. Then: 6. Locate the **Credentials details** section. 7. Set the **Application username format** to **Email**. To change this setting, click the **Edit** link near the top of the tab: 8. Click **Save** when finished. After provisioning is set up, [users that have the Omni application assigned to them in Okta](https://help.okta.com/en-us/content/topics/users-groups-profiles/usgp-assign-apps.htm) will be provisioned in Omni. This process may take a few minutes to complete. In Omni: 1. Navigate to **Settings > Authentication**. 2. Enable **Automatically provision new users on first login from this SAML provider**. 3. Click **Save SAML changes**. This setting ensures that users assigned to the Omni app in Okta are automatically created in Omni when they first log in via SAML. Pushing an Okta group to Omni will **not** automatically provision accounts for users who are group members. You'll need to use the **Assignments** tab to assign the group to the users. Refer to the [Okta SAML setup guide](/administration/authentication/okta/saml) for more information. This step enables Okta's **Push groups** functionality, which allows you to push your Okta user groups to Omni. 1. In the Omni application, navigate to the **Push Groups** tab. 2. Click the **Push Groups** button, then select **Find groups by name**: 3. Use the search field to find and select an Okta group to push to Omni. 4. Click **Save**. Once pushed, Omni will begin provisioning the user group. This process may take a few minutes to complete. **Note**: when users are removed from Okta they will be automatically de-provisioned and revoked in Omni which has implications for the schedules and content they own. See the [Revoke Membership](/administration/users/delete) page for more details. ## What's next? After you finish setting up SCIM, you can go a step further and sync your custom user attributes from Okta to Omni. Refer to the [Syncing Okta user attributes guide](/administration/authentication/okta/user-attributes) for more information. # Syncing Okta user attributes to Omni with SCIM Source: https://docs.omni.co/administration/authentication/okta/user-attributes Sync user attributes from Okta to Omni via SCIM. Custom user attributes can be synced from Okta to Omni, allowing you to fully centralize your user management in Okta. In this guide, we'll demonstrate how to sync a user attribute named `blob_entity` from Okta to Omni. ## Requirements To follow the steps in this guide, you'll need: * **To set up SCIM provisioning with Okta**. Refer to the [Omni Okta SCIM guide](/administration/authentication/okta/scim) for more information. * **Organization Admin** permissions in Omni * **Permissions in Okta** that allow you to: * Access the Admin console * Create user profile attributes * Define user profile attribute values * Modify applications ## Limitations Omni [system user attributes](/administration/users/attributes#default-system-user-attributes) are read-only and cannot be assigned via SCIM. ## Setup In Omni, navigate to **Settings > Attributes** and [create a new attribute](/administration/users/attributes). Our example attribute, `blob_entity`, has the following settings: * **Name** - `Blob Entity` * **Reference** - `blob_entity` * **Type** - `string` Click the dropdowns to display instructions for each step. **Passing a default Okta attribute?** Creating an attribute is required **only** if the attribute you want to pass to Omni doesn't exist in [Okta's default user attributes](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/User/#tag/User/operation/createUser!path=profile\&t=request), such as `name` or `city`. 1. Log in to your Okta Admin console. 2. Navigate to **Directory > Profile Editor**. 3. Click the **User (default)** option. 4. Click the **Add Attribute** button. 5. Fill in the attribute fields as follows: * **Data type** - Select the **Type** the attribute has in Omni. For example, if the attribute has a **Type** of `string` in Omni, you'd select `string`. * **Display name** - Enter a name for the attribute. * **Variable name** - Enter the **Reference** for the attribute in Omni. In our example, this would be `blob_entity`. * **Enum** - If the Omni attribute can have multiple values, check this box and use the fields that display to add the possible values. 6. Omni doesn't require a specific configuration for the remaining fields; feel free to define them as needed. 7. When finished, click **Save**. After you create the attribute, **open the profile of each user assigned to the Omni application** and define a value for the attribute. Refer to the [Okta documentation](https://help.okta.com/en-us/content/topics/users-groups-profiles/usgp-edit-user-attributes.htm) if you need a refresher on how to do this. 1. In Okta, navigate to **Directory > Profile Editor**. 2. Click the **Omni application**. 3. Click **Add Attribute**. 4. Fill in the attribute fields as follows: * **Data type** - Select the **Type** the attribute has in Omni. For example, if the attribute has a **Type** of `string` in Omni, you'd select `string`. * **Display name** - Enter a name for the attribute. * **Variable name** - Enter the **Reference** for the attribute in Omni. In our example, this would be `blob_entity`. * **External name** - This will auto-populate based on the **Variable name** * **External namespace** - Copy and paste the following into this field: ```txt theme={null} urn:omni:params:1.0:UserAttribute ``` **This value must be this exact string - don't change the `UserAttribute`.** * **Enum** - If the Omni attribute can have multiple values, check this box and use the fields that display to add the possible values. 5. Click **Save**. The last step is to map the Okta profile attribute to the Omni application attribute. 1. In the profile editor for the Omni application, click the **Mappings** button: 2. In the dialog that displays, toggle the view to **Okta User to Omni Analytics**: 3. Use the dropdowns to map the attributes to each other. In our example, the `user.blobEntity` attribute on the **Omni user profile** side is mapped to the `blobEntity` attribute on the **Omni Analytics User Profile** side. 4. Use the **arrows** in the middle of the dialog to set the attribute to **Apply mapping on user create and update**: 5. When finished, click **Save Mappings**. ## What's next? At this point, there are two things left: * **Syncing the attributes to Omni**. You can do this by: * **Waiting for Okta to perform the next automatic sync**, or * **Forcing a manual sync**. Open the Okta Omni application, click the **Provisioning** tab, and scroll down to the **Attributes** section. Click the **Force Sync** button to trigger a sync. * **Defining attribute values**. When you do this, use the **user profile attribute** you created in Okta in step 2. The mapping between this attribute and the one in the Okta Omni application will allow the value to flow through to your Omni instance. If you need a refresher on how to do this, refer to the [Okta documentation](https://help.okta.com/en-us/content/topics/users-groups-profiles/usgp-edit-user-attributes.htm). # Rippling authentication Source: https://docs.omni.co/administration/authentication/rippling/index Connect Omni to Rippling for secure SAML single sign-on and automated user provisioning. You can connect Omni to Rippling to manage authentication and user access through your organization’s existing identity provider. Rippling supports **SAML** for single sign-on and **SCIM** for automated user provisioning. ## Integration overview Connecting Rippling to Omni allows you to: 1. **Authenticate users** through Rippling using SAML. 2. **Control when and how users are provisioned** in Omni. ### User provisioning options Omni supports two approaches for provisioning users: | Option | How it works | When to use | | ---------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | **SCIM provisioning** | Users are created in Omni when assigned to the Omni app in Rippling. | You want users provisioned immediately upon assignment, regardless of whether they've logged in. | | **First-login provisioning** | Users are created in Omni only when they first log in via SAML. | You want to control seat usage by provisioning users only when they actually access Omni. | You can use first-login provisioning with or without SCIM. Refer to the [SAML setup guide](/administration/authentication/rippling/saml) for more details. ## Getting started Follow these steps to get set up. You can complete SAML only, or add SCIM and attribute sync for a fully automated experience. | Step | Description | Link | | ---- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | 1 | **Set up SAML SSO** to let users sign in to Omni with their Rippling credentials. | [SAML setup →](/administration/authentication/rippling/saml) | | 2 | **Enable SCIM provisioning** to automatically create, update, and deactivate users in Omni. | [SCIM setup →](/administration/authentication/rippling/scim) | ## Notes and troubleshooting * **Admin access required:** You’ll need Rippling admin permissions to configure SAML and SCIM. * **Test before rollout:** Try SSO with a test user before enabling it organization-wide. If you run into issues, check your Rippling app configuration or see [Omni's troubleshooting SSO guide](/administration/authentication/troubleshooting). ## Related * [Omni SAML configuration overview](/administration/authentication) * [Managing users and groups in Omni](/administration/users) * [Rippling documentation](https://\[idp-docs-link]/) # Configuring Rippling SAML SSO Source: https://docs.omni.co/administration/authentication/rippling/saml Integrate Omni with Rippling for user authentication via the SAML protocol. ## Requirements To follow the steps in this guide, you'll need: * Omni [Organization Admin permissions](/administration/users/permissions) * Permissions in Rippling that allow you to: * Create custom apps * Assign users & groups to apps ## Setup Open Omni's SAML settings and Rippling in separate browser tabs, as you will need to copy and paste values between the two applications to complete the setup. In your Omni instance, navigate to **Settings > Authentication** and locate the **SAML** section. 1. Sign into Rippling. 2. Search for `Custom app` in the search bar. 3. Select **Create new Custom app**. 4. Complete the app form: * **Name** - `Omni` * **Categories** - `Analytics & BI` * Upload the following logo: Omni logo 5. Select **Single Sign-on (SAML)**, or **SAML and SCIM app** if you intend to also configure SCIM. 6. Complete the single sign-on setup form: * Leave the **Metadata URL** and **Metadata** fields empty. * **ACS URL (Assertion Consumer Service URL)** - Copy and paste the **Single sign-on URL** value from the Omni Authentication settings (step 1) * **Service Provider Entity ID** - Enter the full hostname of your Omni instance, e.g. `blobsrus.omniapp.co`. Do not include `https://`. 7. Leave this form open, but note the following - you'll need it in the next step: * **Single Sign-on URL** * **Issuer** * **X509 Certificate** Navigate back to the Omni Authentication settings (**Settings > Authentication**) to complete the setup: * **Display Name** - Enter a name to customize the login button, for example `Rippling`. Leave blank to show the default **Log in with SAML** button. * **Entity ID / Issuer** - Copy and paste the **Issuer** value from Rippling * **Single Sign-on URL** - Copy and paste the **Single Sign-on URL** value from Rippling * **Certificate** - Copy and paste the contents of the **X509 Certificate** certificate. You may need to download it from Rippling. The certificate must include `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` values, for example: ```txt wrap theme={null} -----BEGIN CERTIFICATE----- [certificate contents] -----END CERTIFICATE----- ``` * **Automatically provision new users on first login from this SAML provider** - Toggle this setting to **on** if: * You want to provision users only when they first access Omni **and** * You don't plan to set up SCIM provisioning * **Enable SAML for users** - Toggle this setting to **on** When finished, click **Save SAML changes**. Navigate back to Rippling to finish configuring the custom Omni app: 1. On the setup form, click **Continue**. 2. Select **Do not allow admins to sign in to the admin account**. 3. Skip creating any group attributes. 4. In the app's **Settings** tab, navigate to the **SAML Attributes** section. 5. Create the following **global attributes**: | Name | Value | | ------------ | --------------------------- | | `first_name` | User's preferred first name | | `last_name` | User's preferred last name | Clicking the **Test now** button at this point will yield an error, as Rippling initially sets the SAML SSO as IdP-initiated. You will change this to SP-initiated in the next step. 1. In the Custom app's **Settings > Advanced SAML Settings**, enable **Application only supports login initiated from the application, also referred to as SP initiated flow**. 2. In **URL to trigger SP-initiated flow**, enter the URL of your Omni instance, e.g. `https://blobsrus.omniapp.co/`. In Rippling, assign users and user groups to the custom Omni application. Test your SAML setup by logging out of Omni. On the Omni login page, you should see a login button. Click the button to log in using SAML. By default, the login button will read **Log in with SAML**. Set a **Display Name** in the [Omni authentication settings](#omni-auth-settings) to customize this text. If the setup is successful, finish the setup by rolling out SAML authentication to the rest of your organization. ## What's next? Setting up SAML allows your users to authenticate to Omni using their Rippling credentials. With this setup completed, you can also [configure SCIM to auto-provision users & user groups in Omni](/administration/authentication/rippling/scim). # Auto-provisioning Omni users with Rippling SCIM Source: https://docs.omni.co/administration/authentication/rippling/scim Automatically manage Omni accounts for your users with Rippling SCIM provisioning. When SCIM (System for Cross-domain Identity Management) is enabled, you can automatically provision and de-provision Omni accounts for your users and synchronize Omni user groups with groups in Rippling. You can integrate Rippling's provisioning capability with Omni to create accounts for your users and synchronize Omni groups with attributes in Rippling. All users created via SCIM will be organization Members, organization Admins can only be created or converted from Member level in the UI. ## Requirements To follow the steps in this guide, you'll need: * **To have Rippling SAML authentication set up**. If you don't, refer to the [Rippling SAML authentication setup guide](/administration/authentication/rippling/saml) before proceeding. * **Omni Organization Admin permissions** * **Permissions in Rippling that allow you to** modify applications ## Limitations Only Rippling's `displayName` user attribute can be synced to Omni. ## Setup Omni users created via SCIM will have **Organization Member** permissions. Organization Admins must be created in **Settings > Users** or have their permissions [manually upgraded](/administration/users/permissions). 1. Follow [these steps](/api/authentication) to create a new API key named **Rippling SCIM**. 2. Copy the key somewhere handy - you'll need it to complete the setup. 1. In a new browser tab, log into Rippling. 2. Navigate to the Omni application. **Note**: If you don't have SAML set up already, complete the steps in the [Omni-Rippling SAML guide](/administration/authentication/rippling/saml) before proceeding. 3. Navigate to the **SCIM configuration form** and fill in the following: * **SCIM version** - Set to `2.0` * Leave **Does not support One Way Sync** disabled * **SCIM base url** - Enter the URL you use to log into Omni, appended with `/api/scim/v2`. For example, if your Omni login URL is `https://blobsrus.omniapp.co`, you would enter `https://blobsrus.omniapp.co/api/scim/v2`. * **SCIM authorization method** - Set to `Bearer Token` * Enable **Supports groups** * **Supports Mutually Exclusive Groups** - Set to **Not Mutually Exclusive Groups** * Enable **Supports pagination** and **Create & Delete Groups** * Leave **Use PATCH to edit Groups** and **Generate temporary password** disabled * Select **Use email address as username** * **Supported SCIM attributes** - Set to `displayName` 4. Click **Continue**. 1. If prompted, select **I'm the Omni admin, I'll install it**. 2. Ensure that **Offboarding** is enabled. 3. In the **Bearer Token** field, paste the Omni API key you created in step 1. If Rippling doesn't prompt you to provide a Bearer token, you may need to re-install the custom app. Follow the **Modify App** link in the app's **Settings** tab to do this. 4. Configure provisioning rules and match up existing user accounts and groups. 1. In Omni, navigate to **Settings > Authentication**. 2. Enable **Automatically provision new users on first login from this SAML provider**. This ensures that users assigned to the Omni app in Rippling are automatically created in Omni when they first log in via SAML. 3. Click **Save SAML changes**. **Note**: when users are removed from your Rippling system they will be de-provisioned and revoked in Omni which has implications for the schedules and content they own. See the [Revoke Membership](/administration/users/delete) page for more details. # SAML and SCIM troubleshooting Source: https://docs.omni.co/administration/authentication/troubleshooting Common issues and solutions for SAML and SCIM authentication in Omni. Omni does not support identity provider (IdP)-initiated SSO login for SAML, which means users can't log in by clicking a link in the IdP's dashboard. If they do attempt to log in this way, they'll receive an error similar to the following: ```txt wrap theme={null} Unable to process request due to missing initial state. This may happen if browser sessionStorage is inaccessible or accidentally cleared. Some specific scenarios are - 1) Using IDP-Initiated SAML SSO. 2) Using signInWithRedirect in a storage-partitioned browser environment. ``` To resolve this, users must log into Omni by navigating to the Omni login page and clicking the **Log in with SAML button**. If your users are accustomed to logging in to applications directly from the IdP, most allow you to provide a link to the Omni login page as an app tile. # Managing billing & invoices Source: https://docs.omni.co/administration/billing View your organization's Omni billing information & invoices. The **Settings > General > Billing** tab allows you to view billing-related information for your organization, including past invoices and Omni's W9. ## Requirements **Organization Admin** permissions are required to access the Billing page. ## Viewing invoices The **Invoices** section of the **Billing** page lists the past invoices for your organization, beginning with the most recent: ## Billing contacts In the event that Omni needs to contact you about billing or payment-related issues, we'll reach out to the person(s) specified in the **Billing** setting located in [**Settings > General > Contacts**](/administration/settings#contacts). # Managing custom chart palettes Source: https://docs.omni.co/administration/chart-palettes/custom Create custom palettes with your company colors, ensuring your workbooks, charts, and dashboards are always consistent and on-brand. ## Requirements **Organization Admin** permissions are required to create and modify custom color palettes. ## Creating custom chart palettes 1. Navigate to **Settings > Chart palettes.** 2. Click **Add**. 3. Customize by adding, editing and removing colors. Use the color picker control or select **Open hex code editor** and paste in a list of comma-separated hex codes: Diagram showing the architecture of the system 4. When finished, click **Save**. Once created, you can identify custom palettes using the asterisk (`*`) next to their name in the **Chart palettes** page: Custom palettes will be listed in the chart editor palette picker in alphabetical order before any of the [built-in palettes](/administration/chart-palettes/omni). ## Editing custom chart palettes 1. Navigate to **Settings > Chart palettes**. 2. Click the (three dots icon) next to a custom palette and select **Edit**. 3. Make your changes. 4. Click **Save** when finished. Existing charts that use the palette will be updated with the changes. ## Deleting custom palettes If deleting the default palette, set a new [default palette](/administration/chart-palettes/default) first. 1. Navigate to **Settings > Chart palettes**. 2. Click the (three dots icon) next to a custom palette and select **Delete**. Any existing charts using the palette will be updated to use the organization's default palette. # Setting a default chart palette for your organization Source: https://docs.omni.co/administration/chart-palettes/default Set a default chart color palette for your Omni organization, applied automatically to new charts based on chart type and data. The current default will have a blue DEFAULT badge next to its name: ## Requirements **Organization Admin** permissions are required to set a default chart palette. ## Setting the default palette To set a new default palette, click the (three dots icon) next to the palette and select **Set as default**. Existing charts that use the default color palette will be updated to the new default. The default discrete and continuous palettes will also be available for use in [Apps](/visualize-present/apps/styling#charts). # Managing chart palettes Source: https://docs.omni.co/administration/chart-palettes/index Predefined color palettes help you apply consistent colors across charts, workbooks, and dashboards. Omni includes [several discrete and continuous palettes](/administration/chart-palettes/omni), and administrators can add custom ones for greater flexibility. Organization Admins can [set default palettes for the organization](/administration/chart-palettes/default) and optionally [create custom palettes](/administration/chart-palettes/custom). ## Requirements **Organization Admin** permissions are required to create and modify custom color palettes in the **Settings > Chart palettes** page. ## Using palettes in visualizations Chart palettes can only be used in X/Y style charts such as bar, scatter, line, etc. Chart palettes are currently only used for color faceting. You can access the chart palettes from the **Options** panel in the **Color > Options** popup. Any [custom palettes](/administration/chart-palettes/custom) created for the organization will appear in the list before the [built-in palettes](/administration/chart-palettes/omni). For more on using palettes in visualizations, see the [Color by / Stacking documentation](/visualize-present/visualizations/configuration/color). # Built-in palette color reference Source: https://docs.omni.co/administration/chart-palettes/omni The color values for the built-in palettes are provided as a reference for creating your own palette variations. For all other palettes, refer to the [Vega Scheme Reference](https://vega.github.io/vega/docs/schemes/#scheme-reference). Click a **colored square** to copy the hex code for that color. Click the **Pastable hex codes** tabs in each palette section to copy the hex codes for all colors in the palette. ## Discrete palettes ### Basic ``` #298BE5, #F7B54E, #FF6291, #1DB9B9, #FF8515, #3D923B, #4D59E2, #E43030, #97A345, #BE43C0, #94C5F7, #F6E692, #FF9EC8, #96F1F3, #FFC28A, #97D087, #A5ABF8, #F08A8A, #C1CA82, #DFA3E0, #025DB1, #D7870A, #E11955, #1C8787, #B85800, #296228, #2530B6, #AB1616, #6E7632, #752877 ``` ### Pairs ``` #94C5F7, #298BE5, #F6E692, #F7B54E, #FF9EC8, #FF6291, #96F1F3, #1DB9B9, #FFC28A, #FF8515, #97D087, #3D923B, #A5ABF8, #4D59E2, #F08A8A, #E43030, #C1CA82, #97A345, #DFA3E0, #BE43C0 ``` ### Threes ``` #94C5F7, #298BE5, #025DB1, #F6E692, #F7B54E, #D7870A, #FF9EC8, #FF6291, #E11955, #96F1F3, #1DB9B9, #1C8787, #FFC28A, #FF8515, #B85800, #97D087, #3D923B, #296228, #A5ABF8, #4D59E2, #2530B6, #F08A8A, #E43030, #AB1616, #C1CA82, #97A345, #6E7632, #DFA3E0, #BE43C0, #752877 ``` ### Fours ``` #94C5F7, #298BE5, #025DB1, #013A6F, #97D087, #3D923B, #296228, #183A17, #DFA3E0, #BE43C0, #752877, #4B1A4C, #96F1F3, #1DB9B9, #1C8787, #135D5D, #FF9EC8, #FF6291, #E11955, #971139 ``` ### Ordered ``` #1DB9B9, #298BE5, #4D59E2, #BE43C0, #FF6291, #E43030, #FF8515, #F7B54E, #9BA345, #3D923B ``` ### Ordered Pairs ``` #96F1F3, #1DB9B9, #94C5F7, #298BE5, #A5ABF8, #4D59E2, #DFA3E0, #BE43C0, #FF9EC8, #FF6291, #F08A8A, #E43030, #FFC28A, #FF8515, #F6E692, #F7B54E, #CBD397, #9BA345, #97D087, #3D923B ``` ### Ordered Threes ``` #96F1F3, #1DB9B9, #1C8787, #94C5F7, #298BE5, #025DB1, #A5ABF8, #4D59E2, #2530B6, #DFA3E0, #BE43C0, #752877, #FF9EC8, #FF6291, #E11955, #F08A8A, #E43030, #AB1616, #FFC28A, #FF8515, #B85800, #F6E692, #F7B54E, #D7870A, #C1CA82, #97A345, #6E7632, #97D087, #3D923B, #296228 ``` ### Ordered Fours ``` #96F1F3, #1DB9B9, #1C8787, #135D5D, #94C5F7, #298BE5, #025DB1, #013A6F, #DFA3E0, #BE43C0, #752877, #4B1A4C, #FF9EC8, #FF6291, #E11955, #971139, #97D087, #3D923B, #296228, #183A17 ``` ### Red Green ``` #E43030, #3D923B ``` ### Red Yellow Green ``` #E43030, #F7B54E, #3D923B ``` ## Continuous palettes ### Basic Blues ``` #D6E9FA, #298BE5, #013A6F ``` ### Basic Greens ``` #D6ECCF, #3D923B, #183A17 ``` ### Basic Red Yellow Green ``` #E43030, #F6E692, #3D923B ``` # Content permission settings Source: https://docs.omni.co/administration/content-permissions Manage the default content permissions for your organization in **Settings > Content permissions**. **Organization Admin** permissions are required to access and modify organization-level content permissions. ## Default content access Defines the default user role that all users will have for content (documents and folders) they have access to. Users can be granted additional permissions at the document or folder level - this setting only defines a default base role. For individual documents, users with **Manager** or **Owner** content roles have the ability to set the organization access role higher or lower than the default role defined in this setting. ## Default document abilities Defines default abilities for all documents in the organization. These settings control the abilities users can select in documents: | Ability | Description | | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Upload data](/analyze-explore/data-input-csvs) | Allow users to upload data (CSV, Excel, etc.) to this document. Requires the user to have a [model role][model-role] that allows uploading data. | | [Schedules](/share) | Allow the creation of new deliveries and alerts on this document. Requires the user to have a [model role][model-role] that allows scheduling. Disabling will not remove existing deliveries or alerts. | | **Download** | Allow users to download the document's [data](/analyze-explore/point-click-queries#downloading-results) and [dashboard](/visualize-present/dashboards/download). Requires the user to have a [model role][model-role] that allows downloading. | | [Create spreadsheets](/analyze-explore/spreadsheet-tabs) | Allow users to create spreadsheets. | | **Drill** | Allow users to drill into various data points in this content. | | **Duplicate** | Allow users to duplicate the document. Disabling prevents users from creating a copy of the dashboard or workbook, or [copying individual tabs into another workbook](/analyze-explore/workbook-basics#copy-a-tab-to-an-existing-workbook). **Note**: Reach out to Omni support to have this feature enabled. | | **Viewers can see workbook** | Allow users with the **Viewer** content role and a connection role with the **Use workbooks** ability to see a read-only version of the workbook. They will not be able to edit the workbook or see non-topic tabs or SQL tabs. AccessBoost does not apply to workbooks at this time. | | [Request access](/share/#requesting-document-access) | Allow users who do not have access to this document to request access from the document owner. | | [Require pull request to publish](/content/develop/branch-mode#requiring-pull-requests-to-publish-document-changes) | Require users to publish changes to this document through a pull request | | [Chat with Content](/ai/dashboard-assistant) | Allow users to use Chat with Content on the published version of the document. Requires AI data reading permissions to be enabled at the organization level and the user to have a [model role][model-role] that allows AI use. | | **Timezone override** | Allow users to change the query timezone for this document. See [Enabling timezone selection on documents](/visualize-present/dashboards/timezone-override) for more information. | ## Content creation: Shared "root" is open Allows users to add documents and folders to the root of your organization's [**Hub**](/content/navigate) (shared folder). Otherwise, users will be able to create content in folders they have specifically been granted access to. ## AccessBoost Enables permission boosting, which will ignore a user's database connection role. If **Non-administrators can enable AccessBoost on content** is also enabled, users with SQL editing permissions and embed users can also enable AccessBoost on documents. Refer to the [Sharing content guide](/share#boosting-permissions-with-accessboost) for more information about AccessBoost, including its security implications. ## Delivery personalization Controls whether users can personalize email deliveries with recipient user attributes. This setting determines the availability of the **Personalize delivery with the recipient's user attributes** checkbox in the [email delivery dialog](/share/deliveries/email#email-settings).
Option Description Affects existing deliveries? Delivery setting availability
**Configurable** Users can choose whether to personalize each delivery **No** **Available**
**Always** Forces personalization on for all email deliveries and automatically updates existing deliveries to use the recipient's user attributes.

**This option can't be used if any connection in your Omni organization uses [per-user OAuth](/connect-data/oauth)**. If your organization has OAuth connections, you'll receive an error when you try to select this option.
**Yes** **Removed**
**Never** Forces personalization off for all email deliveries and automatically updates existing deliveries to use the delivery owner's user attributes. **Yes** **Removed**
Switching to **Always** or **Never** will update every existing email delivery in the organization to match. Switching back to **Configurable** later leaves those deliveries as they are - it doesn't restore the per-delivery choices they had before, and each delivery will have to be set manually. You'll be prompted to confirm the switch. All delivery personalization mode changes are recorded in the organization's [audit log](/administration/audit-logs/event-types). ## Verification Controls whether visual indicators appear in workbooks to distinguish between verified model fields and unverified workbook-specific fields (custom fields and formulas). When **Show verification indicators** is enabled, workbook users will see indicator icons next to unverified fields in the field browser, data table headers, and visualization configurations. This helps users understand which fields come from the organization's verified (shared) data model and which are custom workbook fields. For more details, see [Identifying workbook-only fields](/analyze-explore/point-click-queries#identifying-workbook-only-fields). [model-role]: /administration/users/custom-roles "model role" # Omni administration Source: https://docs.omni.co/administration/index Manage users, security, billing, and more in your Omni instance As an Omni Organization Admin, you're responsible for managing your organization's users, permissions, security settings, and more. Use this section of the docs to get started with common administration tasks. ## Get started Add, remove, and manage users in your organization Control what users can see and do in Omni Configure organization-wide settings and preferences ## Security and authentication Configure single sign-on with Google, Okta, Rippling, or Microsoft Entra Configure OAuth using the OIDC protocol Learn about Omni's security practices and compliance ## Monitor and manage Track how your organization uses Omni Manage your subscription and billing details # Localization settings Source: https://docs.omni.co/administration/localization Configure language settings at the organization and user levels. Localization settings control the language used for the Omni app interface. You can configure a default locale for your entire organization and, optionally, override it for individual users. ## Requirements To use localization, you'll need: * **Organization Admin permissions**, which are required to access and modify organization settings ## Organization-level localization Organization-level localization is managed in **Settings > General**. ### Locale The **Locale** setting defines the default language used for the Omni app interface across your organization. * Changes to the locale update the language of the app UI for users who don't have a user-specific locale set. * This setting is applied at the organization level and affects all users by default. Omni currently supports the following locales: | Locale code | Language | | ----------- | ----------------------------- | | `en-US` | English (default) | | `ar-SA` | العربية (السعودية) (Arabic) | | `de-DE` | Deutsch (Deutschland) | | `es-CL` | Español (Chile) | | `es-ES` | Español (España) | | `fr-FR` | Français (France) | | `he-IL` | עברית (ישראל) | | `it-IT` | Italiano (Italia) | | `ja-JP` | 日本語 (日本) | | `ko-KR` | 한국어 (대한민국) (Korean) | | `nb-NO` | Norsk bokmål (Norge) | | `pt-BR` | Português (Brasil) | | `pt-PT` | Português (Portugal) | | `sv-SE` | Svenska (Sverige) | | `th-TH` | ไทย (ประเทศไทย) (Thai) | | `vi-VN` | Tiếng Việt (Việt Nam) | | `zh-CN` | 中文 (中国) (Simplified Chinese ) | ### Allowed locales The **Allowed locales** setting defines which locales are available for use in your Omni instance. * Only locales in this list will be available when selecting a locale for users. * Use this setting to limit the languages that appear as options for your organization (for example, if you only support a subset of languages internally). ## User-level localization You can override the organization-level locale for specific users in **Settings > Users**. To set a user-specific locale: 1. Navigate to **Settings > Users**. 2. Find the user you want to update and click **Manage**. 3. On the user's settings page, choose a value in the **Locale** field. 4. Save your changes. Users can also set their own locale in their [user profiles](/administration/users/your-account) by clicking **their avatar > Manage account**. When a user has a locale set on their profile: * The user-level **Locale** controls the language of the app interface for that user. * If no user-level locale is set, the user inherits the organization-level **Locale**. This lets you support users who need to work in different languages within the same Omni organization. ## Embedded users For embedded Omni experiences, you can pass a `locale` user attribute in the embed configuration to control the interface language for embed users. When provided, this attribute behaves like a user-level locale: * If the `locale` attribute matches one of your **Allowed locales**, it will be used for that embedded user. * If the attribute is missing or does not match an allowed locale, the user falls back to the organization-level **Locale**. # Canceling long-running and hanging queries Source: https://docs.omni.co/administration/running-queries Stop queries that hang or run longer than expected, saving your database resources. Queries that run longer than expected, or that hang entirely, can consume database resources and leave dashboards stuck loading. Omni gives you two ways to stop them: * On the dashboard where the queries are running * From the **Settings > Running queries** page, where you can cancel queries across multiple documents and, if you're an Organization Admin, queries by other users ## Stopping queries on a dashboard While viewing a dashboard, you can stop running queries without leaving the page by: * Clicking **View > Stop queries**. This item will be disabled when no queries are running. * Clicking the **(stop) icon in the footer** while a run is in flight. This displays next to the (download) and (schedule) icons. This will stop all running queries on the dashboard. Additionally, [auto-refresh](/visualize-present/dashboards/settings#auto-refresh) will be disabled until you reload the page. Use the [dashboard performance profiler](/visualize-present/dashboards/performance-profiler) to help optimize dashboard queries. ## Stopping queries from Settings The **Settings > Running queries** page is useful when you need to cancel queries across multiple documents. Organization Admins will see all users' queries, while all other users will only see their own queries. You can stop a specific query by clicking its **Cancel** button. To cancel multiple queries, select the checkboxes next to the queries and then click **Cancel selected queries**. ## Next steps * Identify inefficient queries with the [Dashboard performance profiler](/visualize-present/dashboards/performance-profiler) * Use [caching](/analyze-explore/performance/caching) to improve query performance * Optimize queries with [aggregate awareness](/analyze-explore/performance/aggregate-awareness) # Omni supported cloud regions Source: https://docs.omni.co/administration/security/cloud-regions Select a cloud region for your Omni instance, which determines where customer content will be stored and processed. Omni uses Amazon Web Services (AWS) and Azure to host application deployments. While you can choose the cloud region your Omni application is hosted in, the availability of a specific region is dependent on whether your application is deployed in AWS or Azure. | Region | AWS deployments | Azure deployments | | -------------- | --------------- | ----------------- | | United States | | | | Canada | | | | EU | | | | United Kingdom | | | | Australia | | | | India | | | | UAE | | | | Singapore | | | Customer content will be stored and processed in your selected region. ## Using multiple regions Each Omni organization account is hosted in a single region. To use Omni across multiple regions, you must maintain an Omni organization account in each region. # Omni product & system security Source: https://docs.omni.co/administration/security/index Learn more about how Omni keeps your data secure. Omni is designed to ensure data is only accessible to those who are permitted to access it. Our technical architecture keeps organizations and data sets isolated, and the foundation of our product is a data model with robust governance capabilities that can limit the data sets, fields, and records accessible on a per-user basis. ## Product security and architecture Omni observes the following product and design principles: * Customer Data is always encrypted at rest and in transit over public networks, and customer credentials are additionally encrypted at the application level and can only be decrypted by the application components that require them. * User authentication through your organization's identity provider like Google, Okta, or any SAML-compatible identity provider, allows you to control security requirements like MFA. * Users can be assigned [attributes](/administration/users/attributes) that can checked in authorization logic to, for example, limit the user's access to data sets or apply filters. * Authentication and authorization checks are applied immediately upon the receipt of every request to Omni, and, if passed, set an authorization context on subsequent code execution that ensures the request is sandboxed to the appropriate user and organization. * Access to a customer's Omni instance by Omni personnel for support is visible to and controllable by the customer. ## Customer data Omni processes the following data: * Information about Omni users, for example name and email. This does not include user passwords since this is delegated to a third party identity provider * Omni configuration data, for example connection parameters, the Omni data model, and chart and dashboard configuration, *excluding* credentials to customer systems * Data contained in the data sources connected to Omni, referred to as "Customer Data" * Credentials to access customer data, referred to as "Customer Credentials" ### Data segregation and encryption Customer Data and Customer Credentials are: * Logically segregated on Omni's systems by customer tenant ID and unique dataset identifiers * Always encrypted at rest and in transit over public networks Ownership of Customer Data is retained by the customer. ## Security and compliance documentation See the [Omni Trust Center](https://trust.omni.co/). # Omni information security program Source: https://docs.omni.co/administration/security/information-security-program Omni maintains written policies and procedures designed to ensure the security of our employees, partners, and customers. Omni's CTO is responsible for the Information Security Program, which is reviewed and updated periodically. ## Compliance audits Compliance with the policies and procedures is audited at least annually through a SOC 2 Type II audit, which is available upon request. ## People policies Employees and contractors with access to company data and resources are required to complete the following: * Sign a confidentiality agreement * Agree to comply with the policies of the information security program * Pass a background check by a third party provider ## Data protection and access control Omni classifies Customer Data as our most sensitive asset, and protects it as follows: * Customer Data is not permitted to be copied to destinations outside of the production infrastructure, and is not used for testing, development, or any purpose other than providing the product. * Customer Data is only stored in Omni systems temporarily, and can be permanently deleted upon request * Access to the production infrastructure and systems is granted on a least privilege basis, requires authentication with multiple factors, and logged. Production infrastructure is configured and deployed through automated processes, so direct human access is needed only in rare cases and is not granted to employees other than those responsible for maintaining the automated processes. * Access to Customer Data via the Omni application by Omni personnel for support can be controlled and revoked by the customer * Use of third party subprocessors on customer data is minimized and, when necessary, subject to thorough review # Allowlisting Omni's IP addresses Source: https://docs.omni.co/administration/security/omni-ip-addresses Find the static IP addresses for your Omni environment and configure your firewall or allowlist for secure database connections. By default, outgoing database connections from Omni originate from a set list of IP addresses per environment. ## Locating Omni's IP addresses Omni's IP addresses can be found on an individual connection's page, accessed by navigating to **Settings > Connections** and clicking a connection. ## Restricting connection access In some cases, access to a [database](/connect-data), [SFTP server](/share/deliveries/sftp), or even [webhooks](/share/deliveries/webhooks) can be configured to allow access only from specific IP addresses. This is called an **allowlist**. If you choose to limit access in this way, make sure that all of Omni's IP addresses are included in the allowlist. # Vulnerability disclosure policy Source: https://docs.omni.co/administration/security/vulnerability-disclosure Learn how Omni handles vulnerabilities and how to report them to our security team. We are committed to maintaining the security and integrity of our products, services, and systems. Collaboration with the security community strengthens our protections and helps ensure the safety and privacy of our users. ## Our expectations of you * **Test responsibly**. Make sure your research doesn’t impact privacy, disrupt users, or damage our services. * **Stay within scope**. Focus only on what this policy considers to be [in scope](#in-scope) - anything not listed is off-limits. * **Report it**. Use our [contact information](#submitting-reports) to send us your findings. * **Keep it confidential**. Don’t share details about the vulnerability until we’ve had time to review and/or patch it. ## What you can expect from us When you report a vulnerability to us, you can expect: * **Legal protection**. We won't take legal action against you if you follow the guidelines. * **Prompt acknowledgment**. You’ll hear back from us within 3 business days and we’ll work to fix the issue quickly. ## Vulnerability evaluation We’ll assess your report based on: * **Impact**. What is the potential impact of this issue? Could it compromise user privacy or security? * **Likelihood**. How easy is it to exploit? Does it require advanced skills or is it something a typical attacker could use? ### In scope This policy covers all systems, services, and infrastructure that are developed, operated, or supported by Omni Analytics. This includes nearly all the content hosted within the following domains: * `*.omni.co` * `*.omniapp.co` ### Out of scope This policy does not cover the following: * **Third-party services**. If the issue is with a service not controlled by us, we can’t take responsibility for it. * **Social engineering**. Phishing, smishing, and similar attacks are out of scope. * **Cosmetic issues**. UI glitches, spelling mistakes, or minor user experience bugs aren’t considered vulnerabilities. * **Denial of Service (DoS/DDoS)**. We’re not interested in network-level attacks. * **Outdated browsers/plugins**. Flaws affecting outdated software are outside the scope of this policy. ## Submitting reports If you've found a vulnerability, email us at [security@omni.co](mailto:security@omni.co) and include: * A description of the issue and why it's a problem * The steps to reproduce the vulnerability, including screenshots, scripts, or videos if possible Do not include personally identifiable information (PII) or payment card information (PCI) in your reports to us. We value your efforts to help us improve security and we look forward to working with you! # Organization settings Source: https://docs.omni.co/administration/settings Configure organization-wide settings in Omni, including user access defaults, content visibility, and support access controls. **Organization Admin** permissions are required to access and modify organization settings. The **Settings > General** tab contains settings that apply to your entire Omni organization. From here, you can control user, content, and Omni support access. Settings for [Apps](/administration/settings/app-policy) live on their own **Settings > Apps** tab. Settings for your organization's [custom sidebar](/administration/settings/sidebar) live on their own **Settings > Sidebar** tab. ## General Settings in the **General** tab control the organization's name, default timezone, localization, user invitations, and support settings. ### Default timezone Defines the default timezone for the organization, which is used in emails sent by Omni. **Note**: This setting doesn't apply to [database connections](/connect-data/timezones), which have their own timezone settings. ### Locale and allowed locales Controls the default language used for the Omni app interface and which languages are available to users. * **Locale** – Sets the default app language for your organization. Users without a user-specific locale will see the app in this language. * **Allowed locales** – Defines which locales are available as options in your Omni instance. For more details, see the [Localization settings guide](/administration/localization). ### Session length Controls how long non-embed users stay logged in before requiring re-authentication. Defaults to 24 hours. To change the default, enter a whole number between 1 and 4320 hours. The maximum of 4320 hours equals 180 days. This setting applies to non-embed sessions only. Embed sessions are managed separately. For information on embed session management, see [Embed session management](/embed/admin/sessions). ### Trash visibility window Controls how long deleted content remains visible in the [Trash](/content/archive-restore) before being automatically hidden. Defaults to 180 days. This setting affects the visibility of archived documents, models, branches, and connections in their respective **Trash** tabs. Content archived longer ago than the configured window will be hidden in the **Trash** and will not appear in trash counts. This setting only affects visibility in the **Trash**; nothing is deleted or purged. To make content hidden due to the retention window visible again, increase the retention window or leave the field blank to show all archived content, regardless of age. ### New user invitations When enabled, new users can request an invitation to the Omni organization from the login page. Otherwise, users will need to contact someone outside of Omni to be added to the Omni organization. ### Support settings * **Session recording** - When enabled, Omni support will have access to replays of sessions where bugs or errors were encountered * **Automatic support user creation** - When enabled, Omni support can automatically access your instance for assistance and problem solving * **Limit Omni support logins by region** - Allows you to limit logins from Omni support to a specific region. When set to something other than **All regions**, the support user's IP address must reside in the specified region to successfully log in to your instance. Contact Omni support for access to the **Limit Omni support logins by region** setting. ### Homepage content Allows you to set a default dashboard or app that adds an inline dashboard or app on the homepage for all users. This setting can be used in embedded Omni instances. Custom content displaying on Omni homepage when 'Chat on homepage' is enabled To set homepage content: 1. In **Settings > General**, click the **Homepage content** dropdown. 2. Start typing to search for a dashboard or app. **Note**: Only published documents with a dashboard or app will be returned. Workbook-only documents cannot be selected. 3. Select a dashboard or app. 4. Click **Save** to apply the changes. If the selected dashboard or app isn't accessible to all users, Omni will display a `Limited visibility` message when you click save. Users without access to the content will see the default homepage instead, without the inline content. To make the content visible on all users' homepages, share it with the entire organization. Homepage content adheres to the selected content's cache policy. For example, if you set a dashboard with a 24 hour cache policy as homepage content, the content is cached using that policy. ## Contacts The **Settings > Contacts** tab allows you to define contact persons for your organization. These settings accept comma-separated lists of email addresses. ### Billing Defines the contact person(s) for notices about billing and payments related to your organization. ### Security and Privacy Defines the contact person(s) for notices about security and privacy, including subprocessor updates. ## Preferences The **Settings > Preferences** section allows you to control optional features and behaviors for your Omni organization. ### Opt out of easter eggs When enabled, disables all easter eggs across your Omni organization. This setting applies organization-wide and affects all users. ### Opt out of product announcements When enabled, hides in-app product announcements from non-Organization Admin users in your Omni organization. Announcements targeted specifically at Organization Admins will continue to display, including to the admin who enabled this setting. # App settings Source: https://docs.omni.co/administration/settings/app-policy Control whether your organization can use Apps and which external hosts those apps are allowed to load resources from. **Organization Admin** permissions are required to access and modify app policy settings. The **Settings > Apps** tab controls whether your organization can use [Apps](/visualize-present/apps) and which external hosts those apps may load resources from. ## Enable apps Controls whether your organization can use [Apps](/visualize-present/apps), which let you build custom data experiences beyond traditional dashboards. To restrict app creation to specific users or groups rather than turning apps off entirely, use the granular permission on a [custom role](/administration/users/custom-roles#permissions-reference). ## External source policy Apps run in a sandboxed iframe whose Content Security Policy blocks outbound network requests by default. The **External source policy** sets the organization-wide ceiling on which external hosts that policy will open up — for images, scripts, stylesheets, fonts, and network connections. This is separate from, and takes precedence over, the [**Safe domains**](/visualize-present/apps/settings#safe-domains) setting an app editor configures on an individual app. ### Policy options | Policy | What apps can load | Effect on an app's Safe domains | | ----------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------- | | **Open** | Omni's default hosts, plus any host an app editor adds | Honored as written | | **Omni defaults** | Omni's default hosts only | Ignored | | **Custom** | Only the hosts you list — these **replace** the default hosts rather than adding to them | Honored only where an entry falls within one of your hosts | **Omni defaults** is the policy for an organization that hasn't chosen one. Under **Custom**, your list replaces Omni's default hosts. If your apps rely on a default host — a charting library from `cdn.jsdelivr.net`, or `fonts.googleapis.com` — you have to list it yourself or those resources stop loading. To block external loading entirely, choose **Custom** and leave the host list empty. There's no separate off switch: an empty custom list means an app loads nothing from any external host. ### Setting a custom host list 1. Go to **Settings > Apps**. 2. Under **External source policy**, set **Source policy** to **Custom**. 3. Enter your hosts in the **Custom hosts** field. Add one host per line, or separate them with commas or spaces: ```text theme={null} cdn.example.com *.assets.acme.co cdn.jsdelivr.net ``` 4. Click **Save source policy**. A custom list accepts up to 25 hosts and uses the same formats as an app's [Safe domains](/visualize-present/apps/settings#domain-formats). A `*.` wildcard matches subdomains but not the domain itself, so `*.example.com` covers `cdn.example.com` but not `example.com`. ## Next steps * [Apps](/visualize-present/apps) * [App settings](/visualize-present/apps/settings) — the per-app settings an editor controls * [Organization settings](/administration/settings) # Authentication settings Source: https://docs.omni.co/administration/settings/authentication Configure general authentication behavior, SAML, and OIDC for your Omni organization. **Organization Admin** permissions are required to access and modify authentication settings. The **Settings > Authentication** page contains settings that control how users sign in to your Omni organization. From here, you can manage general authentication behavior and configure SAML or OIDC. ## Default sign-in methods The **Default sign-in methods** section controls which authentication methods are available to users by default. At least one [external sign-in method](#external-sign-in) must be configured before any default methods can be disabled. ### Google When enabled, users can use their Google Workspace account to log in. **Note**: This is a different sign-in method than [Google Workspace SAML](/administration/authentication/google-workspace), which requires additional setup. ### Email When enabled, users can enter their email address and receive a link to log in. #### Admin fallback When **Email** is disabled as a sign-in method, an additional **Admin fallback** setting will display. By default, Organization Admins can sign in using email link authentication as a fallback in case other authentication methods are broken or unavailable. This ensures admins can always access Omni to troubleshoot identity provider issues. When disabled, this fallback is removed and Organization Admins must sign in using the configured SAML or OIDC provider. Disabling the email link fallback can lock administrators out of Omni if your identity provider becomes unavailable or misconfigured. Make sure you have a recovery plan before disabling this setting. ## External sign-in methods The **External sign-in methods** section allows you to enable authentication through your organization's single sign-on. ### SAML When enabled, Security Assertion Markup Language (SAML) can be used as an authentication method. Configuring your Identity Provider (IdP) is required before users can successfully use this method to sign in to Omni. For step-by-step setup instructions, refer to the guide for your identity provider: * [Google Workspace](/administration/authentication/google-workspace) * [Microsoft Entra (Azure AD)](/administration/authentication/entra/saml) * [Okta](/administration/authentication/okta/saml) * [Rippling](/administration/authentication/rippling/saml) ### OIDC When enabled, OpenID Connect (OIDC) can be used as an authentication method. Configuring your OIDC Identity Provider is required before users can successfully use this method to sign in to Omni. For setup instructions, refer to the [OIDC configuration guide](/administration/authentication/oidc). ## Modifying authentication settings Click the toggle next to a setting to enable or disable it. When finished, click **Save** to apply the changes. ## Need help? If you run into issues during setup, check the [SSO troubleshooting guide](/administration/authentication/troubleshooting) for common problems and solutions. # Emoji settings Source: https://docs.omni.co/administration/settings/emoji Configure emoji mode for query tabs and manage custom emoji at the organization level. Emoji settings let you control how query tabs are named in workbooks and manage custom emoji across your Omni organization. You can toggle between emoji-based and sequential tab names, set overrides for embedded experiences, and use custom emoji in dashboards, Markdown, and more. ## Requirements **Organization Admin permissions** are required to access emoji settings. ## Accessing emoji settings Organization-level emoji settings are managed in **Settings > Emoji**. ### Emoji tabs The **Emoji tabs** setting controls how new query tabs are named when users create them in workbooks. * **When enabled** (default): New query tabs are named with emoji prefixes (for example, "🔍 Query") * **When disabled**: New query tabs are named sequentially (for example, "Query 1", "Query 2", "Query 3") This setting applies to all users in your organization by default. ### Sequential tab naming When emoji mode is disabled, Omni uses the workbook's tab index to generate sequential names: * The first query tab is named "Query 1" * The second query tab is named "Query 2" * Additional tabs continue this pattern This naming convention helps users quickly identify and reference specific query tabs in workbooks with many queries. ## Embed emoji override For embedded Omni experiences, you can set a separate emoji mode that overrides the organization-level setting. The **Embed emoji tabs** setting allows you to: * Enable emoji mode for embed sessions while keeping it disabled for your internal users * Disable emoji mode for embed sessions while keeping it enabled for your internal users * Leave it unset to use the organization-level **Emoji mode** for both internal and embed users When set, this override applies to all embed sessions in your organization. Embed users will see query tab names based on this setting rather than the organization-level emoji mode. ## Custom emoji Custom emoji is currently in beta. Additionally, this feature is only available to non-white-labeled embed organizations. Omni's custom emoji catalog (Blobby) provides additional emoji options beyond the standard set. You can use custom emoji throughout Omni to add visual context and personality to your content. White-label organizations do not have access to custom emoji, as the catalog contains Omni-branded emoji characters. ### Using custom emoji While **Organization Admin** permissions are required to access emoji settings, users with lesser permissions can use custom emoji in Omni. You can insert custom emoji anywhere text is supported by using the `:emoji-name:` syntax. For example, typing `:blobby-wave:` will render the waving Blobby emoji. Custom emoji works in the following locations: * **Dashboard tile titles** - Add emoji to visualization and text tile titles for visual categorization * **Markdown content** - Use emoji in markdown text tiles and markdown visualizations * **Workbook tab names** - Include emoji in query tab names to make them more recognizable * **Field labels** - Add emoji to dimension and measure labels in the modeling layer ### Limitations * Downloads and deliveries are not yet supported * Custom emoji will not render inside code blocks or inline code elements. This ensures that emoji syntax in code examples remains as plain text. ### Syntax To use a custom emoji, wrap the emoji name in colons: ```text theme={null} :emoji-name: ``` For example: ```text theme={null} :blobby: Welcome to our dashboard! ``` This will render as: > Welcome to our dashboard! You can use multiple emoji in the same text: ``` :blobby-chart: Sales metrics :blobby-up: ``` # Customizing your organization's navigation sidebar Source: https://docs.omni.co/administration/settings/sidebar Build a custom sidebar for your organization with a visual, drag-and-drop editor and live preview. Use the **Settings > Sidebar** editor to control what users in your Omni organization see in the navigation sidebar. You can add custom groups and items for specific content or external links, like a support site or internal wiki, then reorder and rename them. Omni's built-in groups always stay in the sidebar, but you can rename their items, change their icons, or reset them to defaults. **Embedding Omni?** Create a custom sidebar for a curated, branded navigation experience. ## How it works The Omni sidebar is made of built-in groups and, optionally, custom groups you add. Each group contains items, which can point to a built-in Omni page, an external link, or an existing piece of content in the organization: | Type | Links to | Visibility | | ------------------------------------------------------ | -------------------------------------- | --------------------------------------------------------- | | **Built-in** | An Omni page, such as **My documents** | All users | | **External link** | An external page | All users | | **Content** | An existing folder or document in Omni | Users with at least **Viewer** permissions on the content | Built-in items only exist in built-in groups. Custom groups can only contain external link and content items. ### Default sidebar Omni's default sidebar contains four built-in groups: **Home**, **Personal**, **Shared**, and **All**. These groups always exist and can't be removed or reordered, and **Home** always appears first. Custom groups you add can be reordered among themselves and always appear after **Home**. See [Navigating Omni](/content/navigate) for more information about the built-in pages. ## Requirements **Organization Admin** permissions are required to access and modify sidebar settings. ## Creating a custom sidebar An Omni organization can have one custom sidebar in use at a time. Customizing it starts from the [default sidebar](#default-sidebar): add custom groups and items, then reorder and relabel them to match your organization's needs. Your changes stay in a draft until you [save them](#save-discard). ### Adding groups Adding a group creates a custom group. Built-in groups (**Home**, **Personal**, **Shared**, and **All**) can't be added or removed. To add a new custom group: 1. In the sidebar, click **Settings > Sidebar**. 2. Click **+ Add group**. 3. Enter a display label for the group. 4. [Add items to the group](#add-item). ### Group titles and visibility Every group, built-in or custom, has an optional title. Once a group has a title, click the eye icon next to it to show or hide the group's header in the sidebar. By default, the **Personal** and **Shared** groups are titled "Personal" and "Shared," but their headers are hidden, so the default sidebar doesn't display any group headers. For the **Personal** and **Shared** groups, the title is also the name of the space. If you change the title, Omni uses the new name everywhere it refers to the space: the [Share dialog](/share), folder location chips, the activity feed, breadcrumbs, and [content search](/content/search). This applies whether or not the group's header is visible in the sidebar. ### Adding items to groups You can only add items to custom groups. Built-in groups already contain their full set of items and can't be added to. To add a new item to a custom group: 1. In the group, click to open the add menu. 2. Choose an item type: * **External link** - When prompted, specify a **Label** and **URL**, and whether the link should open in a new tab. * **Content** - When prompted, select the content from the content picker. When content that isn't shared with the organization is selected, a Some members badge will display next to the content item. Users that don't have access to the content won't see it in the sidebar. 3. **Optional.** Enter a display label for the item. Leave empty to use the default label. 4. **Optional.** Click the icon to the left of the item's display label to select a custom icon, or click **Remove icon** to restore its default. ### Reordering items and groups Built-in groups and their items can't be reordered or moved. Only custom groups and their items can be reordered: * Drag a custom group or one of its rows by its handle to reorder it. Items can be reordered within their existing custom group or moved to a different custom group. * You can also move a custom group by clicking its icon and selecting **Move up** or **Move down**. Custom groups always stay after the **Home** group. ### Editing items To update an existing item, click its icon. The options in this menu depend on the item type: * **Built-in** - If you customized the display label, select **Reset to defaults** to use the default label instead. This option is disabled if the item's display label hasn't been customized. * **External link** - Select **Edit link** to update the item's label, URL, or how it opens when clicked. * **Content** - Select **Edit** to change the content the item links to. If you specify a custom label for a built-in item, the label will be used everywhere else it appears in Omni. For example, the [Share dialog](/share), page titles, browser tabs, etc. ### Deleting items Built-in groups and their items can't be deleted. To delete a custom group or one of its items, click its icon and select **Delete**. Deleting a custom group also deletes all the items it contains. ## Saving and discarding changes Changes are held in a draft scoped to your browser session until you save them, so reloading the page doesn't lose your changes. When finished, click **Save** to apply the customized sidebar to your organization. To delete the changes and revert to the last saved sidebar, click **Discard**. ## Exporting a sidebar Exporting a sidebar copies a sidebar's JSON configuration to your clipboard. Click the icon near the top right corner of the page, then **Export**. ```json expandable theme={null} { "groups": [ { "id": "home", "items": [ { "builtinId": "home", "type": "builtin" }, { "builtinId": "chat", "type": "builtin" }, { "builtinId": "routines", "type": "builtin" }, { "builtinId": "skills", "type": "builtin" } ] }, { "id": "personal", "items": [ { "builtinId": "favorites", "type": "builtin" }, { "builtinId": "my-documents", "type": "builtin" }, { "builtinId": "activity", "type": "builtin" } ] }, { "id": "shared", "items": [ { "builtinId": "hub", "type": "builtin" }, { "builtinId": "shared-with-me", "type": "builtin" } ] }, { "id": "all", "items": [ { "builtinId": "all", "type": "builtin" }, { "builtinId": "trash", "type": "builtin" } ] } ], "version": 1 } ``` ## Importing a sidebar To import a sidebar: 1. Click the icon near the top right corner of the page. 2. Click **Import**. 3. Paste a sidebar [exported from this page](#export). 4. Click **Import.** 5. **Optional.** Change the layout in the editor if needed. 6. When finished, [save your changes](#save-discard). ## Next steps * [Organization settings](/administration/settings) # Application theme settings Source: https://docs.omni.co/administration/themes/application Configure application theme settings in Omni, including navigation colors, fonts, dark mode, branding, and theme import/export. **Organization Admin** permissions are required to access and modify application theme settings. Settings in the **Settings > Theme > Application** tab control the appearance of your Omni instance, including enabling light and dark mode. ## Customizing your theme **Want to speed things up?** Use the [Theme Lab](https://omni-theme.pages.dev/) to upload an image and generate a starting color palette for your theme. **This feature is experimental and may change.** Navigate to **Settings > Theme > Application tab**. Update the [available theme settings](#available-settings) to your liking. **Optional**: [Preview the theme](#previewing-the-theme) before saving. Click **Save** when finished. All changes will be immediately applied for internal and (if applicable) embed users. ## Importing and exporting theme configuration To export or import theme configurations, scroll to the bottom of the **Application** tab and click the menu. * **Export** downloads the current theme as an `application-theme.json` file. All theme properties are included; properties that have not been customized are exported as `null`. * **Import** opens a dialog where you can paste JSON or upload a `.json` file. You can also drag and drop a `.json` file directly onto the settings form. Properties not included in the imported file are reset to defaults. Changes are not saved automatically — click **Save** after importing. The JSON format uses `styles` for light mode and `stylesDark` for dark mode. The `assets` and `assetsDark` keys contain branding asset URLs. All keys are optional; missing keys default to empty. Color values must be CSS color strings or `null`, and asset URLs must be HTTPS URLs or `null`. ```json theme={null} { "styles": { "primary-color": "#271126" }, "stylesDark": { "primary-color": "#FFFFFF" }, "assets": { "logo": "https://example.com/logo.png", "wordmark": "https://example.com/wordmark.png" }, "assetsDark": { "logo": "https://example.com/logo-dark.png", "wordmark": "https://example.com/wordmark-dark.png" } } ``` ## Previewing the theme Click **Preview theme** to open a live side-by-side preview of your theme in light and dark mode before saving. The preview includes a mock sidebar, draft banner, primary button, and heading text with any custom fonts applied. ## Restoring factory defaults To reset all theme customizations to Omni defaults, click the menu and select **Restore factory defaults**. Click **Save** to persist the reset. ## Available settings ### Color scheme (light and dark mode) These settings control whether users see light mode, dark mode, or the system default, and whether they can override the instance-wide choice. | Setting | Description | | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | **Default color scheme** | Defines the default color scheme - **Default**, **Light**, or **Dark** - for the instance. Click **Change** to save the selection. | | **Allow user color scheme** | Allows users to select their preferred color scheme for the Omni instance. | ### Styles Each color property can be set independently for light and dark mode. If only one mode is customized, the other mode retains its default colors. #### Interactive colors Interactive colors affect primary buttons (such as **Run** and **Save**), outline and transparent buttons, draft and editing banners and indicators, branch bar styling, and notification badge dots. | Setting | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | **Action border** | Border color for outline and transparent buttons throughout the UI | | **Action text** | Text and icon color for outline and transparent buttons | | **Primary color** | Color for primary buttons and interactive elements (for example, **Run** and other action buttons) | | **On primary** | Text and icon color displayed on top of primary-colored elements | | **Editing color** | Color for draft and editing indicators, including the draft banner, edit mode buttons, and branch indicators. Defaults to the system draft color. | | **On editing** | Text color displayed on editing-colored elements, such as text on draft banners and tokens | | **Notification color** | Color for notification badges and indicator dots throughout the UI. Defaults to `#ff4794`. | #### Navigation colors Navigation colors affect the main [sidebar](/administration/settings/sidebar) and dialog navigation panels, such as the **Settings** sidebar. You can control the appearance of items in their default, hover, and selected states. Dialogs with navigation sidebars, like **Settings**, automatically respect your navigation color choices. | Setting | Description | | ------------------------- | ----------------------------------------------------------- | | **Background** | Navigation sidebar background color | | **Background (hover)** | Background color when hovering over navigation items | | **Background (selected)** | Background color for the currently selected navigation item | | **Text** | Default text color in the navigation sidebar | | **Text (hover)** | Text color when hovering over navigation items | | **Text (selected)** | Text color for the currently selected navigation item | | **Icon** | Default icon color in the navigation sidebar | | **Icon (hover)** | Icon color when hovering over navigation items | | **Icon (selected)** | Icon color for the currently selected navigation item | ### Branding assets Custom branding assets allow you to replace the default Omni logo and wordmark with your own brand assets throughout the Omni interface. Assets can be customized separately for light and dark modes, with automatic fallback when only one mode is configured. Custom branding asset images must be: * Specified using an HTTPS URL * In a web-compatible format such as PNG, SVG, JPG, etc. * Publicly accessible | Setting | Description | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Logo** | Square brand mark displayed in the header at 24×24px. Typically used for icons or compact logo designs. Appears in the navigation header across all page types. | | **Logo (dark mode)** | Alternative logo for dark mode. If not provided, the light mode logo will be used in dark mode. | | **Wordmark** | Horizontal brand text or logo displayed in the header at 100×24px. Best for text-based logos or wider brand marks. Appears alongside or instead of the logo in the header. | | **Wordmark (dark mode)** | Alternative wordmark for dark mode. If not provided, the light mode wordmark will be used in dark mode. | #### Using custom assets in embedded applications When custom branding assets are configured, they appear in application mode embeds where the default Omni branding is normally hidden. This allows you to maintain your brand presence in embedded analytics experiences. * If a custom logo is set, it replaces the menu icon in application mode embeds * Custom wordmarks are also displayed in embed contexts * Assets automatically adapt to the user's color scheme (light or dark mode) ### Fonts Currently, only publicly-accessible [WOFF2 formats](https://www.w3.org/TR/WOFF2/) are supported. | Setting | Description | | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | **Heading** | Font used for page titles, dialog titles, Markdown headings, and dashboard tile headings. Must be a valid URL to a publicly-accessible WOFF2 file. | | **Body** | Main font used throughout the application UI. Must be a valid URL to a publicly-accessible WOFF2 file. | ## Related * [Document theme settings](/administration/themes/documents) - Customize the look and feel of your Omni content # Document theme settings Source: https://docs.omni.co/administration/themes/documents Customize the look and feel of content in your Omni instance. **Organization Admin** permissions are required to access and modify document theme settings. The **Settings > Themes > Documents** tab lists the document themes in your Omni instance. ## Creating and editing themes Document themes are created and edited in published dashboards. See [Applying themes](/visualize-present/dashboards/theming) to learn how to create document themes. ## Setting, duplicating, and deleting themes You can interact with individual themes by using the (three dots icon) in individual rows. This menu allows you to: * Set and unset a default theme * Duplicate a theme * Delete a theme, which will unapply the theme from any documents currently using it ## Applying a default theme to documents To apply the default theme to documents and workbooks without a set theme, click the (three dots icon) at the top of the list of themes, then **Apply default theme to all documents**. # Application and document theme settings Source: https://docs.omni.co/administration/themes/index Manage application and document themes in Omni to customize branding, colors, fonts, and visual style across your organization. **Organization Admin** permissions are required to modify theme settings. The **Settings > Themes** page allows you to control the look and feel of your Omni instance, from the colors and fonts used throughout the application to the themes used in workbooks and dashboards. ## Application Application theme settings control the colors, fonts, and styling used across your Omni instance, including light and dark mode, navigation sidebar appearance, and interactive element colors. You can also import and export theme configurations as JSON. See [Application theme settings](/administration/themes/application) for more information. ## Document themes Document themes control the appearance of content within workbooks and dashboards, including default color palettes for visualizations. You can create multiple document themes and set a default that applies across your instance. See [Document theme settings](/administration/themes/documents) for more information. # User attributes Source: https://docs.omni.co/administration/users/attributes Utilize user-specific variables to create dynamic content and control data access. **Organization Admin** permissions are required to create and modify user attributes, including assigning them to users. User attributes allow you to map user-specific variables to Omni operations, such as querying, dashboarding, and data access. These attributes can be used in dashboard filters or workbooks or to filter embedded content. The user attributes settings page, showing a list of defined attributes. ## User attribute basics Yes. User attributes can be used in a few ways to control data access: * [**Access filters**](/modeling/topics/parameters/access-filters), which allow you to restrict the rows of data a user can access within a topic. Access filters apply the values assigned on a user attribute to the `WHERE` clause of every SQL query a user runs, filtering out to only the data designated to that user: ```yaml title="Filter by brand_name" theme={null} access_filters: - field: products.brand user_attribute: brand_name values_for_unfiltered: [all_brands] enable_sql_like_wildcards: true ``` * [**Access grants**](/modeling/models/access-grants), which define topic- and field-level permissions. Omni will map a user's attribute value to a corresponding allowed value and determine if the user has the necessary permissions to access that topic or field: ```yaml title="Grant access for user group" theme={null} access_grants: blob_sales_access: user_attribute: "omni_user_groups" allowed_values: ["Blob Sales"] access_boostable: false ``` * **Fields**. User attributes can be referenced in fields using Mustache syntax, for example: `{{ omni_attributes. }}`. This construct can be used to: * Provide conditional access to a field, or * To hash a field based on a user attribute. This can be done by using a `CASE` statement in the SQL definition for a field. For example, the following `name_hidden` and `name_hashed` examples demonstrate how to use user attributes to hide or hash a name field as an alternative to using access grants to remove access entirely: ```yaml title="Hide or hash field based on user attribute" theme={null} name: sql: ${users.full_name} name_hidden: sql: |+ CASE WHEN {{omni_attributes.see_names}} = 'true' THEN ${users.name} ELSE 'No Access' END name_hashed: sql: |+ CASE WHEN {{omni_attributes.see_names}} = 'true' THEN ${users.name} ELSE MD5(${users.name}) END ``` Yes. User attributes can be used to parameterize the connection queries run against while in an Omni branch. Refer to the [Dynamically switching database environments guide](/connect-data/dynamic-environments) for more information and setup steps. Yes. [Shared extension models](/modeling/develop/shared-extensions) use user attributes to route users to the correct model extension. You define a mapping in the parent model's `dynamic_shared_extensions` parameter that links user attribute values to specific extensions. Yes. There are a few ways to do this: * **Dashboard Markdown tiles**. You can use user attributes in dashboard Markdown tiles with [Mustache syntax](/visualize-present/mustache-reference). For example, `{{metadata.userAttributes..values}}` would return the value of the specified user attribute. * **Dashboard deliveries**. User attributes can be used to [personalize deliveries](/share/deliveries/dynamic-content), including messages (where supported) and the data included in the delivery. Yes. The steps for [assigning a user attribute](#assigning-attributes-to-users) are the same regardless of user type. To view [email-only users](/administration/users/email-only) when working with a specific attribute, click the **Email Only** toggle in the attribute's **Users** tab: The Email Only toggle highlighted in the Users tab of a user attribute. Yes. Refer to the [Default system attributes section](#default-system-user-attributes) for more information. ## Creating user attributes To define a new user attribute, navigate to **Settings > Attributes** and click the **New Attribute** button. Each user attribute has the following settings: * **Name**: The name of the user attribute, how it will be displayed in the UI * **Reference**: How the attribute will be referenced in code, such as in the model * **Type**: Used to check that valid values are assigned to users. String and Number data types are allowed. * **Multiple values**: Specifies whether multiple values can be assigned to a user for this attribute * **Description**: Explanation of the attribute or how it will be used * **Default value**: **Optional**. Set a default value that all users will inherit if a value is not directly assigned to them. **Do not set a default value for attributes used in access filters or access grants.** Omni assigns the default value to all users immediately upon account creation. If the default value matches a [`values_for_unfiltered`](/modeling/topics/parameters/access-filters#properties) value, those users will receive unfiltered data. Leave the default blank to get fail-closed behavior: users without an assigned value receive an error or no rows, which is visible and fixable. If you use `values_for_unfiltered`, do not set its value as the attribute default. The new user attribute form with fields for name, reference, type, multiple values, description, and default value. ## Assigning attributes to users The steps in this section apply to all user types, including [email-only](/administration/users/email-only) and [embed](/embed). After defining a user attribute, you can assign values to individual users. Navigate to **Settings > Attributes**. Click the attribute you want to set. In the attribute's page, click the **Users** tab. In the list of users, locate the user you want to work with. Use the toggles above the table to filter the list by: | Filter | Description | Default | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | | **User type** | Filters users by type:
  • **Org users** - Show only standard users that can log into Omni
  • **Email only** - Show only email only users
  • **Embed Users** - Show only embed users
  • **All** - Show all users, regardless of type
| Org users | | **Value** | Filters users by their assigned attribute value. Click the control to display condition settings:
  • **any** - Show all users, regardless of value
  • **contains** - Show users whose value contains the text you enter
  • **is empty** - Show users with no assigned value
  • **is not empty** - Show users with any assigned value
| Any | | **Source** | Filters users by the source of their assigned attribute value:
  • **Any source** - Show all users, regardless of source
  • **User setting** - Show users with non-default attribute values
  • **Default setting** - Show users with default attribute values
| Any source |
Click the **Edit value** button in user's row. In the dialog that displays, enter the value for the user. Click **Save**.
After updating, the **Source** field will show whether the value is the default value (`-`) or if it was set specifically for the user (`User setting`). ## Default system user attributes System attributes are read-only. Omni's default user attributes will be marked with a **System** badge in the **Settings > Attributes** page. A special virtual attribute that allows Organization Admins to set an organization-wide default AI credit limit for users. Unlike regular user attributes that assign individual values per user, this virtual attribute sets a default that applies to all users that don't have set [individual credit limits](/ai/settings/usage#individual-user-limit). By default, users have unlimited AI credits. To set this for an embed user with URL parameters, use the [embed `userAttributes` parameter](/embed/setup/url-parameters/userAttributes). Click this attribute in **Settings > Attributes** to open the configuration page for the attribute. See [Managing AI credit usage](/ai/settings/usage) for full details on configuring per-user credit limits. If `true`, the user can create, save, or move content in their [personal **My documents** folder](/content/navigate). When `false`, **My documents** is hidden in the [sidebar](/administration/settings/sidebar) and content operations default to the organization scope. Controlled with the **Personal content access** setting in each [user's settings page](/administration/users/settings#personal-content). If `true`, the split-view AI chat panel opens on the right side of the screen with the document or dashboard on the left. When `false`, the chat panel opens on the left. Use this attribute to set the behavior for embed users or a default for your users. Individual users can update their preference with the **Chat panel on the right** setting in their [account settings](/administration/users/your-account#chat-panel-side). If `true`, the user is an **Organization Admin**. The user's email address. The user's embedded entity name. For example, `Blobs R Us` The [user groups](/administration/users/groups) that the user is a member of. The value will be a comma-separated list of user group names, for example `Blob Sales, Blob Marketing` A unique identifier for the user. For example, `91abbe19-b0de-4537-bc62-cec1d95420c9` The user's locale code. Possible values are: | Locale code | Language | | ----------- | ----------------------------- | | `en-US` | English (default) | | `ar-SA` | العربية (السعودية) (Arabic) | | `de-DE` | Deutsch (Deutschland) | | `es-CL` | Español (Chile) | | `es-ES` | Español (España) | | `fr-FR` | Français (France) | | `he-IL` | עברית (ישראל) | | `it-IT` | Italiano (Italia) | | `ja-JP` | 日本語 (日本) | | `ko-KR` | 한국어 (대한민국) (Korean) | | `nb-NO` | Norsk bokmål (Norge) | | `pt-BR` | Português (Brasil) | | `pt-PT` | Português (Portugal) | | `sv-SE` | Svenska (Sverige) | | `th-TH` | ไทย (ประเทศไทย) (Thai) | | `vi-VN` | Tiếng Việt (Việt Nam) | | `zh-CN` | 中文 (中国) (Simplified Chinese ) | See the [Localization guide](/administration/localization) for more information. The user's name. For example, `Blob Ross` or `Blobby Parton` The user's timezone, which is set using the **Query timezone** setting on the user's profile. For example, `UTC` or `America/Los_Angeles` # Defining custom model roles Source: https://docs.omni.co/administration/users/custom-roles Define custom roles with specific permission restrictions that can be assigned to users, groups, and connections. **Organization Admin** permissions are required to manage custom model roles. Custom roles allow organizations to define variations of existing base roles, such as **Viewer No Download** or **Querier No CSV Upload**. These custom roles inherit the core capabilities of a base role while enabling restrictions on specific granular permissions. This structure avoids the need to create entirely new base role tiers for minor capability adjustments. ## Custom role basics Omni organizes permissions into a hierarchy of role tiers, where each tier builds on the one below it: | Tier | Core capability | | ---------------------- | ------------------------------------------------- | | **No Access** | No access to the organization | | **Viewer** | View content | | **Restricted Querier** | Create topic-based queries | | **Querier** | Create all views and fields queries and write SQL | | **Modeler** | Edit the shared data model | | **Connection Admin** | Manage connections and model permissions | Each tier includes all the capabilities of the tiers below it. Custom roles are variations within a tier — they inherit the tier's core capability but can restrict specific granular permissions. See the [Permissions reference](/administration/users/permissions-reference) for more information on the specific abilities each tier has. Granular permissions are optional capabilities within a role tier that can be individually enabled or disabled. These are what custom roles customize. Some granular permissions are nested under a parent permission in the UI — for example, **Upload data** falls under **Use workbooks**. See [Creating custom roles](#creating-custom-roles) for details on how parent and child permissions work. A custom role keeps the tier's core capability but can restrict any combination of these granular permissions. For example, a **Querier No Upload** role has full **Querier** capabilities but with the **Upload data** permission disabled. See the [Granular permissions reference](#permissions-reference) for a full list of available permissions. **Organization Admin** users can create, edit, and delete custom roles. Custom roles can be: * Assigned to [users](/administration/users) * Assigned to [user groups](/administration/users/groups) * Set as the **Base access** on a connection When a user or group has multiple roles assigned, Omni uses role priority to determine which role takes effect. The higher-priority role wins. * **Across tiers** - Higher base role tiers (e.g., **Modeler**) always take precedence over lower tiers (e.g., **Viewer**), regardless of custom role priority. * **Within a tier** - Priority is determined by the order roles appear in the list, starting from the top. For example, in the screenshot below, the base **Querier** role has the highest priority because it appears first: Roles list showing the Querier tier with the base Querier role above the custom Querier No Upload role You can change the priority of roles within a tier by clicking the icon on a role and dragging it to re-order the list. Role tiers cannot be reordered, only the roles defined in the tier itself. Yes - custom roles with a **resolved role** of **Restricted Querier** or **Viewer** may be used in [embedded contexts](/embed). Use the role's **name** when passing the custom role using [`connectionRoles`](/embed/setup/url-parameters/connectionRoles) and [`modelRoles`](/embed/setup/url-parameters/modelRoles), for example: ```json title="Example modelRoles object with custom role" highlight={3} theme={null} { "model-id-1":"RESTRICTED_QUERIER", "model-id-2":"VIEWER_NO_DOWNLOAD" } ``` ## Creating custom roles 1. Navigate to **Settings > Roles**. 2. Click **+ Create custom role**. 3. Fill in the following: * **Name** - **Required**. Enter a unique name for the custom role, such as `querier_no_upload`. Names can only contain letters, numbers, underscores, and hyphens. * **Display Name** - **Required**. Enter a human-readable display name for the role. This is shown in the UI. * **Description** - Enter a description of the custom role. This will display in the **Description** column on the **Roles** page. Next, choose the granular permissions you want the custom role to have. Permissions are hierarchical at two levels: * **Across role tiers** - Each role tier builds on the tiers below it. To grant a permission from a higher tier, the base permission for each lower tier must also be selected. For example, to grant **Create all views and fields queries and write SQL** (Querier), you must also select **Create topic based queries** (Restricted Querier): Permissions panel showing the Restricted Querier and Querier base permissions both selected * **Within a role tier** - Some permissions are nested under a parent permission. The parent must be selected before you can grant any of its children, but you can deselect individual child permissions. For example, **Create spreadsheets** requires **Use workbooks** to be selected, but you can deselect **Upload data** independently: Restricted Querier tier showing Use workbooks and Create spreadsheets selected, with Upload data deselected As you select and deselect permissions, the **Resolved Role** and **Exceptions** sections on the left side will update: New Role dialog showing selected permissions on the right, with Resolved Role showing Querier and Exceptions listing Upload data and Use Omni Agent as disabled The **Resolved Role** shows the base role tier that your custom role maps to based on the permissions you've selected, which determines how the role is treated for [licensing](/administration/users/permissions#license-types). The **Exceptions** section lists any permissions that are different when compared to the base version of that role tier. Click **Save** when finished to create the role. Once created, the role will display in the **Roles** page within its resolved role tier, along with any restrictions and the date it was created: Roles list showing the Querier tier with the base Querier role and the custom Querier No Upload role with a No data uploads restriction ## Changing role priority in a role tier Priority is determined by the order roles appear in the list, starting from the top. For example, in the screenshot below, the base **Querier** role has the highest priority because it appears first: Roles list showing the Querier tier with the base Querier role listed above the custom Querier No Upload role You can change the priority of roles within a tier by clicking the icon on a role and dragging it to re-order the list. Role tiers cannot be reordered, but the base role within the tier can be moved. For example, the **Querier** role in the above screenshot could be moved, but the **Querier** tier that contains the **Querier** and **Querier No Download** roles can't. ## Editing custom roles Base roles - **Viewer**, **Restricted Querier**, **Querier**, **Modeler**, and **Connection Admin** - can't be edited. 1. Navigate to **Settings > Roles**. 2. Click the icon in the same row as the custom role and select **Edit**. 3. Make your changes. 4. Click **Save** when finished. ## Duplicating custom roles 1. Navigate to **Settings > Roles**. 2. Click the icon in the same row as the custom role and select **Duplicate**. 3. Give the role a name and choose the permissions it should have. 4. Click **Save** when finished. ## Deleting custom roles Base roles - **Viewer**, **Restricted Querier**, **Querier**, **Modeler**, and **Connection Admin** - can't be deleted. Deleting a custom role reassigns all affected users and groups to the tier's base role. For example, deleting a custom role that resolves to **Querier** will revert all assignees to the **Querier** base role. 1. Navigate to **Settings > Roles**. 2. Click the icon in the same row as the custom role and select **Delete**. 3. When prompted, click **Delete**. ## Assigning custom roles Custom roles can be assigned: * **As the [Base Access](/administration/users/permissions#defining-permissions-for-a-connection)** level for a connection * **To individual users** in the user's [**Model Access**](/administration/users/settings#model-access) tab * **To [user groups](/administration/users/groups#model-access)** in a connection's **Permissions > Connection Roles** section ## Granular permissions reference
Role Permission Required permissions
**Viewer** **Run topic-based queries** Cannot be disabled
**Download** Run topic-based queries
**Schedule / Alerts** Run topic-based queries
**Restricted Querier** **Create topic-based queries** Run topic-based queries (Viewer)
**Use Omni Agent**
  • Run topic-based queries (Viewer)
  • Create topic-based queries
**View IDE**
  • Run topic-based queries (Viewer)
  • Create topic-based queries
**View SQL**
  • Run topic-based queries (Viewer)
  • Create topic-based queries
**Use workbooks**
  • Run topic-based queries (Viewer)
  • Create topic-based queries
**Upload data**
  • Run topic-based queries (Viewer)
  • Create topic-based queries
  • Use workbooks
**Create spreadsheets**
  • Run topic-based queries (Viewer)
  • Create topic-based queries
  • Use workbooks
[**Create apps**](/visualize-present/apps)
  • Run topic-based queries (Viewer)
  • Create topic-based queries
  • Use workbooks
**Querier** **Create all views and fields queries and write SQL**
  • Run topic-based queries (Viewer)
  • Create topic-based queries (Restricted Querier)
  • View SQL
**Modeler** **Edit shared data model**
  • Run topic-based queries (Viewer)
  • Create topic-based queries (Restricted Querier)
  • View SQL (Restricted Querier)
  • Create all views and fields queries and write SQL (Querier)
**Connection Admin** **Manage connections and model permissions**
  • Run topic-based queries (Viewer)
  • Create topic-based queries (Restricted Querier)
  • View SQL (Restricted Querier)
  • Create all views and fields queries and write SQL (Querier)
  • Edit shared data model (Modeler)
## Next steps * [User groups](/administration/users/groups) - Assign custom roles to groups of users * [Permissions](/administration/users/permissions) - Understand the full permissions model * [Content sharing](/share) - Learn how content access works alongside connection roles # Revoking user memberships Source: https://docs.omni.co/administration/users/delete Learn how to permanently revoke a user's membership in Omni, including what happens to their content and deliveries. Revoking user memberships is **not reversible**. Read this guide carefully before revoking a user's membership. When a user's membership to your Omni instance is revoked, the following will occur: * **Schedules created by the user will be deleted**. Unless transferred, the schedules must be re-created by another user to continue. * [**Content in the user's Personal folder**](/content/navigate) will be accessible to **Organization Admins** through search. Content outside of the user's Personal folder will not move. * [API Keys](https://docs.omni.co/api/authentication) * [PATs](https://docs.omni.co/api/authentication#token-types) will be disabled. * [Organization API keys](https://docs.omni.co/api/authentication#organization-api-keys) will remain active. Requests to endpoints which require context about the user taking action may fail if the user is revoked. Even if the user is re-added to your Omni instance with the same name and email, their previous history, permissions, content, etc. will not be associated with them. It will be as if they are a brand new user. ## Preparation checklist Before you revoke a user's membership, complete the following: Prior to being revoked, **Organization Admins** can impersonate the user to directly access this folder and move its content. You can also use the [**Analytics dashboard**](/administration/analytics) to identify the content the user owns, including documents in their personal folder. To find the schedules created by the user, navigate to **Settings > Deliveries** and apply a filter for the user. You can navigate to the documents from this page and re-create the schedules to prevent disruptions. Alternatively, you can use the [transfer ownership API](/api/schedules/transfer-schedule-ownership) to programmatically transfer ownership. After the user is removed, **Organization Admins** will still be able to find and access the user's **Personal** content using search or the [**Analytics dashboard**](/administration/analytics). The **Settings > Deliveries** page will also list the user's schedules, but they will need to be re-created in order to run. # Email-only users Source: https://docs.omni.co/administration/users/email-only Learn how email-only users work in Omni, including how they're created, managed, and used with deliveries and embedded analytics. **Organization Admin** permissions are required to manage email-only users. An email-only user is a delivery recipient who doesn't have an Omni account. Unlike [Standard or Embed users](/administration/users), email-only users can't log in to Omni — they only receive scheduled [email deliveries](/share/deliveries/email). ## Creating email-only users Omni automatically creates an email-only user when an [email delivery](/share/deliveries/email) recipient has an email that can't be matched to an existing Omni user. When the delivery is saved, Omni creates an account for the recipient to track delivery usage and related metadata. See [Resolving delivery recipients by email](/share/deliveries/email/personalization#resolve-recipients) for more information. Email-only users can also be created programmatically using the [manage email-only user API](/api/schedule-recipients/manage-email-only-user) or the [bulk manage API](/api/schedule-recipients/bulk-manage-email-only-users). After a new email-only user is created, you should immediately set [values for their user attributes](#user-attributes). Email-only users aren't counted toward any [licenses](/administration/users/permissions#license-types). ## Accessing email-only users in Omni To view and manage email-only users, click **Settings > Users** and select the **Email-Only** tab. This tab only appears if there is at least one email-only user in your organization. The Email-Only tab in the Users settings page, displaying a list of email-only users with their names and schedule counts. The tab displays each user's **Name** and the number of **Schedules** they are included in. ## Inviting email-only users to your organization Email-only users can be invited to join your organization as a [Standard user](/administration/users/invite). The user's attributes will be retained, and they'll remain recipients of schedules. 1. In the **Settings > Users > Email-only tab**, locate the user you want to work with. 2. Click the in the same row as the user. 3. Click **Invite to Standard User**. Omni will move the user to the **Standard** tab and display an Invited badge next to their display name. ## Deleting email-only users **Heads up!** Deleting an email-only user removes their email from all deliveries where they are a recipient. 1. In the **Settings > Users > Email-only tab**, locate the user you want to work with. 2. Click the in the same row as the user. 3. Click **Remove Scheduler User**. ## Assigning user attributes Email-only users can be assigned [user attributes](/administration/users/attributes) like any other user type. These attributes personalize the content they receive from [email deliveries](/share/deliveries/email). For example, you could assign a `region` attribute to each email-only user and deliver a dashboard that filters to only their region's data. The steps to assign attributes to email-only users are the same as for any other user. See [Assigning attributes to users](/administration/users/attributes#assigning-attributes-to-users) for more information. Use the [manage email-only user API](/api/schedule-recipients/manage-email-only-user) or [bulk manage API](/api/schedule-recipients/bulk-manage-email-only-users) to assign attributes to email-only users. **Make sure you set user attribute values for email-only users before their deliveries run!** If user attributes have default values, email-only users will inherit the defaults if values are not explicitly set. This can result in errors or no rows being returned. For attributes used in access filters, it can also expose unfiltered data in deliveries where they're a recipient. ## Next steps * Learn more about [personalizing email deliveries with recipient attributes](/share/deliveries/email/personalization) * See what's possible with [user attributes](/administration/users/attributes) * Set up [email deliveries](/share/deliveries/email) # User groups Source: https://docs.omni.co/administration/users/groups Assign permissions to users in bulk with user groups. **Organization Admin** permissions are required to manage user groups. User groups let you manage permissions for multiple users at once instead of configuring each user individually. Groups page showing a list of user groups with their name, label, member count, and group ID ## Creating user groups User groups can also be created through some [SCIM integrations](/administration/authentication). 1. Navigate to **Settings > Groups**. 2. Click **New Group**. 3. Enter a **Name** for the group. You can also add a description. 4. Click **Save** to create the group. After the group is created, you'll be redirected to the group's **Members** tab where you can [add users](#adding-users-to-groups). Use the [Create user group API](/api/user-groups/create-user-group) API to programmatically create a user group: ```http theme={null} curl --request POST \ --url https://{your-omni-org}.omniapp.co/api/scim/v2/groups \ --header 'Authorization: Bearer {token}' \ --header 'Content-Type: application/json' \ --data ' { "displayName": "Blob Sales", "members": [ { "value": "9e8719d9-276a-4964-9395-a493189a247c" } ] } ' ``` ## Managing group members Users can be added to and removed from groups manually, through the [API](/api/user-groups) or some [SCIM integrations](/administration/authentication). ### Adding users to groups A user's group membership is also available as the `omni_user_groups` [user attribute](/administration/users/attributes#default-system-user-attributes), which can be used for data-level permissioning. You can add users to groups from the group's **Members** tab or directly from a [user's **Groups** tab](#user-profile-group). From a group's **Members tab**: 1. Navigate to **Settings > Groups**. 2. Click the group you want to work with. 3. In the group's **Members** tab, click **Add Members**. 4. Search for and select users in the modal, then click **Add**. Use the [Update user group](/api/user-groups/update-user-group) API to programmatically add users to a user group: ```http theme={null} curl --request PATCH \ --url https://{your-omni-org}.omniapp.co/api/scim/v2/groups/{userGroupId} \ --header 'Authorization: Bearer {token}' \ --header 'Content-Type: application/json' \ --data ' { "schemas": [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ], "Operations": [ { "op": "add", "path": "members", "value": [ { "display": "blob.ross@blobsrus.co", "value": "9e8719d9-276a-4964-9395-a493189a247c" } ] } ] } ' ``` ### Removing users from groups When a user is removed from a group, they lose any [permissions that were granted through that group](#assigning-permissions-to-groups). Users can be re-added as group members if needed. You can remove users from groups from the group's **Members** tab or directly from a [user's **Groups** tab](#user-profile-group). From a group's **Members tab**: 1. Navigate to **Settings > Groups**. 2. Click the group you want to work with. 3. In the group's **Members** tab, locate the user you want to remove. 4. Click **Remove from group**. Use the [Update user group API](/api/user-groups/update-user-group) to programmatically remove a user from a group: ```http theme={null} curl --request PATCH \ --url https://docs.omniapp.co/api/scim/v2/groups/{userGroupId} \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data ' { "schemas": [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ], "Operations": [ { "op": "remove", "path": "members[value eq \"9e8719d9-276a-4964-9395-a493189a247c\"]" } ] } ' ``` ### Managing a user's groups from their settings In addition to managing user memberships from the group's **Members** tab, you can view and modify an individual user's group memberships from their [user settings](/administration/users/settings). This is particularly useful when managing a user who is not yet a member of any groups, or when you need to modify multiple group memberships for a single user. ## Assigning permissions to groups Access to connections, models, and content can be granted to an entire user group at once. ### Assigning connection/model access Model roles control what actions user group members can perform on connections and the individual models associated with those connections. 1. Navigate to **Settings > Connections** and open the connection you want to work with. 2. Click the **Permissions** tab and scroll to **Connection Roles**. 3. In the **Groups** view, locate the group you want to grant permissions to. 4. Use the **Access** dropdown to change the group's role. If [custom roles](/administration/users/custom-roles) are defined, they will display as options in the dropdown. Connection Roles section showing groups listed with their model, access level dropdown, and member count Use the [Assign or update user group model role API](/api/user-group-model-roles/assign-or-update-user-group-model-role) to programmatically assign model roles to user groups. The role will apply to all members of the group. ```https theme={null} curl --request POST \ --url https://blobsrus.omniapp.co/api/v1/user-groups/{userGroupId}/model-roles \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data ' { "connectionId": "bc1f9c9f-208d-48a2-9ae3-ff80f2c79fed", "modelId": "7d3e4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a", "roleName": "QUERIER" } ' ``` ### Assigning content access To grant access to documents and folders, share the content with the group. See [Content sharing](/share#users-and-user-groups) for details. ## Deleting user groups Deleting a user group is not reversible. Group members will lose any connection roles and content access that were granted through the group. 1. Navigate to **Settings > Groups**. 2. Click the icon in the user group's row. 3. When prompted, click **Yes, Delete** to confirm. You can also delete a group by opening its **Settings** tab and clicking the **Delete** button. Use the [Delete user group API](/api/user-groups/delete-user-group) to programmatically delete a user group: ```http theme={null} curl --request DELETE \ --url https://{your-omni-org}>.omniapp.co/api/scim/v2/groups/{userGroupId} \ --header 'Authorization: Bearer {token}' ``` ## Next steps * [Custom roles](/administration/users/custom-roles) - Define custom role variations to assign to groups * [Content sharing](/share) - Learn how to share documents and folders with users and groups * [Permissions](/administration/users/permissions) - Understand how connection roles and permissions work # Testing access grants and permissions with user impersonation Source: https://docs.omni.co/administration/users/impersonate Use Omni's impersonation feature to view the application as another user and verify that access grants and permissions work correctly. **Organization Admin** permissions are required to impersonate other users. Admins can't impersonate other admins. The **Impersonate user** feature is useful for testing that access grants work as expected. ## Impersonating users Navigate to **Settings > Users** and click on a user. **Note**: If testing an [access grant](/modeling/develop/data-access-control), the user must have a [user attribute value](/administration/users/attributes) that excludes them from the grant. At the bottom of the user's details page, click **Impersonate user**. Create a new workbook based on the connection you want to test. In this environment, you can verify what the user would and wouldn't have access to and adjust their permissions accordingly. ## Impersonating a pending invite Only **pending** invites can be impersonated. Expired, declined, or revoked invitations are not eligible for impersonation. You can impersonate a user who has been invited but hasn't yet accepted their invite. This is useful for checking their permissions and validating dashboards before the user logs in for the first time. If you create content - such as folders or saved documents - while impersonating a pending invite, that content will be owned by the invited user. If the user later declines the invite or the invite expires without being accepted, the content will be owned by a non-member, similar to what happens when a user is revoked. When impersonating a pending invite, the impersonation banner displays a note indicating that the invite is still pending. ## Impersonate vs View As Omni provides two ways to test content as another user: * **Impersonate user** provides a full-session simulation where you experience Omni exactly as that user would. This includes all role-based restrictions, connection access controls, and permissions. Access it from **Settings > Users** by clicking on a user and selecting **Impersonate user** at the bottom of their details page. * **[View As](/visualize-present/dashboards/view-as)** is a quick preview mode available in dashboard and workbook **File** menus. It applies the selected user's attributes to resolve dashboards, filters, and access grants, but does not simulate role-based restrictions or connection access. Use this for quick user attribute testing without leaving your current context. Use **Impersonate** for comprehensive testing that includes role-based restrictions and connection access. Use **View As** for quick user attribute testing. # Managing users Source: https://docs.omni.co/administration/users/index Invite, monitor, and manage users in your Omni organization. ## Requirements **Organization Admin** permissions are required to view and manage users. ## The user list The user list (**Settings > Users**) is the central hub for managing the people in your Omni organization. From here, you can invite new users, monitor login activity, and access individual user settings. The user list is organized into tabs for different user types and statuses: | **Tab** | **Description** | | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Standard** | Standard users in your organization. | | **Embed** | Users accessing Omni through an [embedded instance](/embed). | | **Email-Only** | Users added to at least one [email delivery](/share/deliveries/email) who don't have an Omni account. See [Email-only users](/administration/users/email-only). | | **Omni Support** | Omni support team members with access to your instance. | | **Expired Invitations** | Invitations that were not accepted within the expiration window. | | **Invite Requests** | Pending requests from users who have requested access through the login page. | ### Standard and Embed users The **Standard** and **Embed** tabs display the following columns: | **Column** | **Description** | | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Name** | The user's full name. | | **Email** | The user's email address. | | **Status** | The user's current status: **Active**, **Invited**, or **Suspended**. | | **Last login** | When the user last logged in, displayed as relative time (for example, "2 days ago"). Shows "Never" for users who haven't logged in. This column provides a quick way to monitor user engagement without navigating to the [Analytics dashboard](/administration/analytics), which offers more detailed activity tracking. | ### Email-only users The **Email-Only** tab lists users who receive [email deliveries](/share/deliveries/email) but don't have an Omni account. Refer to [Email-only users](/administration/users/email-only) for details on how these users are created and managed. **Note**: Email-only users aren't counted towards any [licenses](/administration/users/permissions#license-types). ## Managing individual users To access the settings for a specific **Standard** or **Embed** user, hover over them in the user list and click the **Manage** button that appears. On the user's profile page, you can: * Assign an [organization role](/administration/users/settings#organization-role) and [model access](/administration/users/settings#model-access) * Set the user's [locale](/administration/users/settings#locale) and [query timezone](/administration/users/settings#query-timezone) * Configure [user attributes](/administration/users/attributes) for data access control * [Impersonate the user](/administration/users/settings#impersonating-a-user) to test their data access * Set [AI credit limits](/administration/users/settings#ai-credit-limit) to control per-user AI usage Refer to [User settings & impersonation](/administration/users/settings) for details. ## User management tasks Send invitations, manage requests, and re-invite users with expired invitations. Control access to connections and content with connection roles and model permissions. Create variations of base roles with specific permission restrictions for users, groups, and connections. Create groups to manage permissions and content access at scale. Map user-specific variables to control data access, route connections, and personalize content. Experience a full session as another user to test all permissions and role-based restrictions. Remove a user from your organization and understand the impact on their content and schedules. Track user activity, content engagement, and more with the Analytics dashboard. # Inviting users Source: https://docs.omni.co/administration/users/invite Send invitations, manage invitation requests, and re-invite users with expired invitations. ## Requirements **Organization Admin** permissions are required to invite users. ## User invitation requests If the [**New user invitations**](/administration/settings#general) setting is enabled, users can request an invitation from your organization's login page. ### Stale invitation requests If you see invitation requests from users who are already active members of your organization, you can safely dismiss these requests. These stale requests can occur when a user submits an invitation request and then joins the organization through SSO or SCIM provisioning before an Organization Admin acts on the request. To dismiss a stale invitation request: 1. Navigate to **Settings > Users**. 2. Click the **Invitation requests** tab. 3. Find the request from the user who is already a member. 4. Click **Dismiss** next to the request. If you attempt to invite a user who is already an active member, you'll receive an error indicating the user already exists in the organization. ## Inviting users Once an invite is sent, new users have 7 days to log into Omni. The invite will automatically expire after this time and the user will have to be [re-invited](#re-inviting-users). If the **New user invitations** setting isn't enabled or you need to send a one-off invite, you can manually invite new users. 1. Navigate to **Settings > Users**. 2. Click **Invite**. 3. In the **Email** field, add the emails of the users you want to invite as a comma-separated list. For example: ```txt theme={null} blobby@blobsrus.com,blob.ross@blobsrus.com ``` 4. Click **Send invitations**. After the invitation is sent, the user will appear in the **Users** list with an **Invited** badge and you'll be able to [assign permissions](/administration/users/settings) to the user: ## Re-inviting users If a user hasn’t accepted their invitation by logging in to Omni or needs a new one, you can revoke and re-send their invite: 1. Navigate to **Settings > Users**. 2. In the **Users** list, find the user with the **Invited** badge. 3. Click **Manage** next to their name. 4. At the bottom of the user's profile page, click **Revoke invitation**. 5. Return to **Settings > Users** and click **Invite**. 6. In the **Email** field, add the user's email address. 7. Click **Send invitations**. The user will receive a new invite email and appear in the **Users** list with a refreshed **Invited** badge. # Managing data access with connection permissions Source: https://docs.omni.co/administration/users/permissions Assign and test database connection, data model, and content-level permissions to control user access across your Omni instance.as asd as das dw User permissions are first set on the individual database connection then more fine-tuned permissions can be assigned to individual users or groups within the organization, streamlining the management process. ## Connection permission basics **Organization Admins** and users who have **Connection Admin** permissions for a connection can define connection permissions. Omni has six base connection roles, ordered from the **least** permissive to the **most** permissive: * No access * Viewer * Restricted Querier * Querier * Modeler * Connection Admin Organizations can also create [custom roles](/administration/users/custom-roles) that inherit a base role's core capabilities while restricting specific granular permissions, such as a **Querier** role without the **Upload data** permission. For the specifics of what each base role can and cannot do, refer to the [Permissions reference](/administration/users/permissions-reference). Yes. Using the **Base access** setting, you can assign the minimum role users will have for the models in the connection. More permissive roles can be set in the connection's **Model access** section. **Note**: The base role will override a less permissive role set in the **Model access** section. Yes! In the **Model access** section, you can assign granular permissions to users and user groups for specific models. A connection's **base role** will override a less permissive role set in the **Model access** section. It depends on what you want to achieve! Do you want to lock everything down, or only restrict access for some things? Or perhaps it varies by team or dataset? In the [**Common permissions scenarios guide**](/administration/users/permissions-scenarios), we've outlined some common scenarios and how to use permissions to achieve the desired result. For example, limiting access to folders based on the team a user belongs to. Yes. Refer to the [User license types](#license-types) section for more information. ## Defining permissions for a connection **Organization Admin** or **Connection Admin** permissions for the connection are required to define connection permissions. To access the connection's **Permissions** tab: 1. Click **Settings > Connections**. 2. Click the connection. 3. Click the connection's **Permissions** tab. On this page, you can define default access for the connection (**Base access role**) and assign permissions to users and user groups for specific models (**Model access**). If [custom roles](/administration/users/custom-roles) are defined, they will be included as options in these sections. **Not sure what permissions to set?** Check out the [Common permissions scenarios guide](/administration/users/permissions-scenarios) to learn what permissions to set in specific scenarios, such as restricting access to datasets based on team. ## Testing data access As you assign connection roles to users, you can [impersonate them](/administration/users/impersonate) to test what users can see. This can be helpful in preemptively surfacing access warnings, which will display when users attempt to access specific types of content. See the [Access warnings](/share#access-warnings) guide to learn what an access warning is and how to resolve it. ## License types Omni's licensing structure has three tiers: Viewer, Standard, and Administrator/Developer. To calculate a user's license type, Omni looks at: * The user's **highest Connection role** across all connections, **and** * Whether the user is an **Organization Administrator**. These users will have an **Administrator** license by default. The following table shows how license types match to connection roles. Refer to the [Permissions reference](/administration/users/permissions-reference) for more information about what individual connection roles can do in Omni. | License type | Connection role | Permissions | | ------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **None** | **No Access** | ❌ Cannot view content built on the connection
❌ Cannot query (topics)
❌ Cannot use SQL queries
❌ Cannot modify shared model files
❌ Cannot modify connection settings | | **Viewer** | **Viewer** | ✅ Can view dashboards built on topics
❌ Cannot query topics
❌ Cannot use SQL queries
❌ Cannot modify shared model files
❌ Cannot modify connection settings | | **Standard** | **Restricted Querier** | ✅ Can create, edit, and view workbooks and dashboards
✅ Can query topics (UI and AI)
❌ Cannot use SQL queries
❌ Cannot modify shared model files
❌ Cannot modify connection settings | | **Standard** | **Querier** | ✅ Can create, edit, and view workbooks and dashboard
✅ Can query topics (UI and AI)
✅ Can use SQL queries
❌ Cannot modify shared model files
❌ Cannot modify connection settings | | **Admin/Developer** | **Modeler** | ✅ Can create, edit, and view workbooks and dashboards
✅ Can query topics (UI and AI)
✅ Can use SQL queries
✅ Can modify shared model files
❌ Cannot modify connection settings | | **Admin/Developer** | **Connection Admin** | ✅ Can create, edit, and view workbooks and dashboards
✅ Can query topics (UI and AI)
✅ Can use SQL queries
✅ Can modify shared model files
✅ Can modify connection settings | ## Custom roles Custom roles allow organizations to create variations of base roles with specific permission restrictions — for example, a **Querier** role without the **Upload data** permission. Custom roles can be assigned to users, groups, and as the base access on a connection. For details on creating and managing custom roles, see [Custom roles](/administration/users/custom-roles). # Connection and model permissions reference Source: https://docs.omni.co/administration/users/permissions-reference A detailed reference of all connection and model role permissions in Omni, covering document, query, and modeling capabilities. Refer to the [Assigning permissions guide](/administration/users/permissions) to learn how to assign permissions to users. ## Documents This section describes the actions different connection/model roles can take regarding [documents](/content/develop).
Permission No access Viewer Restricted Querier Querier Modeler Connection Admin
[Create documents](/content/develop)
View document names on homepage
## Workbooks This section describes the actions different connection/model roles can take in the [workbook](/analyze-explore) section of a document.
Permission No access Viewer Restricted Querier Querier Modeler Connection Admin
Access workbooks
[Upload CSV & XLSX files](/analyze-explore/data-input-csvs)
Run topic-based queries
Run all queries
Create & run [SQL queries](/analyze-explore/sql)
View SQL query results ❌\*
Use [functions & formulas](/analyze-explore/calculations)
Create & edit [visualizations](/visualize-present/visualizations/types)
Use [AI query](/ai/queries) or AI [spreadsheet calculations](/analyze-explore/calculations#ai-generated)
\* Can be enabled via the **View SQL** granular permission on a [custom Restricted Querier role](/administration/users/custom-roles). ## Dashboards This section describes the actions different connection/model roles can take in the [dashboard](/visualize-present/dashboards) section of a document.
Permission No access Viewer Restricted Querier Querier Modeler Connection Admin
Access dashboards
[Create & edit dashboards](/visualize-present/dashboards)
View topic-based charts
View non-topic based charts
[Download](/visualize-present/dashboards/download)
Create [schedules & alerts](/share/deliveries)
Use [filters & controls](/visualize-present/dashboards/filters)
Use drill functionality
## Modeling This section describes the actions different connection/model roles can take when interacting with the connection's [model](/modeling).
Permission No access Viewer Restricted Querier Querier Modeler Connection Admin
Stage workbook model changes
Access the [Content Validator](/modeling/develop/content-validator)
Stage [shared data model](/modeling) changes using a branch
Directly edit the [shared data model](/modeling)
[Refresh schema](/modeling/develop/schema-refreshes) (single model connection)
[Refresh schema](/modeling/develop/schema-refreshes) (multi-model connection)
Rename a shared model or shared extension
Create a shared extension model
Edit connection settings
## Branches This section describes the actions different connection/model roles can take when interacting with [branches](/content/develop/branch-mode).
Permission No access Viewer Restricted Querier Querier Modeler Connection Admin
View branches
Create branches
Merge branches
## Administration This section describes the actions different connection/model roles can take regarding the connection's settings. **Note**: Managing users, such as inviting them to your Omni instance, is handled by **Organization Admins**.
Permission No access Viewer Restricted Querier Querier Modeler Connection Admin
Manage connection permissions
Manage connection settings
# Common user access scenarios Source: https://docs.omni.co/administration/users/permissions-scenarios Learn how to implement user permissions to achieve different levels of access in Omni. Omni's user roles and the permissions they contain control your users' entire experience in Omni, from what they see in the app to the data they can access and build upon. In this guide, we'll show you how to implement permissions to achieve different levels of access in your own Omni instance. If there's a scenario you want to see here, reach out to Omni support. ## Requirements To follow this guide, you'll need familiarity with user roles in Omni, including [content roles](/share#content-access-permissions) and [connection roles](/administration/users/permissions). ## Before you begin Before you dive in, we recommend aligning with your team on what levels of access different groups should have in Omni - both for dashboards and for the data behind them. Think about the sensitivity of the data in your connected databases. If it includes things like employee details or other PII, you’ll want to make sure only the right people can directly query that data. Also consider whether your team will be building dashboards that include sensitive or internal-only information. If so, it’s important to map out folder and document permissions early so you can keep content access aligned with your organization’s needs. ## Fully locked down In this scenario, users shouldn't: * Be able to view existing dashboards and/or workbooks * Have access to data in your connections (databases) This type of setup is common when [externally embedding Omni](/embed), as it ensures that data access is tightly controlled. To achieve this, set the [organization's **default content access role**](/administration/content-permissions) and each [connection's **base access role**](/administration/users/permissions#defining-permissions-for-a-connection) to **No access**. This approach ensures that your users won’t have access to any data by default and anything they need access to would be granted explicitly after they were provisioned. ## Limited access In some cases you may want to allow users to only access specific datasets. There are a few ways to accomplish this: This will limit users to data in the connection that has been pre-joined and curated into topics. [Access grants](/modeling/develop/data-access-control) allow you to granularly restrict access to specific fields, topics, or views using [user attributes](/administration/users/attributes). Only users with the required user attribute value will be able to access the restricted data. When using this approach, you'll also need to set the users' **connection role** to **Restricted Querier** or below to limit the ability to query raw SQL, as this would allow users to bypass `access_grants` restrictions. In this scenario, you want your users to only be able to access content in the folders you specify. They won't be able to access any existing dashboards or workbooks outside these folders. To achieve this, you should: * **Set the [organization's default content role](/administration/content-permissions) to No access**. This ensures that, by default, users won't have access to content unless it's directly shared with them. * **Utilize [user groups](/administration/users/groups) to manage folder and document access**. This approach allows you to share folders and documents with the group instead of individual users. You can easily add and remove members as needed, ensuring each user always has the correct level of access. In this scenario, you want to grant different teams or users varying levels of access to a table or a topic. This can be accomplished in a few ways: * **Utilize [user groups](/administration/users/groups) to define different access levels**. For example: * `Group A` has **Querier** permissions, giving them access to all views and fields in the connection's models * `Group B` has **Restricted Querier** permissions, giving them access only to topics in the connection's models * **Individually define [connection roles](/administration/users/permissions#defining-permissions-for-a-connection) at the user level**. If you set the connection's base access role to something more restrictive - like **No Access** or **Viewer** - you can then individually grant users less restrictive permissions. For example, `User A` could have **Querier** permissions while `User B` has **Restricted Querier** permissions. * **Define [access grants](/modeling/develop/data-access-control) for topics and views**. Access grants allow you to apply additional restrictions to individual topics and views. This can be implemented with [user attributes](/administration/users/attributes) or through [user groups](/administration/users/groups), which can be more straightforward to maintain. * **Hide topics or views in workbooks.** When a topic or view's [`hidden` parameter](/modeling/topics/parameters/hidden) is set to `true`, it will no longer be visible to users in the workbook. The topic or view can still be referenced by the model, but users will be unable to select it. When a tile on a dashboard is backed by raw SQL - that is, the underlying query was built with SQL using the [Advanced Editor](/analyze-explore/sql) - users with the **Viewer** connection role may run into issues when trying to view the dashboard. These users will see something like this: This occurs because, despite having the **Content role** needed to view the dashboard, the query is built on data outside of their **Connection role** permissions. Connection **Viewers** can't view data built outside of topics, which limits their ability to inadvertently view data in the connection they're not supposed to have access to. **In this scenario, you can enable [AccessBoost](/share#boosting-permissions-with-accessboost) for the document or folder**. This will allow connection **Viewers** to view the raw SQL content. You can then manage access to the dashboard using the [document's content permission settings](/share#assigning-access-roles-to-content). **Before using AccessBoost**, refer to the [AccessBoost guide](/share#boosting-permissions-with-accessboost) to make sure you understand how this feature works and the impact it can have. # Troubleshooting user permissions Source: https://docs.omni.co/administration/users/permissions-troubleshooting Troubleshoot the most common permission issues. Omni offers a powerful set of user roles and the permissions to control your users' experience, but sometimes understanding all the nuances of permissions can cause confusion. If there's a troubleshooting question or scenario you want to see here, reach out to Omni support. Restricted Queriers and Viewers see **Can't display chart** errors when viewing a dashboard. This is typically due to Omni enforcing [connection roles](/administration/users/permissions) when content in a dashboard is built outside of a [topic](/modeling/topics). In this video, we explain what's happening and how to resolve it using Omni's [AccessBoost](/share#boosting-permissions-with-accessboost) feature. ``` After you've successfully configured and created an embed session, the last step is to apply your branding styles. While this last step is **optional**, it allows you to make the Omni Agent your own and blend it seamlessly with your application. Navigate to **AI Hub > General** and then click the [**Branding** tab](/ai/settings/branding). Use the settings to configure how you want the Omni Agent to look and then click **Save**. ## Next steps * [Implement AI credit controls](/ai/settings/usage) to manage your users' credit consumption * Define AI credit limits for [embed entity groups](/embed/admin/ai-credits) to manage credit usage for individual entities # Create Mode for embedded analytics Source: https://docs.omni.co/embed/customization/create-mode Enable the full Omni experience - creating, sharing, and navigating content - for your embedded users. Customers don’t just want to see data. They want to interact with it, explore it, and get their own insights, without waiting for a data team to make adjustments. With Create Mode for Omni embedding, you can allow your users to create, share, and navigate content as if they were in the native Omni app. ## Entities Create mode uses an `entity` parameter to isolate embed customers from each other. This ensures that users can only see and share content with other users in their `entity`. Refer to the [Enabling create mode section](#enabling-create-mode) for an example. When Omni detects a new entity value, a dedicated, shared folder and user group is automatically created for the entity. Only the entity that the folder was created for and admins on your Omni organization can access it. Refer to the [User roles & content permissions](#user-roles-and-content-permissions) for more information on controlling user access to content. ## Enabling Create Mode To enable Create Mode for an embedded Omni instance, set the `mode` embed URL parameter to `APPLICATION` (`mode=APPLICATION`). For example: ```markdown wrap theme={null} https://blobsrus.embed-omniapp.co/embed/login?contentPath=%2Fdashboards%2F12db1a0a&externalId=1234abcd&name=Blobby&nonce=OYZFNSulBHxivB9xBw7kAsv4aDu7zl4G&signature=kYnijvMXMBmVQ3wJ6mfmR132qOZZpnZlRi2uSvEjZYA&userAttributes=%7B%7D&entity=blobs_r_us&connectionRoles=%7B%22c0f12353-4817-4398-bcc0-d501e6dd2f64%22%3A%22RESTRICTED_QUERIER%22%7D&mode=APPLICATION&entityFolderContentRole=VIEWER&groups=%5B%5D ``` Refer to the [Embed parameters reference](/embed/setup/url-parameters) for more information about URL parameters. Refer to [step 1 of the Standard SSO setup guide](/embed/setup/standard-sso) for information about manually generating a signature. ## User roles and content permissions Two parameters control how embed users can interact with content when in Create mode: * **Connection role** (`connectionRoles`), which determines if a user can create content or only consume it * **Entity folder content role** (`entityFolderContentRole`), which determines if a user can add or manage content for their entity Refer to the following table for information about how these roles map and the permission sets they produce. | Connection role | Entity folder content role | Permissions | | ------------------ | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | Viewer | Viewer |
  • View content
| | Restricted querier | Viewer |
  • Create content only in a user's private folder
  • Share content with other users in the entity
| | Restricted querier | Editor or Manager |
  • Create content in the **Shared** folder or a user's private folder
  • Share content to the entity's **Shared** folder
| ## Entity folder and group labels By default, the labels of an entity's generated folder and user group will be human-readable versions of the associated entity value. As an example, entity `"tottenham_hotspur"` would generate a folder and group labeled `Tottenham Hotspur` in the Omni UI. If you'd like to customize the names of the generated entity group and folder, you can use the [`entityFolderLabel`](/embed/setup/url-parameters/entityFolderLabel) and [`entityGroupLabel`](/embed/setup/url-parameters/entityGroupLabel) parameters. These parameters are useful if you want multiple entity groups and folders to have the same label for an entity A and B. For example, if you have two entities - `acme_marketing` and `acme_finance` - but want the generated groups and folders to both appear as `Acme` in the Omni UI, you can do so using the `entityFolderLabel` and `entityGroupLabel` parameters. ## Next steps * Create a [custom sidebar and theme](/embed/customization/themes) for your embedded application # Configuring email deliveries in embedded Omni Source: https://docs.omni.co/embed/customization/deliveries Allow users in your embedded Omni instance to schedule or set alerts on documents. ## Disabling deliveries If needed, Organization Admins can disable this feature at an [instance-wide](/administration/content-permissions) or a [document](/share#controlling-document-interactivity) level. ## Customizing sender information The **Customer email sender** feature allows you to customize the sender information for Omni delivery emails, including the sender's name, email domain, and reply-to address. Refer to [Whitelabeling sender addresses for email deliveries](/share/deliveries/email/whitelabel) for more information. ## Populating email suggestions In order for email suggestions to be populated automatically for deliveries, the [`email` parameter](/embed/setup/url-parameters/email) needs to be included in the embed URL. # Enabling iframe-restricted functionality for embedded instances Source: https://docs.omni.co/embed/customization/iframes Enable functionality for embedded content that iframes restrict by default. By default, iframes restrict access to certain functionality that could pose a security risk, such as copying or using the microphone. However, you can allow your users to use these features by including them in your iframe declarations. ## Supported features The following Omni features can currently be enabled through the `allow` parameter in iframe declarations: | Parameter | Description | | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | [`clipboard-write`](#allow-clipboard) | Enables clipboard access, allowing users to copy data values from embedded Omni | | [`microphone`](#allow-microphone) | Enables microphone access, allowing users to use the Omni Agent's voice mode feature | | [`fullscreen`](#allow-fullscreen) | Enables fullscreen viewing for dashboards and workbooks through the user's native browser fullscreen functionality | ## Allow copying in embed iframes Access to the viewing device's clipboard is restricted by default. This means that when you click on a data value within Omni and select **Copy value**, the value will not be copied to your clipboard. To allow clipboard access, add `allow="clipboard-write"` to your iframe declaration: ```html wrap theme={null} ``` # Embed events Source: https://docs.omni.co/embed/events/index Build interactive experiences in your embedded Omni application with JavaScript events. Omni events make it easy to create interactive, integrated experiences when embedding Omni in your application: * With just a few lines of JavaScript, [your app can listen](/embed/events/consume) for what users are doing inside embedded Omni content - like selecting filters, downloading content, or switching tabs - and respond in real time. * You can also [send events back into Omni](/embed/events/send) to drive the experience from the outside, whether that’s updating filters in embedded content or navigating to a specific page. * Omni's [table and Markdown visualizations](/embed/events/visualizations) can emit events on click with a little bit of configuration # navigate embed event Source: https://docs.omni.co/embed/events/navigate Triggers a redirect to the path specified in the payload. Content and/or connection permissions are not automatically provided to the user during a `navigate` event. This means if you redirect a user to a dashboard or workbook, the user will need the appropriate content and/or connection permissions to view the content. ```json theme={null} { "name": "navigate", "payload": { "path": "string" } } ``` ## Properties The path to redirect to. ## Example ```json theme={null} { "name": "navigate", "payload": { "path": "/dashboards/abcd1234" } } ``` # navigation:home embed event Source: https://docs.omni.co/embed/events/navigation-home Emitted by Omni when a user clicks the logo or home link in the navigation header. This event is emitted when users interact with the home navigation elements: * Clicking the Omni logo * Clicking the home link in the header Use this event to track when users navigate to the home page or to trigger custom navigation behaviors in your embedding application. ## Payload This event carries an empty payload and serves as a notification signal only. ```json theme={null} {} ``` ## Example When a user clicks the logo or home link, Omni emits: ```json theme={null} { "name": "navigation:home", "payload": {} } ``` # page:changed embed event Source: https://docs.omni.co/embed/events/page-changed Emitted by Omni when the URL of a page changes. This can be consumed by the embedding frame to generate shareable links. ## Payload ```json theme={null} { "href": "string", "pathname": "string", "search": "string", "type": "string" } ``` ## Properties The fully qualified URL, e.g., `https://blobsrus.omniapp.co/dashboards/123abc?f--users.email=someone@example.com`. The path of the URL (e.g., `/dashboards/123abc`). Query params from the URL, e.g., `?f--users.email=someone@example.com`. Type of page. One of `dashboard`, `workbook`, or `other`. ## Example ```json wrap theme={null} { "href": "https://blobsrus.omniapp.co/dashboards/123abc?f--users.email=someone@example.com", "pathname": "/dashboards/123abc", "search": "?f--users.email=someone@example.com", "type": "dashboard" } ``` # Sending embed events to Omni Source: https://docs.omni.co/embed/events/send Trigger actions in an embedded Omni application by sending events into the Omni iframe. You can send events into an Omni iframe to trigger actions in your embedded Omni application. Like emitted events, events sent to Omni should use the [`postMessage` protocol](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage). ## Event shape Events sent to Omni are expected to have the following shape: ```typescript theme={null} type EmbedEvent = { payload: Payload name: EmbedEventName } ``` The following is an example of a JavaScript event handler that sends a `navigate` embed event to an Omni iframe via `postmessage`: ```javascript wrap theme={null} const handleNavigateButtonClick = (path) => { document.querySelector('iframe').contentWindow.postMessage( { name: "navigate", payload: { path }, }, "https://youromniorganization.embed-omniapp.co" ); }; ``` ## Supported events The following events can be sent to an Omni iframe: | Event | Description | | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | [`appearance:mode`](/embed/events/appearance-mode) | Triggers a color scheme change of the embedded Omni session. | | [`dashboard:filter-change-by-url-parameter`](/embed/events/dashboard-filter-change-by-url-parameter) | Triggers the change of a filter value on an embedded dashboard. | | [`fullscreen:set`](/embed/events/fullscreen-set) | Sets the fullscreen presentation state of the embedded Omni session. | | [`navigate`](/embed/events/navigate) | Triggers a redirect to the path specified in the payload. | # sidebar:open embed event Source: https://docs.omni.co/embed/events/sidebar-open Emitted by Omni when a user clicks the mobile menu button. This event is emitted when users click the mobile menu button to open the [sidebar](/administration/settings/sidebar) navigation. Use this event to track when users interact with mobile navigation or to trigger custom behaviors in your embedding application when the sidebar is accessed. This event is informational only. The sidebar popover will still open within the embedded iframe regardless of how the parent application handles this event. ## Payload This event carries an empty payload and serves as a notification signal only. ```json theme={null} {} ``` ## Example When a user clicks the mobile menu button, Omni emits: ```json theme={null} { "name": "sidebar:open", "payload": {} } ``` # size embed event Source: https://docs.omni.co/embed/events/size Emitted by Omni to give the size of embedded content, allowing you to dynamically size the iframe. Omni emits the `size` event when a dashboard loads, and when an embedded [app](/visualize-present/apps) loads or resizes. This allows you to dynamically adjust the iframe height to fit the content. The payload is the same for both, so an existing dashboard resize handler will size an app without changes. An app only emits the event when it fills the whole frame, with no Omni header or navigation around it — which is what [`SINGLE_CONTENT`](/embed/setup/url-parameters/mode) mode gives you. An app shown with Omni's chrome doesn't emit it, because a size that excluded the chrome would make the host clip the page. ## Payload ```json theme={null} { "width": number, "height": number } ``` ## Properties Width of the embedded content in the iframe. Height of the embedded content in the iframe. ## Example ```json theme={null} { "width": 600, "height": 400 } ``` # status embed event Source: https://docs.omni.co/embed/events/status Emitted by Omni to indicate the status of the dashboard to the parent frame. ## Payload ```json theme={null} { "status": "string", "dashboardId": "string" } ``` ## Properties Status of the dashboard in the iframe. One of `loading`, `running`, `done`, or `error`. The identifier of the dashboard that emitted the status event. This allows embedded dashboard consumers to identify which dashboard is reporting its status. ## Example ```json theme={null} { "status": "loading", "dashboardId": "dashboard-123abc" } ``` # Sending embed events from Omni visualizations Source: https://docs.omni.co/embed/events/visualizations Trigger actions in your application by emitting events from embedded Omni table and Markdown visualizations. Omni's Markdown and table visualizations can be configured to emit events. These events can be observed by listeners in the parent frame to trigger certain actions, such as popping open custom drill modals or passing through certain data from Omni to the parent frame. ## Table visualizations Events can be triggered on click in table visualizations. 1. Open the configuration options for a table visualization. 2. Next to a field, click the to open its configuration options. 3. Click the **Display** tab. 4. Set **Display as** to **Link**. 5. Set **URL** to **Embed event**. 6. Enter a name for the event. ## Markdown visualizations You can also send events from Markdown visualizations. When clicked, a post message is sent from the iframe to the parent iframe. Use a tag like the following, setting the event name and data, to accomplish this: ```html wrap theme={null} ``` # Embedding Omni in external applications Source: https://docs.omni.co/embed/index Embed Omni dashboards and analytics in external applications with row-level permissions, SSO, and full theme customization. External embedding enables delivering data to users outside of the business, living in other applications. Reporting can be mapped to row level permissions, allowing many users to access identical reports filtered to only their own data. Using embedded Omni content, you could create: * Simple, interactive dashboards for high-level summaries * Short-lived workbooks to give their users deeper access to their data * More robust data applications All these use cases leverage the same base technology: creating an authorized Omni URL that you'll use in an iframe. The URL contains the content you want to share, the ID of the user in your system, and the attributes you want that user to have. You'll then sign the URL with a secret key provided by Omni. ## See it in action * Follow along [on Youtube](https://www.youtube.com/watch?v=4XRgDRv9SRM) as we build a data product, going from analysis to dashboard to stylized app in 30 minutes * Check out the **Analytics** tab in your Omni instance! This is an example of embedded content in [Create mode](/embed/customization/create-mode) that shows information about the usage of your Omni instance. **Note**: This feature is only available to Organization Admins. # Embedding limitations Source: https://docs.omni.co/embed/limitations Understand current limitations of Omni embedding, including session length, supported browsers, content types, and feature gaps. ## Session length Currently, using a valid embed URL will create an embed session that can be configured to last between 0-576 hours. That embed session will be unusable after the configured expiry. Visiting a new, valid embed SSO URL at any time will create a new session. ## Chrome incognito Using Chrome in Incognito mode requires allowing third-party cookies. These can be found under **Chrome > Settings... > Privacy and Security > Third-party cookies**. Enable the **Allow third-party cookies** option. ## Default iframe restrictions By default, iframes restrict access to certain functionality that could post a security risk, such as copying or using the mircophone. However, you can allow your users to use these features by including them in your iframe declarations. See [Enabling iframe-restricted functionality for embedded instances](/embed/customization/iframes) for more information. ## Keyboard shortcuts [Keyboard shortcuts](/getting-started/keyboard-shortcuts) are not currently supported in embedded Omni instances. ## Safari, mobile Safari, and mobile iOS Chrome Omni uses cookies to manage authentication sessions. When embedded in iframes, browsers like Safari treat these as third-party cookies and block them by default, which prevents access to Omni content. How you handle this depends on which Safari version your users have and whether you've configured a vanity domain. ### Safari 26.2 and newer - Automatic handling Safari 26.2+ supports CHIPS (Cookies Having Independent Partitioned State), which allows embedded content to authenticate automatically without requiring user action. Omni detects CHIPS support and handles authentication seamlessly. This automatic experience works in: * Safari 26.2+ on macOS * Safari 26.2+ on iOS and iPadOS ### Safari 26.1 and older - Manual handshake Older Safari versions require a multi-step handshake that prompts users to explicitly allow third-party cookies: 1. When the embedded dashboard loads, a `Cookies are not permitted` message appears with a button to visit the Omni instance directly. 2. After visiting Omni in a non-embedded context, the user returns to the embedded page. 3. Safari prompts the user to allow access to "use cookies and website data". Clicking **Allow** displays the embedded dashboard. Users typically only need to complete this process once, though Safari may occasionally prompt them again. ### Vanity domains - Alternative approach Configuring a [vanity domain](/embed/customization/vanity-domains) allows Omni cookies to originate from your embedding domain, making them first-party cookies. This eliminates Safari's third-party cookie restrictions entirely across all Safari versions. Vanity domains require infrastructure setup but provide a consistent experience regardless of browser version or privacy settings. Vanity domain embeds continue to use the Storage Access API handshake flow even on Safari 26.2+, as CHIPS partitioned cookies do not support custom domain attributes. ## Per-user database OAuth [Per-user OAuth for database connections](/connect-data/oauth) is only supported with [vanity-domain embeds](/embed/customization/vanity-domains). When using per-user OAuth, Omni opens a popup for database authentication. This popup must share the same cookie partition as the embedded iframe to complete the OAuth flow. Default embed domains (`embed-*`) use a different registrable domain than your embedding page, which places them in separate cookie partitions and prevents the OAuth flow from completing. Vanity domains solve this by using your own subdomain (e.g., `omni.myapp.com` embedded in `myapp.com`), keeping both the iframe and popup in the same cookie partition. # Embedding Omni quickstart Source: https://docs.omni.co/embed/quickstart Get up and running with your embedded Omni application. **Organization Admin** permissions are required to follow the steps in this guide. First, reach out to Omni support to have the **Embed** feature enabled for your instance. You have two options when it comes to generating embedded user sessions: 1. [**Standard SSO**](/embed/setup/standard-sso): Generate and use a single URL to create an embed user and session. This is the simplest way to embed Omni for your external users. 2. [**2-step SSO**](/embed/setup/two-step-sso): First, send a `POST` request to generate the embed user and session. Then, generate and use a URL to authenticate into the session. This requires more setup, but has a few advantages over the standard SSO embed experience: * **Sensitive user data**: If using the `userAttributes` parameter with sensitive user data, you may prefer creating SSO embed users and sessions via `POST` request for added security. * **URL length**: While generally unlikely, there is more risk of standard SSO embed URLs exceeding a browser's URL character limit. 2-step login URLs are more compact and thus have no risk of hitting the limit. Follow the guide for your preferred approach to complete the implementation. While Omni is where permissions and content are managed, the application where the content is embedded should dynamically map users to the right underlying data. Refer to the [Embedding best practices](/embed/best-practices) to make sure Omni is set up correctly before you begin developing. Once you successfully set up your embed infrastructure, you can: * Change your application's look and feel with [custom theming](/embed/customization/themes) * Add interactivity with [events](/embed/events) * Implement [vanity domains](/embed/customization/vanity-domains) for a fully whitelabeled experience # Customizing embed users and sessions with URL parameters Source: https://docs.omni.co/embed/setup/customize Customize embed users and sessions with Omni embed parameters. For example, you can use embed URL parameters to: * Specify user content roles * Assign connection and model roles to users * Control the look and theme of your embedded application * Apply user attributes to users ## Providing parameters How parameters are provided depends on the type of SSO setup your embed implementation uses: * [**In standard SSO embed**](/embed/setup/standard-sso), parameters are passed as URL query parameters: ```markdown wrap theme={null} https://omni.blobsrus.com/embed/login?contentPath=%2Fmy&externalId=artiste1322&name=Blob+Ross&nonce=7RR6BdkQ8FgXf2FHABLFhWTebflsWya2&signature=VwmHh5ygv35i0Zc8mTiT6ugRnzqwBLfEP83ZDh6pfVE&entity=Happy+Trees&connectionRoles=%7B%7D&entityFolderContentRole=EDITOR&preserveEntityFolderContentRole=false ``` * [**In 2-step SSO embed**](/embed/setup/two-step-sso), the majority of these parameters are included as a JSON payload in the `POST /generate-session` request: ```json wrap title="POST /api/unstable/embed/sso/generate-session" theme={null} curl -X POST 'https://omni.blobsrus.com/api/unstable/embed/sso/generate-session' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "contentPath": "/my", "externalId": "artiste1322", "name": "Blob Ross", "entity": "Happy Trees", "entityFolderContentRole": "EDITOR" }' ``` ## Available parameters Refer to the [Embed URL parameters reference](/embed/setup/url-parameters) for a complete list of parameters and examples. # Generating embedded user sessions Source: https://docs.omni.co/embed/setup/index Set up your embedding infrastructure and generate user sessions. You have two options when it comes to generating embedded user sessions: ## Easy: Standard SSO With [**standard SSO**](/embed/setup/standard-sso), you generate and use a single URL to create an embed user and session. This is the simplest way to embed Omni for your external users. ## Advanced: 2-step SSO With [**2-step SSO**](/embed/setup/two-step-sso), you start by sending a `POST` request to generate the embed user and session. Then, you'll generate and use a URL to authenticate into the session. This requires more setup, but has a few advantages over the standard SSO embed experience: * **Sensitive user data**: If using the `userAttributes` parameter with sensitive user data, you may prefer creating SSO embed users and sessions via `POST` request for added security. * **URL length**: While generally unlikely, there is more risk of standard SSO embed URLs exceeding a browser's URL character limit. 2-step login URLs are more compact and thus have no risk of hitting the limit. # Embed standard SSO Source: https://docs.omni.co/embed/setup/standard-sso/index Set up standard SSO for Omni embedding by generating a signed URL that creates an embed user session with a single request. With standard SSO, you generate and use a single URL to create an embed user and session. Omni embed URLs are signed with a secret key used only by your organization. When an Omni server receives the request, it verifies the signature using that secret. If the signature checks out, the request is honored. Two signing formats are supported for standard SSO: | Format | Status | Description | | ----------------------------------------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [**v1 (signed payload)**](/embed/setup/standard-sso/latest) | latest | Every [parameter](/embed/setup/url-parameters) is included inside a single `payload` query parameter that the signature covers as a whole. If generating with the SDK, requires `@omni-co/embed` v1.0.0 or later. | | [**v0 (legacy)**](/embed/setup/standard-sso/v0-legacy) | v1 (deprecated) | Each parameter is sent as its own query parameter alongside a `signature`. Deprecated: unsupported after October 1, 2026, and removed by January 1, 2027. | Both formats are accepted at `/embed/login`, so existing integrations will continue to work. Use v1 for new integrations, and plan to migrate existing ones. Because embed URLs are signed using your Omni organization's embed secret, it is crucial that your embed URLs are generated server-side rather than client-side. From a security perspective, this protects your embed secret from being exposed to attackers. Also note that the Omni TypeScript SDK utilizes Node's `crypto` module, which is only available in Node environments. Attempting to use the Omni TypeScript SDK functions in a client-side context will likely lead to the SDK functions generating improperly signed embed URLs. # Setting up embed standard SSO with the v1 signing payload format Source: https://docs.omni.co/embed/setup/standard-sso/latest Set up standard SSO for Omni embedding by generating a signed URL that creates an embed user session with a single request. In this guide, you'll set up standard SSO for Omni embed using the v1 (latest) signing format. As the simplest way to embed Omni, this involves generating and using a single URL to create an embed user session. **Migrating from v0?** See [Migrating to the v1 embed standard SSO signing format](/embed/setup/standard-sso/migrate-to-latest) to learn about what changed in v1 and how to migrate your code. ## Requirements To follow the steps in this guide, you'll need: * **Organization Admin** permissions * To have the **Embed** feature enabled in your Omni instance If you want to use the [Omni TypeScript SDK](https://www.npmjs.com/package/@omni-co/embed) to generate an embed URL, you'll need `@omni-co/embed` v1.0.0 or later: ```bash theme={null} npm install @omni-co/embed ``` 1. Navigate to **Settings > Embed > Admin** in your Omni instance. 2. Click the **Add Secret** button below the secrets table. 3. In the dialog that appears: * A 32-character secret key is automatically generated for you * Enter a descriptive **Name** to identify the secret's purpose (e.g., "Production", "Staging", or "Partner Integration") Use descriptive names for your secrets to make them easier to identify and manage, especially when rotating secrets or managing multiple environments. 4. Click **Add secret** to save the new secret. This step is optional. In the [**Embed** settings](/embed/admin/security) of your Omni instance, you can also customize the length of embed sessions using the **Session Length** setting. In this field, enter the number of hours you want sessions to last and click **Change**. Because embed URLs are signed using your Omni organization's embed secret, it is crucial that your embed URLs are generated server-side rather than client-side. From a security perspective, this protects your embed secret from being exposed to attackers. Omni embed URLs are signed with a secret key used only by your organization. When an Omni server receives the request, it verifies the signature using that secret. If the signature checks out, the request is honored. There are three ways to generate a signed embed URL - the SDK (recommended), the API, or manually. **Click the tabs below to view instructions for each approach.** Omni's [TypeScript SDK](https://www.npmjs.com/package/@omni-co/embed) is the recommended way to generate embed URLs. Each function returns a complete, signed login URL: ```typescript title="Generate a v1 signed embed URL" wrap theme={null} import { embedSsoDashboard } from "@omni-co/embed"; const iframeUrl = await embedSsoDashboard({ contentId: "123abc", externalId: "blob.ross@blobsrus.com", name: "Blob Ross", organizationName: "blobsrus", secret: process.env.OMNI_EMBED_SECRET, entity: "Blobs R Us", theme: "vibes", userAttributes: { planet: "blobine" }, }); ``` The Omni TypeScript SDK utilizes Node's `crypto` module, which is only available in Node environments. Attempting to use Omni TypeScript SDK functions in a client-side context will likely lead to the SDK functions generating improperly signed embed URLs. Always generate embed URLs server-side. Every v1 payload carries an expiry. The SDK automatically sets the expiry to 24 hours from the moment the URL is minted. To choose a different lifetime, use the `expiresIn` parameter to define the new lifetime in seconds. The value must be positive and at most seven days (`604800` seconds): ```typescript title="Generate a URL that's valid for one hour" wrap highlight={12} theme={null} import { embedSsoDashboard } from "@omni-co/embed"; const iframeUrl = await embedSsoDashboard({ contentId: "123abc", externalId: "blob.ross@blobsrus.com", name: "Blob Ross", organizationName: "blobsrus", secret: process.env.OMNI_EMBED_SECRET, entity: "Blobs R Us", theme: "vibes", userAttributes: { planet: "blobine" }, expiresIn: 3600, }); ``` See [URL expiry](/embed/setup/standard-sso/migrate-to-latest#url-expiry) for more information. While the TypeScript SDK is the preferred method for generating signed URLs, you may not be able to leverage it if your backend isn't running a JavaScript runtime. For other languages and environments, Omni offers a stateless API as an escape hatch: ```text wrap theme={null} https:///embed/sso/generate-url ``` The `/embed/sso/generate-url` endpoint only accepts `POST` requests. For `POST` operations, parameters are passed as a JSON object in the request body: ```bash wrap title="POST /embed/sso/generate-url" theme={null} curl -X POST https://blobsrus.omniapp.co/embed/sso/generate-url \ -H 'Content-Type: application/json' \ -d '{ "contentPath": "/dashboards/12345678", "externalId": "abcd1234", "name": "Blob Ross", "secret": "12345678901234567890123456789012", "userAttributes": "%7B%22shop_id%22%3A%22123%22%7D" }' ``` This endpoint returns a v1 signed URL for an embedded piece of content. Additionally: * The endpoint does not accept a signature parameter, as that is what's being generated. * The endpoint requires a `secret` parameter in the request body. The value should be the **Embed secret** you created in step 1. * The `nonce` parameter is optional. If not included, one will be automatically generated. * JSON-encoded parameter values in the request body (`userAttributes`, `connectionRoles`) should be URL encoded. This applies to the request body only - the endpoint handles payload encoding for the URL it returns. Refer to the [Embed parameters reference](/embed/setup/url-parameters) for a complete list of available parameters. The steps outlined in this section must be followed **exactly** to be successful. Use these steps to generate a v1 signed URL if your backend can't run the TypeScript SDK and you'd rather not call the API: Build a JSON object containing your parameters. The following are required: ```markdown theme={null} loginUrl // the full login URL, including scheme and host contentPath externalId name nonce exp // expiry, as epoch seconds ``` Any of the [optional parameters](/embed/setup/url-parameters) can be included alongside the above parameters. Omit parameters you aren't setting rather than sending them empty, and note that: * **`loginUrl` must exactly match the URL you send the request to.** Omni compares the two after verifying the signature. * **`exp` is the absolute expiry in epoch seconds**, following the JWT convention - seconds, not milliseconds. This value must be no more than seven days out. See [URL expiry](/embed/setup/standard-sso/migrate-to-latest#url-expiry) for more information. * **JSON-valued parameters are real JSON.** `userAttributes`, `connectionRoles`, `modelRoles`, `customTheme`, and `uiSettings` are objects, and `groups` is an array of strings. Don't stringify them first. * **`filterSearchParam` is a URI-encoded query fragment**, because that's what the parameter itself holds. For example: ```json wrap title="Example parameters" theme={null} { "loginUrl": "https://blobsrus.embed-omniapp.co/embed/login", "contentPath": "/dashboards/123abc", "externalId": "luke@example.com", "name": "Luke Skywalker", "nonce": "hN38NgtnV2B3PMILhKQOpwLyJRP4qVv4", "exp": 1787684977, "entity": "Acme Corp", "theme": "vibes", "userAttributes": { "planet": "tatooine" } } ``` Serialize the object to UTF-8 JSON, compress it with raw DEFLATE ([RFC 1951](https://datatracker.ietf.org/doc/html/rfc1951)), and base64url-encode the result. This encoded string is the `payload` parameter. The compression level doesn't matter; neither does the exact byte output of your DEFLATE implementation. Two languages compressing the same parameters will produce different `payload` strings - both are valid. Omni also accepts a zlib-wrapped ([RFC 1950](https://datatracker.ietf.org/doc/html/rfc1950)) payload, which is the default output of several standard libraries. The encoded `payload` string must be 64KB or smaller. A fully populated payload is well under 2KB, so if you hit this limit, a parameter - usually `userAttributes` - is carrying more than it should. Sign the `payload` string - the base64url text itself, not the compressed bytes - using your secret key with an HMAC-SHA256 digest algorithm, encoded as a base64url string. This is the `signature` parameter. Padding is optional, and both the `-_` and `+/` alphabets are accepted, so the default output of most languages' base64url helpers will verify as-is. Refer to [the Base64 spec](https://datatracker.ietf.org/doc/html/rfc4648#page-7) for more information about base64url. Append `payload` and `signature` to the login URL as URL-encoded query parameters. No other parameters are included in the URL; everything else is carried inside the payload. ```python wrap expandable title="Python example" theme={null} import base64, hashlib, hmac, json, os, time, urllib.parse, zlib secret = os.environ["OMNI_EMBED_SECRET"] login_url = "https://blobsrus.embed-omniapp.co/embed/login" params = { "loginUrl": login_url, "contentPath": "/dashboards/123abc", "externalId": "luke@example.com", "name": "Luke Skywalker", "nonce": "hN38NgtnV2B3PMILhKQOpwLyJRP4qVv4", # Expire in 24 hours. Epoch seconds, at most 7 days out. "exp": int(time.time()) + 24 * 60 * 60, "entity": "Acme Corp", "theme": "vibes", "userAttributes": {"planet": "tatooine"}, } # Raw DEFLATE (RFC 1951): a negative wbits omits the zlib wrapper. compressor = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS) compressed = compressor.compress(json.dumps(params).encode("utf-8")) compressed += compressor.flush() payload = base64.urlsafe_b64encode(compressed).decode("ascii") signature = base64.urlsafe_b64encode( hmac.new(secret.encode("utf-8"), payload.encode("utf-8"), hashlib.sha256).digest() ).decode("ascii") embed_url = login_url + "?" + urllib.parse.urlencode( {"payload": payload, "signature": signature} ) ``` A v1 login URL has the following form, where all parameters are carried inside the `payload` parameter: ```text wrap theme={null} https://.embed-omniapp.co/embed/login?payload=&signature= ``` For example, this is a signed embed URL for a `blobsrus` organization: ```shell wrap theme={null} https://blobsrus.embed-omniapp.co/embed/login?payload=HY7BboMwEER_JZozBSWgQn1q2lNamtJWzd02q4AwtmsvSVCUf6_I9Y3mzVxh3LG3v8FAoGP2UWSZMk7FMMWURkXtgxttL71PtcvuILtXkEA7y2S5kdxBIGtl7JSToY3ZepNLpZGALkzBSrNrIWCmgZ7pIkdvKNVuRAIrR4JAPQ20-hnmszQDhYU7q5eg2-fV_sj2sHnJm49d3b1_ffpzPb99N8Xf4VQsE5Z7niGw1SOtXl3wSMAd3cWnXlFEgilS2DKHXk1MEeIKb6QlhgBLdq63hNty10Osy6p8rIqnsrz9Aw&signature=c14FIQAVH7__vgWG5G3IF8_DF5qPSGx4CPFWqeMmfgc&sdk=%40omni-co%2Fembed%401.0.0-next.3 ``` SDK-generated URLs also carry an `sdk` parameter identifying the version that produced the URL. It isn't covered by the signature and isn't required - Omni uses it to understand which SDK versions are in use. This step is optional. While the embed URL builder is primarily intended for internal embedding, you can use it to test the format of your [URL parameters](/embed/setup/url-parameters). 1. First, you'll need your content's unique ID: You can find the dashboard ID by: * **Opening the document settings**. Navigate to **File > Document settings** in the dashboard and then click **Settings**. The **Identifier** field contains the dashboard ID. * **Using the dashboard's URL**. The string after `/dashboards` is the dashboard's ID; for example: ```markdown wrap theme={null} https://blobsrus.omniapp.co/dashboards/12db1a0a ``` * **If the workbook is attached to a dashboard**, its content ID is the same as the dashboard * **If the workbook doesn't have a dashboard**, you can find the ID by navigating to **File > Document settings**, then clicking **Settings**. The **Identifier** field contains the document ID. **Note**: Embedding a workbook creates a copy of the workbook for that embed user so their changes are not reflected back into the application's production version of the workbook. 2. Navigate to **Admin > Embed > URL Builder tab**. 3. Fill in the required fields, noted below: * **Content Path** * **For dashboards**: `/dashboards/` * **For workbooks**: `/w/` * **For apps**: `/apps/` * **External ID** - Any alphanumeric value * **Name** - Any alphanumeric value 4. Generate your URL and embed! # Migrating to the v1 embed standard SSO signing format Source: https://docs.omni.co/embed/setup/standard-sso/migrate-to-latest Learn what changed in the v1 embed standard SSO signing format and how to update your code from v0. The v1 signing format replaces the deprecated v0 format. The v0 format will be unsupported after October 1, 2026, and removed by January 1, 2027. Use this page to learn what changed in v1 and what to update in your code. See the [v1 standard SSO guide](/embed/setup/standard-sso/latest) for step-by-step instructions on setting up standard SSO with the v1 format. ## SDK functions In [`@omni-co/embed`](https://www.npmjs.com/package/@omni-co/embed) v1.0.0 and later, the original function names now produce v1 URLs. The v0 builders are still exported, renamed with a `deprecated` prefix: | v1 function | v0 equivalent | Generates a URL for | | -------------------------- | ------------------------------------ | ------------------------ | | `embedSsoDashboard` | `deprecatedEmbedSsoDashboard` | A dashboard | | `embedSsoWorkbook` | `deprecatedEmbedSsoWorkbook` | A workbook | | `embedSsoApp` | `deprecatedEmbedSsoApp` | An app | | `embedSsoContentDiscovery` | `deprecatedEmbedSsoContentDiscovery` | A content discovery page | Both formats are temporarily accepted at `/embed/login`. The v1 functions accept the same parameters, with two differences: * **JSON-valued parameters are passed as objects and arrays instead of pre-stringified strings.** See [JSON-valued parameters](#parameters) for more information. * **`expiresIn` sets how long the generated URL stays valid.** The `deprecatedEmbedSso*` builders accept and ignore it, because v0 URLs have nowhere to carry an expiry. See [URL expiry](#url-expiry) for more information. Upgrading to v1.0.0 without changing your code will change the URLs you generate. Existing calls to `embedSsoDashboard` and its siblings keep working but will produce v1 URLs. Expect the new shape if anything on your side inspects, logs, or reconstructs these URLs. ## JSON-valued parameters The [v1 SDK functions](#sdk-functions) accept the same parameters they did in v0, but parameters structured as JSON are now passed as objects and arrays instead of pre-stringified strings. In v0, you needed to stringify and then URL encode parameters with JSON values. For example: ```json wrap v0 parameter example theme={null} userAttributes=%7B%22country%22%3A%22Townsville%22%7D ``` In v1, you instead pass the JSON as-is: ```json wrap v1 parameter example theme={null} userAttributes={"country":"Townsville"} ``` ## New parameters ### exp (URL expiry) Every v1 payload carries an `exp` parameter: the absolute moment the URL stops being valid, in epoch seconds, following the JWT convention. * **If you use the SDK**, the SDK sets `exp` to 24 hours out by default. Use the `expiresIn` parameter to change the lifetime. * **If you generate URLs manually**, set `exp` yourself as part of the payload. Set it no more than seven days out to match the ceiling the SDK enforces. Because `exp` is included in the payload, the signature already covers it. There's no separate query parameter, and a URL's expiry can't be changed without re-signing. When defining URL expiry, keep in mind that shorter expiries are better. Until the embed URL is redeemed, it's a bearer credential - anyone who has it can start the session it describes, and URLs leak through browser history, referer headers, screenshots, and proxy logs. Generate URLs on demand where you can, and only use a longer lifetime when needed, such as a URL that goes out in an email or gets built by a nightly job. Omni currently requires `exp` to be present, but doesn't yet reject URLs whose expiry has passed. By October 2026, Omni will begin enforcing URL expiry and reject payloads that don't include an `exp` parameter. Migrate your code before then to avoid disruptions. ## Removed parameters The `domain` parameter was removed in v1.0.0. Use `host` instead. ## Next steps * [Set up embed standard SSO with the v1 signed payload format](/embed/setup/standard-sso/latest) # Embed standard SSO - Legacy v0 signing format Source: https://docs.omni.co/embed/setup/standard-sso/v0-legacy Reference for the deprecated v0 embed URL signing format, in which each parameter is sent as its own URL parameter alongside a signature. The v0 format is deprecated. It will be unsupported after October 1, 2026, and removed by January 1, 2027. Use the [v1 signed payload format](/embed/setup/standard-sso/latest) for new integrations, and [migrate existing ones](/embed/setup/standard-sso/migrate-to-latest) before then. Use this guide as a reference for the legacy v0 embed URL signing format. In the v0 format, each [parameter](/embed/setup/url-parameters) is sent as its own URL query parameter, and the `signature` parameter covers the parameter values concatenated into a single newline-delimited string. ## Parameter encoding JSON-valued parameters - [`userAttributes`](/embed/setup/url-parameters/userAttributes), [`connectionRoles`](/embed/setup/url-parameters/connectionRoles), [`modelRoles`](/embed/setup/url-parameters/modelRoles), [`customTheme`](/embed/setup/url-parameters/customTheme), [`uiSettings`](/embed/setup/url-parameters/uiSettings), and [`groups`](/embed/setup/url-parameters/groups) - must be stringified and then URL encoded, like every other parameter in the URL. For example, this JSON-valued parameter: ```json wrap theme={null} userAttributes={"country":"Townsville"} ``` Must be stringified and then URL encoded: ```markdown wrap theme={null} userAttributes=%7B%22country%22%3A%22Townsville%22%7D ``` ## Manually generate a v0 signed URL To generate the signature: Concatenate the required properties, delimited by a newline character **in the exact order enumerated below**. **Note**: The properties are in alphabetical order, with the exception of the leading login URL: ```text theme={null} login URL contentPath externalId name nonce ``` Concatenate the optional properties in alphabetical order, delimited by a newline character **in the exact order enumerated below**: ```markdown highlight={12} theme={null} accessBoost connectionRoles customTheme customThemeId email entity entityAiCreditLimit entityFolderContentRole entityFolderGroupContentRole entityFolderLabel entityGroupLabel filterSearchParam // must be URI encoded groups linkAccess mode modelRoles prefersDark preserveEntityFolderContentRole theme timezone uiSettings userAttributes ``` **Do not include leading or trailing spaces. Include only a single newline between each part of the signature.** The following example includes optional parameters for custom theme, entity, filter search param, prefers dark, link access, theme, and user attributes: ```text wrap theme={null} https://example.embed-omniapp.co/embed/login /dashboards/123abc luke@example.com Luke Skywalker hN38NgtnV2B3PMILhKQOpwLyJRP4qVv4 {"dashboard-background":"#00FF00","dashboard-tile-title-font-size":"1.5rem"} Acme Corp f--users.country=%7B"kind"%3A"EQUALS"%2C"type"%3A"string"%2C"values"%3A%5B"USA"%5D%2C"is_negative"%3Afalse%7D&f--users.state=%7B"kind"%3A"EQUALS"%2C"type"%3A"string"%2C"values"%3A%5B%5D%2C"is_negative"%3Afalse%7D&f--inventory_items.cost=%7B"kind"%3A"GREATER_THAN"%2C"type"%3A"number"%2C"values"%3A%5B"20"%5D%2C"is_negative"%3Afalse%2C"is_inclusive"%3Afalse%7D true __omni_link_access_open vibes {"planet": "tatooine"} ``` Refer to the [Embed parameters reference](/embed/setup/url-parameters) for more information about available parameters. Sign the string using your secret key with an HMAC sha256 digest algorithm, encoded as a base64url string: ```javascript wrap title="Node.js example" theme={null} const hmac = crypto.createHmac("sha256", secret); hmac.update(data); return hmac.digest("base64url"); ``` Refer to [the Base64 spec](https://datatracker.ietf.org/doc/html/rfc4648#page-7) for more information about base64url. URL encode each parameter as part of a URL query string and attach the generated signature. The order of parameters is irrelevant when generating the login URL. ```shell wrap theme={null} https://blobsrus.embed-omniapp.co/embed/login?contentPath=%2Fembed%2Fdashboards%2F123abc&externalId=luke%40example.com&name=Luke%20Skywalker&nonce=hN38NgtnV2B3PMILhKQOpwLyJRP4qVv4&entity=Acme+Corp&theme=vibes&userAttributes=%7B%22planet%22%3A%22tatooine%22%7D&filterSearchParam=f--order_items.status%3D%257B%22kind%22%253A%22EQUALS%22%252C%22type%22%253A%22string%22%252C%22topic%22%253A%22order_items%22%252C%22values%22%253A%255B%22Returned%22%255D%252C%22base_view%22%253A%22order_items%22%252C%22is_negative%22%253Afalse%257D&linkAccess=__omni_link_access_open&prefersDark=true&customTheme=%7B%22dashboard-background%22%3A%22%2300FF00%22%2C%22dashboard-tile-title-font-size%22%3A%221.5rem%22%7D&signature=rpf-YbMMTd2XzO_HRyP1E_RiYpQYqBkU-X9iUMplEz4 ``` ## Next steps * [Setting up embed standard SSO with the v1 signed payload format](/embed/setup/standard-sso/latest) * [Embed parameters reference](/embed/setup/url-parameters) # Testing embed URL parameters with the URL builder Source: https://docs.omni.co/embed/setup/test-urls Use the embed URL builder to test and generate embed URLs for internal use. The embed URL builder is a tool within Omni that helps you generate and test embed URLs. While primarily designed for internal embedding scenarios (such as embedding Omni in Notion), you can also use it to validate the format of your [URL parameters](/embed/setup/url-parameters). ## Requirements To use the embed URL builder, you need: * **Organization Admin** permissions * The **Embed** feature enabled in your Omni instance * An embed secret generated in **Settings > Embed > Admin** ## Using the URL builder To generate an embed URL using the URL builder: 1. Navigate to **Settings > Embed > URL Builder** in your Omni instance. 2. Fill in the required fields: * [Content Path](/embed/setup/url-parameters/contentPath) * [External ID](/embed/setup/url-parameters/externalId) * [Name](/embed/setup/url-parameters/name) 3. Optionally, fill in any additional [URL parameters](/embed/setup/url-parameters) based on your embedding needs. 4. Click **Generate URL** to create your signed embed URL. 5. Use the generated URL to test your embed configuration. ### Wildcard vanity domains If your organization has configured a wildcard [vanity domain](/embed/customization/vanity-domains) (e.g., `*.omni.example.com`), the URL builder will display a **Host** field. This field is required when using wildcard domains: 1. Enter a specific hostname that matches your wildcard pattern (e.g., `tenant1.omni.example.com`). 2. The hostname will be validated against your configured wildcard domain pattern. 3. Invalid hostnames that don't match the pattern will be rejected with an error message. The **Host** field only appears when you have a wildcard vanity domain configured. For standard vanity domains, the host is already specified in your domain configuration. ## Next steps * Learn about all available [URL parameters](/embed/setup/url-parameters) * Set up [custom vanity domains](/embed/customization/vanity-domains) for your embeds # Setting up embed with 2-step SSO Source: https://docs.omni.co/embed/setup/two-step-sso Set up 2-step SSO for Omni embedding using a POST request to generate a session token, then redeem it via a login URL. In this guide, we'll walk you through setting up **2-step SSO** for Omni embed. Rather than performing an SSO embed login via a single login URL, the 2-step login flow divides the process into 2 steps: 1. Generate an SSO embed user and session via `POST` request, returning a session token to be redeemed at a later time 2. Redeem the generated session token and redirect to the specified content via a login URL While the standard SSO embed experience is more straightforward, there a few reasons you might opt to use the 2-step SSO embed login flow over standard login URLs: * **Sensitive user data**: If using the `userAttributes` parameter with sensitive user data, you may prefer creating SSO embed users and sessions via `POST` request for added security. * **URL length**: While generally unlikely, there is more risk of standard SSO embed URLs exceeding a browser's URL character limit. 2-step login URLs are more compact and thus have no risk of hitting the limit. ## Requirements To follow the steps in this guide, you'll need: * **Organization Admin** permissions * To have the **Embed** feature enabled in your Omni instance 1. Navigate to **Settings > Embed > Admin** in your Omni instance. 2. Click the **Add Secret** button below the secrets table. 3. In the dialog that appears: * A 32-character secret key is automatically generated for you * Enter a descriptive **Name** to identify the secret's purpose (e.g., "Production", "Staging", or "Partner Integration") Use descriptive names for your secrets to make them easier to identify and manage, especially when rotating secrets or managing multiple environments. 4. Click **Add secret** to save the new secret. This step is optional. In the **Embed** settings of your Omni instance, you can also customize the length of embed sessions using the **Session Length** setting. In this field, enter the number of hours you want sessions to last and click **Change**. As with all other API endpoints, an `Authorization` header with an Omni API key as a `Bearer` token is necessary for authentication purposes. Refer to the [API docs](/api/authentication) for more information. You can also use the `createSessionToken` function in the [TypeScript SDK](https://www.npmjs.com/package/@omni-co/embed) to complete this step. In this step, you'll generate the embed user and session. This is done by sending a `POST` request to the `/api/unstable/embed/sso/generate-session` endpoint. This will return a token that will be redeemed later. Most parameters listed in the [Embed parameters reference](/embed/setup/url-parameters) can be passed in the JSON body of the request. The only exceptions are: * [`theme`](/embed/setup/url-parameters/theme) and [`prefersDark`](/embed/setup/url-parameters/prefersDark), which can be set via URL parameters in the login URL, and * [`nonce`](/embed/setup/url-parameters/nonce), which isn't necessary at this step Like the standard SSO login flow, [`contentPath`](/embed/setup/url-parameters/contentPath), [`externalId`](/embed/setup/url-parameters/externalId), and [`name`](/embed/setup/url-parameters/name) are required. ```json wrap title="POST /api/unstable/embed/sso/generate-session" theme={null} curl -X POST 'https://test.blobsrus.com/api/unstable/embed/sso/generate-session' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "contentPath": "/my", "externalId": "artiste1322", "name": "Blob Ross", "connectionRoles": { "abcd1234-abcd-efgh-ijkl-abcdef123456": "RESTRICTED_QUERIER" }, "entity": "Happy Trees", "entityFolderContentRole": "EDITOR" }' ``` Once a successful request is made, a few things will happen: * The endpoint will return a JSON payload with a single `sessionId` property. This `sessionId` will be used in the next step during session redemption. * An embed user will be upserted into your organization based on the request body's values. * An embed session will be created for this embed user with a 5 minute expiry. For security purposes, if the session isn't redeemed within 5 minutes of creation, the session will no longer be usable. If using the TypeScript SDK `redeemSessionToken` function, the signature will be automatically generated and included in the returned session redemption URL. This works the same on every SDK version - the [v1 signed payload format](/embed/setup/standard-sso/latest) applies only to standard SSO login URLs, not session redemption. Signatures are generated using the request URL and URL parameters. To generate the signature, the following steps must be followed exactly: 1. Concatenate the required properties, delimited by a newline character in the exact order enumerated below. **Note**: The parameters are in alphabetical order, with the exception of the leading login URL: ```markdown theme={null} login URL nonce sessionId ``` 2. Concatenate the optional properties in alphabetical order, delimited by a newline character. **Omit any undefined properties**. ```markdown theme={null} prefersDark theme ``` **Do not include leading or trailing spaces. Include only a single newline between each part of the signature.** The following example includes optional parameters for custom theme, entity, filter search param, prefers dark, link access, theme, and user attributes: ```shell wrap theme={null} https://example.embed-omniapp.co/embed/sso/redeem-session XxDcs01bnenbOyJTNAAUHheXRVFTVDOA abcd1234-abcd-efgh-ijkl-abcdef123456 false vibes ``` 3. Sign the string using the **Embed secret** you created in step 1 with an HMAC sha256 digest algorithm, encoded as a base64url string. Refer to [this standard](https://datatracker.ietf.org/doc/html/rfc4648#page-7) for more information about base64url. ```javascript wrap title="Node.js example" theme={null} const hmac = crypto.createHmac("sha256", secret); hmac.update(data); return hmac.digest("base64url"); ``` You can also use the `redeemSessionToken` function in the [TypeScript SDK](https://www.npmjs.com/package/@omni-co/embed) to complete this step. With the `sessionId`, you can now create a 2-step session redemption URL. Like standard SSO embed login URLs, session redemption URLs should be passed into the `src` attribute of an `iframe` HTML element. In addition, 2-step SSO embed login URLs must be signed using the request host, a nonce, and other [URL parameters](/embed/setup/url-parameters). You'll use the signature you generated in the previous step to sign the embed login URL. * **Required URL parameters**: * Session ID (`sessionId`) * Nonce ([`nonce`](/embed/setup/url-parameters/nonce)) * Signature (`signature`) * **Optional URL parameters**: * Prefers dark ([`prefersDark`](/embed/setup/url-parameters/prefersDark)) * Theme ([`theme`](/embed/setup/url-parameters/theme)) ```shell wrap title="Example URL" theme={null} https://test.embed-blobsrus.com/embed/sso/redeem-session?prefersDark=false&theme=vibes&nonce=XxDcs01bnenbOyJTNAAUHheXRVFTVDOA&sessionId=abcd1234-abcd-efgh-ijkl-abcdef123456&signature=7Gk9LmN2oP3QrStUvWxYzA1BcDeFgHiJkLmNoPqRsTu ``` Once the URL is passed into an `iframe` and a successful session redemption request is made, the following will happen: * The associated embed session will update its expiry from 5 minutes to **24 hours**, or to the custom **Session Length** specified in the **Admin > Embed** section of your Omni organization. * The iframe will redirect to the [`contentPath`](/embed/setup/url-parameters/contentPath) specified during session generation. # accessBoost Source: https://docs.omni.co/embed/setup/url-parameters/accessBoost Enables AccessBoost for the embedded dashboard. If `true`, [AccessBoost](/share#access-warnings) will be enabled for the embedded dashboard. In the **Embed URL Builder**, this is the **Access Boost** field. ## Requirements Embed users can provision AccessBoost when both of the following organization settings are enabled: * **AccessBoost** is enabled in **Settings > Content permissions** * **Non-administrators can enable AccessBoost on content** is enabled in **Settings > Content permissions** ## Syntax ```markdown theme={null} accessBoost= ``` ## Properties Set to `true` to enable AccessBoost, or `false` to disable it. ## Examples ```markdown title="Enable AccessBoost" theme={null} accessBoost=true ``` # connectionRoles Source: https://docs.omni.co/embed/setup/url-parameters/connectionRoles Specifies the level of access users will have to all models associated with a connection. This parameter is not required to create valid embed requests, but Omni recommends setting it. An object of connection roles available for embed users, used to specify the level of access users will have to all models associated with the connection. To specify permissions for individual models, use the [`modelRoles`](/embed/setup/url-parameters/modelRoles) parameter. ## Syntax ```json theme={null} connectionRoles={"":"", ...} ``` ## Properties An object containing connection ID and role pairs, formatted as `"": ""`. `connection_role` values must be the name of a standard user role **or** the name of a [custom user role](/administration/users/custom-roles) that resolves to either a **Viewer** or **Restricted Querier**. * `RESTRICTED_QUERIER` - Can create new content and view workbooks and dashboards * `VIEWER` - Can only view dashboards * `` - Abilities depend on the role's included permissions Base access roles are not respected. Connection roles should be specified using this parameter or by setting group permissions on the connection in Omni and then assigning embed users to those [groups](/embed/setup/url-parameters/groups). ## Behavior When a user creates an embed session, the `connectionRoles` value on the latest request acts as the source of truth for that user's connection access. This means: * A role can be **downgraded** by a later request (e.g. from **Restricted Querier** to **Viewer**). * A role can be **removed** entirely if the later request doesn't mention the connection — either explicitly in `connectionRoles` or implicitly in the connection backing the requested [`contentPath`](/embed/setup/url-parameters/contentPath). To avoid unintentionally changing a user's access, include `connectionRoles` on every request. ## Examples In the [v1 signed payload format](/embed/setup/standard-sso/latest), send the value as JSON: ```json v1 payload wrap theme={null} connectionRoles={"65b10d2a-473b-4486-92c8-0ba628c7d1cb":"RESTRICTED_QUERIER"} ``` In the [legacy v0 format](/embed/setup/standard-sso/v0-legacy), stringify and URL encode the value before sending: ```markdown v0 (legacy) payload wrap theme={null} connectionRoles=%7B%2265b10d2a-473b-4486-92c8-0ba628c7d1cb%22%3A%22RESTRICTED_QUERIER%22%7D ``` # contentPath Source: https://docs.omni.co/embed/setup/url-parameters/contentPath Defines the starting page when the embed user logs into the iframe. This parameter is **required** to create valid embed requests. In the **Embed URL Builder**, this is the **Content path** field. ## Syntax ```markdown theme={null} contentPath= ``` ## Properties The URL-encoded path to the starting page. Click the following toggles to view examples for each of the pages you can use as a starting page. If the starting content path is a dashboard or app path, Omni provides a 24 hour `VIEWER` content permit to that content for that user. ```markdown title="/dashboards/" theme={null} contentPath=%2Fdashboards%2Fa6908f35 ``` Refer to [Embedding apps](/visualize-present/apps#embedding-apps) for details. ```markdown title="/apps/" theme={null} contentPath=%2Fapps%2Fa6908f35 ``` ```markdown title="/w//duplicate" theme={null} contentPath=%2Fw%2Fa6908f35%2Fduplicate ``` ```markdown title="/apps/" theme={null} contentPath=%2Fapps%2Fa6908f35 ``` In this example, a [`connectionRoles`](/embed/setup/url-parameters/connectionRoles) parameter was also provided to associate the chat with a specific connection (`MD2`) and its models: ```markdown title="/my" theme={null} contentPath=%2Fmy ``` An `entity` parameter is required when `/entity-folder` is used as the `contentPath`. By default, the `entity` value will be used to create the entity folder. To provide a different name for the folder, use the [`entityFolderLabel`](/embed/setup/url-parameters/entityFolderLabel) parameter. ## Examples ```markdown title="Dashboard path" theme={null} contentPath=%2Fdashboards%2Fa6908f35 ``` ```markdown title="Workbook path" theme={null} contentPath=%2Fw%2Fa6908f35%2Fduplicate ``` ```markdown title="App path" theme={null} contentPath=%2Fapps%2Fa6908f35 ``` ```markdown title="My Documents path" theme={null} contentPath=%2Fmy ``` # customTheme Source: https://docs.omni.co/embed/setup/url-parameters/customTheme Defines custom theme properties for styling embedded dashboards. Defines custom theme properties for styling embedded dashboards. In the **Embed URL Builder**, this is the **Custom theme** field. ## Syntax ```json wrap theme={null} customTheme={"":"", "":""...} ``` ## Properties An object containing theme properties and their values. Values must be a valid [theme property](/embed/customization/themes). ## Examples In the [v1 signed payload format](/embed/setup/standard-sso/latest), send the value as JSON: ```json v1 payload wrap theme={null} customTheme={"dashboard-background":"blue"} ``` In the [legacy v0 format](/embed/setup/standard-sso/v0-legacy), stringify and URL encode the value before sending: ```markdown v0 (legacy) payload wrap theme={null} customTheme=%7B%22dashboard-background%22%3A%22blue%22%7D ``` # customThemeId Source: https://docs.omni.co/embed/setup/url-parameters/customThemeId Specifies the custom theme to use in the resulting embed session. Used to apply your own custom styles. To use a default Omni theme, use the [`theme`](/embed/setup/url-parameters/theme). In the **Embed URL Builder**, this is the **Custom theme ID** field. ## Syntax ```markdown theme={null} customThemeId= ``` ## Properties A valid theme ID from your Omni instance. ## Examples ```markdown wrap title="Example customThemeId" theme={null} customThemeId=abcdefgh-ijkl-mnop-qrst-123456789123 ``` # email Source: https://docs.omni.co/embed/setup/url-parameters/email Populates the from email for entity users when sharing content or sending deliveries. In the **Embed URL Builder**, this is the **Email** field. ## Syntax ```markdown theme={null} email= ``` ## Properties A valid email address for the embed user. ## Examples ```markdown title="Example email" theme={null} email=blobby17%40blobsrus.com ``` ## Effect on email-only users When this parameter is set, Omni checks for any existing [email-only users](/administration/users/email-only) with a matching email. If a match is found, Omni automatically transfers the email-only user's schedule recipients to the embed user and removes the email-only membership. This happens on embed login. After the merge, [personalized deliveries](/share/deliveries/email#email-settings) use the embed user's attributes instead of the email-only user's defaults — which is important when [access filters](/modeling/topics/parameters/access-filters) are in use. Set this parameter for any embed user who is also a delivery recipient. Without it, Omni creates a separate email-only user for that address with default attribute values. # entity Source: https://docs.omni.co/embed/setup/url-parameters/entity Defines a user group identifier used to associate the resulting embed user with a larger group. This parameter also creates the shared entity folder, using the name set in the value. Entity name has a 64 character limit. In the **Embed URL Builder**, this is the **Embed entity** field. ## Syntax ```markdown theme={null} entity= ``` ## Properties An alphanumeric identifier for the user group. ## Examples ```markdown title="Example entity" theme={null} entity=Blobs+R+Us ``` # entityAiCreditLimit Source: https://docs.omni.co/embed/setup/url-parameters/entityAiCreditLimit Sets an AI credit limit for the embed user's entity group at login. Sets an AI credit limit for the embed user's entity group at login. ## Requirements An [`entity`](/embed/setup/url-parameters/entity) parameter must be provided in the generated URL for this parameter to have an effect. If `entityAiCreditLimit` is provided without an `entity`, the login will fail with a missing-entity error. ## Syntax ```markdown theme={null} entityAiCreditLimit= ``` ## Properties Sets an AI credit limit for the entity group at login. Accepted values: * A whole number to set a credit cap (e.g., `40`) * The string `"unlimited"` to explicitly remove any credit cap * Omit the parameter to remove the override and fall back to the [organization's embed entity group default](/embed/admin/ai-credits#embed-entity-default) ## Examples Set `entityAiCreditLimit` to a number to cap the entity group's AI credit usage: ```markdown theme={null} entityAiCreditLimit=50 ``` Set `entityAiCreditLimit` to `unlimited` to allow the entity group to use unlimited credits: ```markdown theme={null} entityAiCreditLimit=unlimited ``` To remove an entity group's credit limit override, omit the `entityAiCreditLimit` parameter from the embed URL. This will remove the group-specific setting and apply the [organization's embed entity group default](/embed/admin/ai-credits#embed-entity-default) instead. ## Next steps * [Managing AI credits for embed entity groups](/embed/admin/ai-credits) — Learn about entity group credit limits, defaults, and monitoring * [Managing AI credit usage](/ai/settings/usage) - Learn about organization and user-level credit limits defaults # entityFolderContentRole Source: https://docs.omni.co/embed/setup/url-parameters/entityFolderContentRole Specifies the content role the embed user will be given to their shared entity folder. In the **Embed URL Builder**, this is the **Entity folder content role** field. ## Syntax ```markdown theme={null} entityFolderContentRole= ``` ## Properties The content role for the user. Value must be one of: * `VIEWER` - Can see content in the shared folder, but cannot save content into it * `EDITOR` - Can see and save content into the shared folder * `MANAGER` - Can see and save content into the shared folder and manage other users' permissions * `NO_ACCESS` - Cannot see content in the top-level shared folder. **Note**: It is still possible for the group to have access to subfolders by assigning content permits directly in the UI. ## Examples ```markdown title="Example entityFolderContentRole" theme={null} entityFolderContentRole=EDITOR ``` # entityFolderGroupContentRole Source: https://docs.omni.co/embed/setup/url-parameters/entityFolderGroupContentRole Specifies the content role the embed entity group will be given to their shared entity folder. If unspecified, an entity group will have `VIEWER` access to their shared entity folder. In the **Embed URL Builder**, this is the **Entity folder group content role** field. ## Syntax ```markdown theme={null} entityFolderGroupContentRole= ``` ## Properties The content role for the entity group. Value must be one of: * `VIEWER` - Can see content in the shared folder, but cannot save content into it * `EDITOR` - Can see and save content into the shared folder * `MANAGER` - Can see and save content into the shared folder and manage other users' permissions * `NO_ACCESS` - Cannot see content in the top-level shared folder. Note that it is still possible for the group to have access to subfolders by assigning content permits directly in the UI. ## Examples ```markdown title="Example entityFolderGroupContentRole" theme={null} entityFolderGroupContentRole=MANAGER ``` # entityFolderLabel Source: https://docs.omni.co/embed/setup/url-parameters/entityFolderLabel Updates the embed user's associated entity folder label. In the **Embed URL Builder**, this is the **Entity folder label** field. ## Requirements An [`entity`](/embed/setup/url-parameters/entity) must be provided in the generated URL for this parameter to have an effect. ## Syntax ```markdown theme={null} entityFolderLabel=
In this example, Mustache tags create a dynamic y-axis label that displays summary values and filter details. ```handlebars wrap theme={null} Order Count ({{result._totals.0.order_items.order_count.value}} Total Orders in {{result.0.users.state.value}}) ```
## Available tags Refer to the [Mustache reference](/visualize-present/mustache-reference) for a complete list of the tags Omni currently supports. ## Escaping All tags are escaped by default. This means that text enclosed in `{{}}` will always render, even if you intend to just display the curly braces themselves. To return raw contents without escaping, add an extra curly brace: ```handlebars theme={null} {{{ variable }}} ``` To escape the curly braces and have them render, use backslashes: ```handlebars theme={null} \{\{variable\}\} ``` For more specifics on syntax and gotchas, refer to the [Mustache docs](https://mustache.github.io/mustache.5.html). # Visualize & present Source: https://docs.omni.co/visualize-present/index Turn query results into charts, build interactive dashboards, and use AI to surface insights from your data. Once you've [queried your data](/analyze-explore/querying), Omni provides tools to visualize results, assemble dashboards, and present insights to your team. This section covers everything from chart configuration to dashboard design and management. ## Chat with Content [Chat with Content](/ai/dashboard-assistant) brings conversational AI directly into your content. Ask follow-up questions, drill into subsets, summarize results, or request new analyses — all without leaving the page. ## Visualize data Omni includes a library of [built-in chart types](/visualize-present/visualizations/types) — bar, line, area, scatter, funnel, KPI, map, and more. Each chart supports [configuration options](/visualize-present/visualizations/configuration/color) for color, axes, series mapping, tooltips, and sizing. For advanced use cases, you can edit the underlying [Vega-Lite spec](/visualize-present/visualizations/types/custom) directly. You can also use AI to [generate visualizations](/ai/visualizations) from your query results. ## Design dashboards [Dashboards](/visualize-present/dashboards) are the presentation layer for your workbooks, displaying multiple queries as an interactive collection of tiles. Dashboards support: * **[Chart and table tiles](/visualize-present/dashboards/charts)** — Display query results as visualizations or tables * **[Text and Markdown tiles](/visualize-present/dashboards/text-markdown)** — Add context, headers, and documentation * **[Filters](/visualize-present/dashboards/filters)** and **[controls](/visualize-present/dashboards/controls)** — Let viewers interact with the data * **[Dynamic content](/visualize-present/dynamic-content)** — Use Mustache syntax to personalize dashboards for each viewer * **[Theming](/visualize-present/dashboards/theming)** — Apply custom themes to match your organization's branding ## Manage dashboards Once your dashboard is built, Omni provides tools to keep it running well: * **[Dashboard settings](/visualize-present/dashboards/settings)** — Configure refresh behavior, default filters, and document-level options * **[Performance profiler](/visualize-present/dashboards/performance-profiler)** — Identify slow queries and optimize load times * **[Download](/visualize-present/dashboards/download)** and **[migrate](/visualize-present/dashboards/migrate)** dashboards as needed ## Apps BETA When a dashboard's grid of tiles isn't expressive enough, [apps](/visualize-present/apps) let you build a fully custom, interactive interface — a calculator, a leaderboard, a guided tool — backed by live, governed queries from your workbook. Describe what you want to the [Omni Agent](/ai/chat) and it builds the app for you. The data stays inspectable and tunable in the workbook, just like every other surface in Omni. # Mustache cheatsheet Source: https://docs.omni.co/visualize-present/mustache-cheatsheet Quick reference for Omni's supported Mustache tags For detailed information, refer to the [Mustache syntax reference](/visualize-present/mustache-reference). Returns [query metadata](/visualize-present/mustache-reference#query-metadata). Supported only in dashboard Markdown tiles. | Returns | Syntax | | ----------------- | ---------------------------------- | | Query name | `{{queries.query_id.name}}` | | Query subtitle | `{{queries.query_id.subtitle}}` | | Query description | `{{queries.query_id.description}}` | | Query topic name | `{{queries.query_id.topicName}}` | | Query created at | `{{queries.query_id.createdAt}}` | | Query updated at | `{{queries.query_id.updatedAt}}` | Returns metadata about a [query field](/visualize-present/mustache-reference#query-fields). Supported in Markdown visualizations. | Returns | Syntax | | ----------------- | --------------------------------------------- | | View name | `{{fields.view_name.field_name.view_label}}` | | Field name | `{{fields.view_name.field_name.label}}` | | Field description | `{{fields.view_name.field_name.description}}` | Returns a value from [query results](/visualize-present/mustache-reference#query-results). Supported in Markdown visualizations. | Returns | Syntax | | ------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | First row | `{{result._first.view_name.field_name.value_type}}` | | Last row | `{{result._last.view_name.field_name.value_type}}` | | Specific row | `{{result.row_number.view_name.field_name.value_type}}` | | Column total | `{{result._total.first.view_name.field_name.value_type}}` | | Row total | `{{result.row_number.row_total.view_name.field_name.value_type}}` | | Grand total | `{{result.totals._first.row_total.view_name.field_name.value_type}}` | | [Pivot column iteration](/visualize-present/mustache-reference#pivot-iteration) | `{{#result._pivots}}...{{/result._pivots}}` | | [Pivot row iteration](/visualize-present/mustache-reference#pivot-iteration) | `{{#row._pivots}}...{{/row._pivots}}` | **Value types:** `value` (interactive), `value_static` (formatted), `raw` (plain) Returns metadata about [filters](/visualize-present/mustache-reference#filters). Supported in Markdown tiles. **Dashboard filters** use the filter ID: | Returns | Syntax | | ----------------- | ----------------------------------------- | | Label | `{{filters.filter_id.label}}` | | Summary | `{{filters.filter_id.summary}}` | | Value | `{{filters.filter_id.value}}` | | URL-encoded value | `{{filters.filter_id.value_url_encoded}}` | | JSON | `{{filters.filter_id.json}}` | **Workbook filters** use the view and field name: | Returns | Syntax | | ----------------- | ---------------------------------------------------- | | Label | `{{filters.view_name.field_name.label}}` | | Summary | `{{filters.view_name.field_name.summary}}` | | Value | `{{filters.view_name.field_name.value}}` | | URL-encoded value | `{{filters.view_name.field_name.value_url_encoded}}` | | JSON | `{{filters.view_name.field_name.json}}` | Returns metadata about [dashboard controls](/visualize-present/mustache-reference#controls). Supported in Markdown tiles. | Returns | Syntax | | ----------------- | ------------------------------------------- | | Label | `{{controls.control_id.label}}` | | Summary | `{{controls.control_id.summary}}` | | Value | `{{controls.control_id.value}}` | | URL-encoded value | `{{controls.control_id.value_url_encoded}}` | | JSON | `{{controls.control_id.json}}` | Returns [dashboard metadata](/visualize-present/mustache-reference#dashboard-metadata). Supported in Markdown tiles. | Returns | Syntax | | --------------- | ---------------------------- | | Created at | `{{metadata.createdAt}}` | | Created by | `{{metadata.createdBy}}` | | Last updated at | `{{metadata.lastUpdatedAt}}` | Returns [user attribute data](/visualize-present/mustache-reference#user-attribute-metadata). Supported in Markdown tiles. | Returns | Syntax | | ---------------- | --------------------------------------------------------- | | User email | `{{metadata.userAttributes.omni_user_email.element}}` | | User name | `{{metadata.userAttributes.omni_user_name.element}}` | | User ID | `{{metadata.userAttributes.omni_user_id.element}}` | | Is org admin? | `{{metadata.userAttributes.omni_is_org_admin.element}}` | | User groups | `{{metadata.userAttributes.omni_user_groups.element}}` | | Custom attribute | `{{metadata.userAttributes.attribute_reference.element}}` | **Elements:** `label` (display name), `values` (attribute value) Returns [query and user attribute metadata](/visualize-present/mustache-reference#query-and-user-attribute-inspection) as JSON. Supported in Markdown visualizations. ```handlebars theme={null} {{inspect}} ``` # Mustache syntax reference Source: https://docs.omni.co/visualize-present/mustache-reference Complete reference for Mustache template syntax in Omni, including tags, keys, sections, and dynamic content for dashboards. In Mustache, a **tag** is indicated by double mustaches, for example `{{results}}`. A tag is made up of one or more **keys**, which are used to find the requested data. In the previous example, `results` is the key in `{{results}}`. Check out the [Cheatsheet](/visualize-present/mustache-cheatsheet) for a high-level summary of all Omni's currently-supported tags. ## Locating keys Several Omni tags require specific keys, such as a `view_name` or a `field_name`. Refer to the following sections for help finding this information in Omni. ### view\_name and field\_name The `view_name` and `field_name` keys are used in [Query field](#query-fields) and [Query result](#query-results) tags. To locate the name of a view or field in a query: 1. Enter **draft** mode in a workbook. 2. In the tab of the query, open the **Results** panel. 3. In the **Fields** section, locate a field and click the (caret) icon. Below the **Label** field will be the name of the view and the field. In the example image (click to enlarge), this is `main__customers.id`. `main__customers` is the `view_name`, and `id` is the `field_name`. Using the query results panel to locate the names of a view and field ### control\_id and filter\_id The `control_id` and `filter_id` keys are used in [Control](#controls) and [Filter](#filters) tags for dashboards. To locate the ID of a dashboard control or filter: 1. Enter **draft** mode in a dashboard. 2. Locate the control or filter at the top of the dashboard and click the (pencil) icon to open the **Edit** panel. 3. Locate the **ID** field at the bottom of the panel. In the example image, the ID is `8v_G12D7`. Highlighted ID value in the Edit control panel Control and filter IDs are configurable. To change an ID, edit the **ID** field in the control or filter's **Edit** panel. You'll have to update existing references - Omni won't automatically do this when you change the ID. ## Query metadata Query metadata tags are only supported in [dashboard Markdown tiles](/visualize-present/dashboards/text-markdown). Use the **Variables** menu ( icon) in the Markdown editor to quickly insert fully-formed variables. Returns metadata about a query. ```handlebars title="Syntax" theme={null} {{queries.query_id.element}} ``` Requires the following keys: Accesses query metadata The ID of the query. This will be an integer, such as `4`. The data you want to retrieve, such as the name of the query. Refer to the following sections for information on what is currently supported. ### Query name Returns the name of the query. ```handlebars title="Syntax" theme={null} {{queries.query_id.name}} ``` ```handlebars title="Example" theme={null} {{queries.4.name}} ``` ### Query subtitle Returns the subtitle of the query. ```handlebars title="Syntax" theme={null} {{queries.query_id.subtitle}} ``` ```handlebars title="Example" theme={null} {{queries.4.subtitle}} ``` ### Query description Returns the description of the query. ```handlebars title="Syntax" theme={null} {{queries.query_id.description}} ``` ```handlebars title="Example" theme={null} {{queries.4.description}} ``` ### Query topic name Returns the name of the topic used in the query. ```handlebars title="Syntax" theme={null} {{queries.query_id.topicName}} ``` ```handlebars title="Example" theme={null} {{queries.4.topicName}} ``` ### Query created date Returns the date the query was created. ```handlebars title="Syntax" theme={null} {{queries.query_id.createdAt}} ``` ```handlebars title="Example" theme={null} {{queries.4.createdAt}} ``` ### Query updated date Returns the date the query was last updated. ```handlebars title="Syntax" theme={null} {{queries.query_id.updatedAt}} ``` ```handlebars title="Example" theme={null} {{queries.4.updatedAt}} ``` ## Query fields Query field tags are only supported in visualizations, meaning they can't be used in [Markdown dashboard tiles](/visualize-present/dashboards/text-markdown). Returns metadata about a specific query field. ```handlebars title="Syntax" theme={null} {{fields.view_name.field_name.element}} ``` Requires the following keys: Accesses query field data The name of the view that contains the field The name of the field The data you want to retrieve, such as the display name of the field. Refer to the following sections for information on what is currently supported. ### View name Returns the display name of the view that contains the specified field. ```handlebars title="Syntax" theme={null} {{fields.view_name.field_name.view_label}} ```
```handlebars title="Input" theme={null} {{fields.customers.id.view_label}} ```
Example view name
### Field name Returns the display name of the field. ```handlebars title="Syntax" theme={null} {{fields.view_name.field_name.label}} ```
```handlebars title="Input" theme={null} {{fields.customers.id.label}} ```
Example field name
### Field description Returns the [description](/modeling/dimensions/parameters/description) of the field as defined in the model. ```handlebars title="Syntax" theme={null} {{fields.view_name.field_name.description}} ``` ```handlebars title="Example" theme={null} {{fields.customers.lifetime_value.description}} ``` ## Query results Query result tags are only supported in visualizations, meaning they can't be used in [Markdown dashboard tiles](/visualize-present/dashboards/text-markdown). Returns a result value from a query. The syntax varies depending on the data point you want to retrieve, but typically looks like the following: ```handlebars title="Syntax" theme={null} {{result.data_point.view_name.field_name.value_type}} ``` The following keys must always be provided, regardless of the data point being retrieved: Accesses query result data The type of data point you want to retrieve, such as the value of a field in the first row of query results (`_first`). Refer to the following sections for information on what's currently supported. The name of the view that contains the field The name of the field. Refer to the [Locating keys section](#view_name-and-field_name) for help finding this and the `view_name`. Determines the level of interactivity and formatting of the returned value: * `value` - Interactive; user can click to copy, drill, etc. * `value_static` - Formatting applied, no interactivity * `raw` - No formatting or interactivity ### First row value Returns the first value in the result set for the specified field. ```handlebars title="Syntax" theme={null} {{result._first.view_name.field_name.value_type}} ``` This example uses `value_static`, which returns a formatted value with no interactivity:
```handlebars title="Input" theme={null} {{result._first.customers.first_name.value_static}} ```
Example first row value
### Last row value Returns the last value in the result set for the specified field. ```handlebars title="Syntax" theme={null} {{result._last.view_name.field_name.value_type}} ``` This example uses `value`, which allows dashboard users to click and interact with the value. Note the dropdown menu over the value in the example image.
```handlebars title="Input" theme={null} {{result._last.customers.first_name.value}} ```
Example last row value
### Specific row value Returns a field value from the specified row (`row_number`) in the result set. In Omni, row numbering begins at 0. When you define the variable, subtract **one** from the number of the actual row you want to reference. ```handlebars title="Syntax" theme={null} {{result.row_number.view_name.field_name.value_type}} ``` For example, to return a value from row `11`, use `10` as the `row_number`:
```handlebars title="Input" theme={null} {{result.10.customers.first_name.raw}} ```
Example specific row value
### Column total Returns the total of a specified column in the result set. Requires [**Column totals**](/analyze-explore/point-click-queries#column-totals) to be enabled in the query's **Results options** panel. ```handlebars title="Syntax" theme={null} {{result._total.first.view_name.field_name.value_type}} ```
```handlebars title="Input" theme={null} {{result._total.first.customers.total_price_sum.value}} ```
Example column total
### Row total Returns the total of a specified row (`row_number`) in a **pivoted** result set. Requires a query with at least one pivot and for [**Row totals**](/analyze-explore/point-click-queries#row-totals) to be enabled in the query's **Results options** panel. In Omni, row numbering begins at 0. When you define the variable, subtract **one** from the number of the actual row you want to reference. ```handlebars title="Syntax" theme={null} {{result.row_number.row_total.view_name.field_name.value_type}} ``` For example, to return values from row `6`, use `5` as the `row_number`: ```handlebars title="Example" theme={null} {{result.5.row_total.order_items.sale_price_sum.value}} ``` ### Grand total Returns the grand total of a specified column in a **pivoted** result set. Requires a query with at least one pivot and for [**Column totals**](/analyze-explore/point-click-queries#column-totals) to be enabled in the query's **Results options** panel. ```handlebars title="Syntax" theme={null} {{result.totals._first.row_total.view_name.field_name.value_type}} ``` ```handlebars title="Example" theme={null} {{result.totals._first.row_total.customers.total_price_sum.value}} ``` ### Pivot iteration Iterates over pivot columns in a pivoted result set without hardcoding pivot values. This allows templates to work dynamically when filters change which pivot values exist. Only applies to queries with at least one [pivot](/analyze-explore/queries/pivots). Two iteration modes are available: * **Column-major** (`result._pivots`) - Iterate all pivot columns, with each entry containing all row data for that column * **Row-major** (`row._pivots`) - Iterate pivot entries within each row (used inside a `{{#result}}` loop) Both modes exclude row-total and subtotal columns, as well as the synthetic "Previous Period" alias used in period-over-period comparisons. ```handlebars title="Syntax (column-major)" theme={null} {{#result._pivots}}...{{/result._pivots}} ``` ```handlebars title="Syntax (row-major)" theme={null} {{#result}} {{#row._pivots}}...{{/row._pivots}} {{/result}} ``` Each pivot entry exposes the following keys: The pivot value as a single string, for example `Idaho` or `Female - UK` for multi-level pivots The pivot value(s) as an array. For single-level pivots, this is a one-element array. For multi-level pivots, this contains each level separately, for example `["Female", "UK"]` The row data for this pivot column. Each row's cells for this column are merged with that row's non-pivoted fields. Pivot dimension values are exposed as regular field entries (e.g., `users.state.value`) Like other result entries, pivot entries are decorated with the standard `_first`, `_second`, `_last`, and `_rows` accessors used elsewhere in Mustache templates. The keys are prefixed with underscores (`_value`, `_values`) to prevent collisions with actual field names from your data model. The following column-major example uses a query pivoted on `users.state` and grouped by `users.age`. For each pivot column, the template: 1. Renders the pivot value (`{{_value}}`) as a heading, for example `Idaho` 2. Loops through that column's rows (`{{#rows}}`) and renders each row as an `age: count` pair ```handlebars title="Example: create a section for each pivot column" theme={null} {{#result._pivots}} ### {{_value}} {{#rows}}{{users.age.value}}: {{users.count.value}} {{/rows}} {{/result._pivots}} ``` Because the template never references a specific pivot value, it renders one section per pivot column no matter which states the query returns. ## Query and user attribute inspection Query & user attribute inspection is only supported in Markdown visualizations. Returns the elements of a query and user attribute metadata in JSON format. ```handlebars title="Syntax" theme={null} {{inspect}} ``` ## Filters Returns metadata about [dashboard](/visualize-present/dashboards/filters) and workbook filters. The syntax differs depending on where the filter is located: * **Dashboard filters** use the filter's ID: `{{filters.filter_id.element}}` * **Workbook filters** use the view and field name: `{{filters.view_name.field_name.element}}` ```handlebars theme={null} {{filters.filter_id.element}} ``` ```handlebars theme={null} {{filters.view_name.field_name.element}} ``` Requires the following keys: Accesses filter data The ID of a dashboard filter. Refer to the [Locating keys section](#control_id-and-filter_id) for help finding this value. The name of the view that contains the field used in a workbook filter The name of the field used in a workbook filter. Refer to the [Locating keys section](#view_name-and-field_name) for help finding this and the `view_name`. The data you want to retrieve, such as `label`. Refer to the following section for information on what's currently supported. ### Label Returns the label of the filter. In a dashboard, open the **Edit** panel for the filter and locate the **Label** field. ```handlebars theme={null} {{filters.filter_id.label}} ``` ```handlebars theme={null} {{filters.view_name.field_name.label}} ```
```handlebars title="Input" theme={null} {{filters.customers.country.label}} ```
Example filter label
### Summary Returns the default value (summary) of the filter. In a dashboard, open the **Edit** panel for the filter and locate the **Default value** field. ```handlebars theme={null} {{filters.filter_id.summary}} ``` ```handlebars theme={null} {{filters.view_name.field_name.summary}} ```
```handlebars title="Input" theme={null} {{filters.customers.country.summary}} ```
Example filter summary
### Value Returns the current value of the filter. ```handlebars theme={null} {{filters.filter_id.value}} ``` ```handlebars theme={null} {{filters.view_name.field_name.value}} ``` ```handlebars title="Example (workbook)" theme={null} {{filters.customers.country.value}} ``` ### URL-encoded value Returns the current value of the filter, URL-encoded. Use this when you need to include filter values in URL query parameters within Markdown links. ```handlebars theme={null} {{filters.filter_id.value_url_encoded}} ``` ```handlebars theme={null} {{filters.view_name.field_name.value_url_encoded}} ``` ```handlebars title="Example (dashboard)" theme={null} [View details](https://example.com/report?country={{filters.8v_G12D7.value_url_encoded}}) ``` ### JSON Returns the URL-encoded JSON of the filter. ```handlebars theme={null} {{filters.filter_id.json}} ``` ```handlebars theme={null} {{filters.view_name.field_name.json}} ``` ```handlebars title="Example (dashboard)" theme={null} {{filters.8v_G12D7.json}} ``` ## Controls Returns metadata about [dashboard controls](/visualize-present/dashboards). ```handlebars title="Syntax" theme={null} {{controls.control_id.element}} ``` Requires the following keys: Accesses control data The ID of the control, located in the **Edit control** panel. Refer to the [Locating keys section](#control_id-and-filter_id) if you need help finding this panel. The data you want to retrieve, such as `label`. Refer to the following section for information on what's currently supported. ### Label Returns the label of the control. In a dashboard, open the **Edit** panel for the control and locate the **Label** field. ```handlebars title="Syntax" theme={null} {{controls.id.label}} ```
```handlebars title="Input" theme={null} {{controls.8v_G12D7.label}} ```
Example control label
### Summary Returns the default value (summary) of the control. In a dashboard, open the **Edit** panel for the control and locate the **Default value** field. ```handlebars title="Syntax" theme={null} {{controls.id.summary}} ```
```handlebars title="Input" theme={null} {{controls.8v_G12D7.summary}} ```
Example control summary (default value)
### Value Returns the full database name (`view_name.field_name`) of the field currently selected in the control. ```handlebars title="Syntax" theme={null} {{controls.id.value}} ```
```handlebars title="Input" theme={null} {{controls.8v_G12D7.value}} ```
Example control value
### URL-encoded value Returns the value of the control, URL-encoded. Use this when you need to include control values in URL query parameters within Markdown links. ```handlebars title="Syntax" theme={null} {{controls.id.value_url_encoded}} ``` ```handlebars title="Example" theme={null} [View details](https://example.com/report?field={{controls.8v_G12D7.value_url_encoded}}) ``` ### JSON Returns the URL-encoded JSON of the control. ```handlebars title="Syntax" theme={null} {{controls.id.json}} ``` ```handlebars title="Example" theme={null} {{controls.8v_G12D7.json}} ``` ```txt wrap title="Example output" theme={null} %7B%22id%22%3A%228v_G12D7%22%2C%22kind%22%3A%22FIELD%22%2C%22type%22%3A%22FIELD_SELECTION%22%2C%22field%22%3A%22customers.birthday%5Bdate%5D%22%2C%22label%22%3A%22Control%20(Switcher)%22%2C%22options%22%3A%5B%7B%22label%22%3A%22Birthday%20Date%22%2C%22value%22%3A%22maincustomers.birthday%5Bdate%5D%22%2C%22isDimension%22%3Atrue%7D%2C%7B%22label%22%3A%22Created%20Date%20Date%22%2C%22value%22%3A%22main__customers.created_date%5Bdate%5D%22%2C%22isDimension%22%3Atrue%7D%5D%7D ``` ## Dashboard metadata Returns metadata about the dashboard itself. Available in [Markdown dashboard tiles](/visualize-present/dashboards/text-markdown). ```handlebars title="Syntax" theme={null} {{metadata.element}} ``` Requires the following keys: Accesses Omni metadata The data you want to retrieve. Refer to the following sections for information on what's currently supported. ### Created at Returns the timestamp when the dashboard was created. ```handlebars title="Syntax" theme={null} {{metadata.createdAt}} ``` ### Created by Returns the name of the user who created the dashboard. ```handlebars title="Syntax" theme={null} {{metadata.createdBy}} ``` ### Last updated at Returns the timestamp when the dashboard was last modified. ```handlebars title="Syntax" theme={null} {{metadata.lastUpdatedAt}} ``` ## User attribute metadata Returns information about the [user attributes](/administration/users/attributes) associated with the user currently viewing the dashboard. ```handlebars theme={null} {{metadata.userAttributes.attribute_reference.element}} ``` Requires the following keys: Accesses Omni metadata Accesses Omni user attribute data The reference of the attribute you want to retrieve data for, for example `omni_user_email`. The following sections demonstrate some of the Omni system attributes you can use in tags. Refer to the **Reference** column in [**Settings > User attributes**](/administration/users/attributes) to locate an attribute's reference. The data you want to retrieve. Can be either of the following: * `label` - The display name of the attribute, for example `Omni user email` * `values` - The attribute value set for the user ### User email Returns the email address (`omni_user_email` value) of the user currently viewing the dashboard. ```handlebars title="Syntax" theme={null} {{metadata.userAttributes.omni_user_email.values}} ``` ### User name Returns the user name (`omni_user_name` value) of the user currently viewing the dashboard. ```handlebars title="Syntax" theme={null} {{metadata.userAttributes.omni_user_name.values}} ``` ### User ID Returns the user ID (`omni_user_id` value) of the user currently viewing the dashboard. ```handlebars title="Syntax" theme={null} {{metadata.userAttributes.omni_user_id.values}} ``` ### Is org admin? Returns `true` if the user currently viewing the dashboard is an [Organization Admin](/administration/users/permissions) (`omni_is_org_admin` value). Otherwise, returns `false`. ```handlebars title="Syntax" theme={null} {{metadata.userAttributes.omni_is_org_admin.values}} ``` ### Custom user attribute Returns the value of a [custom user attribute](/administration/users/attributes) of the user currently viewing the dashboard, where `custom_attribute_reference` is the **reference** of the custom attribute. ```handlebars title="Syntax" theme={null} {{metadata.userAttributes.custom_attribute_reference.values}} ``` ```handlebars title="Example" theme={null} {{metadata.userAttributes.blob_entity.values}} ``` ### User groups Returns a list of [user groups](/administration/users/groups) (`omni_user_groups` value) that the user currently viewing the dashboard is a member of. If the user is a member of more than one group, the output will be a comma-delimited list like `Group 1, Group 2`. ```handlebars title="Syntax" theme={null} {{metadata.userAttributes.omni_user_groups.values}} ``` # Color by / Stacking Source: https://docs.omni.co/visualize-present/visualizations/configuration/color Configure color-by dimensions and stacking options to create multi-series charts with distinct visual groupings in Omni workbooks. ## Color options Color sets a facet across the given data set to create individual series. Color options also include stacking controls for the visualization. There will be slightly different options for string, date, and numeric data. Strings only offer discrete bucketing, while date and numeric data will offer both discrete (nominal) and continuous (temporal or quantitative) coloring. Note also that the palette options will change for discrete vs continuous, with discrete offering diverging color palettes and continuous offering a set of gradient color palettes. When continuous options are not offered on an apparent date or numeric, casting the field may solve the problem. ## Palettes and color faceting When using color faceting, Omni automatically applies the organization's [default color palette](/administration/chart-palettes/default) to your chart, using the discrete or continuous palette appropriate to the data. In the case of discrete data, colors from the palette are automatically applied based on the sort order of the query and the color order in the palette. For continuous data, the gradient palette is automatically applied to the range of the values from the query results. Select a different option from the palette menu to update the color treatment. Use the **Reverse colors** option to reverse the order in which colors from the palette are applied to the data. With color faceting, the series **are not** independently configurable. For independent color configuration of a given series, [create separate measures](/analyze-explore/custom-fields/filtered-measures) for each series and refer to the section below on [series color controls](#series-color-controls). ### Custom palettes If one of the provided palettes doesn't quite suit your visualization needs, a custom palette can be built for an individual chart. The last option in either the continuous or discrete palette menus is a **Custom** palette option. Select this option and then click the **Customize button** next to the menu. From here you can add, remove, and edit the palette colors: Use the **Open hex code editor** button to toggle a bulk editor. This makes it easy to copy and paste a list of comma-separated hex values. Custom palettes built for individual charts can be reused by copying and pasting the hex codes from chart to chart. If you find yourself using the same custom palette repeatedly, an administrator can [add additional palettes to the organization](/administration/chart-palettes) to make it broadly available in the palette menu. ## Gradient color scale values When using a continuous gradient palette to color a visualization by a numeric field, you can pin specific values for the minimum, midpoint, and maximum of the color scale. This allows you to control exactly which data values map to which colors in the gradient, rather than always using the automatic data range. A **Scale values** row appears in the color configuration panel whenever you have a quantitative (continuous numeric) color field. You can set: * **Min** - The minimum value for the color scale. Values at or below this value will use the first color in the gradient. If left unset, defaults to the minimum value in the data. * **Mid** - The midpoint value for the color scale. This value will use the middle color in the gradient and remain within the min and max bounds. * **Max** - The maximum value for the color scale. Values at or above this value will use the last color in the gradient. If left unset, defaults to the maximum value in the data. When data values fall outside the pinned range, they are clamped to the boundary colors. For example, if you set **Max** to `100` but have data values of `150`, those values will display using the same color as the `100` value. ## Series color controls Color controls are available on a series-by-series basis when no color facet is applied (with a single measure and no color, or with multiple measures). This will offer a simple color picker for each series. You can also map a color to a specific measure when using it as a series with the [measure's `colors` parameter](/modeling/measures/parameters/colors). ## Stacking options Several stacking options are supported: * **Automatic**: Omni will attempt to select the best option from the four below * **Stack**: The series will be stacked * **Group**: The series will appear side-by-side (only offered for bar charts) * **Overlay**: The series will appear on top of each other. This is how points and lines frequently work, but rarely valuable for bar. * **Stack %**: The series will be stacked, and shown as the percentage rather than the absolute values. **Note**: The tooltip will show the raw value, not the percentage, so to add percentage it's recommended to use table calculations like `% of row`. ### Stacked segment sorting When using stacking, you can control how the stacked segments are sorted using the **Sort stack by** option. The following sorting options are available: * **Label**: Sorts segments alphabetically by dimension value. This is the default option. * **Value**: Sorts segments by their measure value within each individual stack. This option is only available for bar and column charts. * **Sum**: Sorts segments by their total sum across all stacks. This is useful when you want to see which segments contribute the most overall, regardless of their value in any individual stack. * **Unsorted**: Preserves the original data order from your query results. The **Value** sorting option is only available for bar and column charts. For area and line charts, use **Sum** to sort by total contribution or **Label** for alphabetical ordering. ## Legend options Legends can be located on the right, left, top, or bottom of the chart. They can also be hidden. ## Dimension colors Dimension color modeling isn't currently supported everywhere in the workbook. For example, dimension color mapping won't apply colors to table cells. Omni supports the ability to define consistent coloring for dimensions across visualizations, whether they're in the same document or in different documents. Using the [`colors` parameter in a dimension](/modeling/dimensions/parameters/colors), you can map a color to specific values. For example, the following image shows an example of two bar charts that include a `status` field. Notice that the bars for the `Complete` status are the same color: ### Assigning colors to dimensions in the IDE To achieve this in your own visualizations: 1. In the IDE, add the `colors` parameter to a dimension in a [view](/modeling/views) or [query view](/modeling/query-views). For example: ``` dimensions: status: order_by_field: status_order colors: conditions: # List of conditions - condition: # Required. A condition, specified using filter syntax. is: Complete color: green # Required. The color to be used in visualizations when the condition is met else: red # Optional. Specifies fallback color if no condition is met ``` Refer to the [Dimensions parameter reference](/modeling/dimensions/parameters/colors) for more information and examples. 2. In the **Chart** tab of the workbook, drag the dimension to the **Color** field: # Series configuration Source: https://docs.omni.co/visualize-present/visualizations/configuration/series-configuration Configure individual chart series in Omni, including chart type, axis assignment, label formatting, and data display options. Each series / field offers configuration in addition to the axis configuration. In this area the data itself can be controlled (vs the axis or facet like color). To configure the or generally follow the corresponding settings. To access the configuration menu, click the **caret** to the left of the `X` in either an X-axis or Y-axis field in the **Chart Options**: ## X-Axis series configuration The X-Axis configuration offers controls for the label (which mirrors the x-axis label controls). Additional configuration is available for formatting of values (number, percentage, currency, and integer) as well as number of decimals. By default series will mirror formatting in the results table (auto). ## Y-Axis series configuration The y-axis configuration will mirror the x-axis configuration with additional controls for labeling data points and trendlines. ### Visualization data labels The **Labels** tab contains configuration options for data labels, which display as values above each point in the graph. To make the labels more dense, check the **Show all labels** box. By default, points are labeled with the series in use, but can also reference other fields (ie. labeling a measure-measure XY scatterplot with data labels for the dimension). Position will move the label vis-a-vis the data point (by default overlaid). ### Trendlines / moving average / regression lines The **Analytics** tab contains configuration options for adding moving averages to charts or regression lines. **Note**: Displaying the regression formula or r-squared isn't currently supported. **For moving averages,** the trend line will mirror the order in the table when toggling between center and lagging, so for desired behavior the table may need to be resorted. **For more custom trendlines and moving averages,** it's recommended to build [calculations](/analyze-explore/calculations) in the results table. # Series mapping Source: https://docs.omni.co/visualize-present/visualizations/configuration/series-mapping Rearrange dimensions, measures, and pivots across chart axes and facets to build different visualization types from the same data. Any column (dimensions, measures, or calculations) or pivot can be re-arranged in the visualization layer. This allows for the flexible construction of many different types of visualizations over the same results table. Each facet is presented at the bottom of the visualization configuration under available fields. ### Duplicating fields across facets Fields can be used across more than one facet by dragging from available fields into the corresponding facet. Alternatively the fields can be moved by grabbing a token and changing the chart. Here are a few examples with our original query: # Size by Source: https://docs.omni.co/visualize-present/visualizations/configuration/size For scatterplots, fields can be mapped to control the size of each bubble. ## Configuration The only configuration available is showing or hiding the size legend, which will hide the circles that correspond to size at the right. Note that you may also want to hide the color by legend, which is done under color configuration. # Tooltips Source: https://docs.omni.co/visualize-present/visualizations/configuration/tooltips Customize chart tooltips in Omni by adding fields, reordering series, and controlling which data values appear on hover. Tooltips can be adjusted by dragging series from 'Available Fields' into the tooltip section. They are not required to be visualized to show in the tooltip, and will display in the order added. For control over formatting, the series can be adjusted in the table view. If no series are present in the tooltip area, tooltips will be inactive. ## Notes Tooltips can also be significantly adjusted in advanced mode using the [Vega lite spec](https://vega.github.io/vega-lite/docs/tooltip.html). # X-axis configuration Source: https://docs.omni.co/visualize-present/visualizations/configuration/x-axis To access the configuration options for the X-axis, click the (configuration options) icon to the right of the label: ## Options These settings control only the axis itself. To customize the [series mapped to the axis](/visualize-present/visualizations/configuration/series-configuration), use the dropdown next to the series/field. The settings in the **X-Axis** tab control the title, type, and sorting of the axis. ### Axis types The **Type** setting controls the type of X-axis used in the visualization. Omni will select a default axis type depending on the data in the query, but you can override it using this setting. Omni adjusts axis treatment for different data types and visualization types: * **Strings** - Axes will always be ordinal, and, by default, obey sort in the results table * **Numbers** - Bars are ordinal; line, scatter, area are quantitative (continuous) * **Dates** - Bars are ordinal; line, scatter, area are temporal (continuous) For the ordinal series, note that missing rows **will not** be displayed. We recommend that you [fill missing rows](/analyze-explore/point-click-queries#filling-missing-data) to retrieve these values when that is desirable. ## Labels The settings in the **Labels** tab allow you to customize how labels associated with the X-axis display in the visualization: * **Show labels** - If enabled, labels will display on the X-axis * **Show axis line** - If enabled, a line representing the X-axis will display * **Show ticks** - If enabled, ticks will display along the X-axis * **Font** - Options for customizing the styling and color of X-axis labels When selecting axis colors, note that there aren't separate settings for light and dark mode. The default palette will adjust colors based on the selected mode - such as a dark axis in light mode - but when explicitly defined, the color you select will be used in both light and dark mode. * **Format** - Defines the format X-axis labels use, such as `MMM-DD-YY` for dates * **Label rotation** - Controls the degree of rotation for X-axis labels * **Ticks** - Controls the number of ticks that display between labels ### Label spacing Axis labels will behave differently for continuous / temporal axes (vs ordinal / string). * **In continuous mode,** the labels will be spaced so as not to cut text, but may not align exactly with the visualization points * **In ordinal mode,** the values will be labeled one-by-one and hidden in consistent intervals to avoid collision. Currently, there aren't controls for label sparseness. ## Reference line Settings in the **Reference line** tab allow you to define a reference line, which is a quick way to set targets on a chart. There is limited configuration for these, so more complex use cases may be better served with table calculations as a regular, independent series. ## Grid Settings in the **Grid** tab control if and how grid lines display in the background of the visualization. ## Vega-lite options Long-tail axis configuration is available in the [Vega-lite spec](https://vega.github.io/vega-lite/docs/axis.html). # Y-axis (left axis / right axis) Source: https://docs.omni.co/visualize-present/visualizations/configuration/y-axis To access the configuration options for the Y-axis, click the (configuration options) icon to the right of the label: ## Options These settings control only the axis itself. To customize the [series mapped to the axis](/visualize-present/visualizations/configuration/series-configuration), use the dropdown next to the series/field. The settings in the **Y-Axis** tab control the title, type, domain, scale, and stacking of the axis. ### Axis types The **Type** setting controls the type of Y-axis used in the visualization. Omni will select a default axis type depending on the data in the query, but you can override it using this setting. **Note**: Depending on the selected type, some settings - such as domain and scale - may become unavailable. ## Labels The settings in the **Labels** tab allow you to customize how labels associated with the Y-axis display in the visualization: * **Show labels** - If enabled, labels will display on the Y-axis * **Show axis line** - If enabled, a line representing the Y-axis will display * **Show ticks** - If enabled, ticks will display along the Y-axis * **Font** - Options for customizing the styling and color of Y-axis labels When selecting axis colors, note that there aren't separate settings for light and dark mode. The default palette will adjust colors based on the selected mode - such as a dark axis in light mode - but when explicitly defined, the color you select will be used in both light and dark mode. * **Format** - Defines the format Y-axis labels use, such as the number of decimals for numbers * **Label rotation** - Controls the degree of rotation for Y-axis labels * **Ticks** - Controls the number of ticks that display between labels ## Reference lines Settings in the **Reference line** tab allow you to define a reference line, which is a quick way to set targets on a chart. There is limited configuration for these, so more complex use cases may be better served with table calculations as a regular, independent series. ## Grid Settings in the **Grid** tab control if and how grid lines display in the background of the visualization. ## Vega-lite options Long-tail axis configuration is available in the [Vega-lite spec](https://vega.github.io/vega-lite/docs/axis.html). # Visualize data in Omni Source: https://docs.omni.co/visualize-present/visualizations/index Turn query results into charts, tables, KPIs, and custom visualizations in Omni workbooks. Omni includes a library of built-in visualizations and configuration options to help you turn query results into clear, interactive charts. You can also use AI to generate visualizations automatically or build fully custom visuals with Vega-Lite. ## Chart types Omni supports a range of [built-in chart types](/visualize-present/visualizations/types), including bar, line, area, pie, scatter, funnel, heatmap, KPI, map, sankey, boxplot, and more. Each type is designed for specific data patterns — refer to the [chart types overview](/visualize-present/visualizations/types) for guidance on when to use each one. ### Selecting a chart type The quick chart icons in the workbook offer shortcuts to pre-configured chart types. They provide a fast way to switch between layouts like stacked vs. grouped bars, mixed bar-line charts, or toggle between table, chart, and Markdown views without digging into lower-level menus. Omni will take a best guess at the right chart for each new query, while retaining any manual changes you've made to the configuration. ### Resetting chart settings To clear the visualization and have Omni re-guess the best chart type, click **Tab > Reset Chart**. ## Generate visualizations with AI [AI-generated visualizations](/ai/visualizations) let you describe the chart you want in natural language — like "show this as a bar chart grouped by region" — and Blobby will create and configure it for you. You can also use auto-suggest to let AI pick the best visualization for your data. ## Configure charts Fine-tune the appearance and behavior of your visualizations with the [chart configuration](/visualize-present/visualizations/configuration/color) options: * **[Color and stacking](/visualize-present/visualizations/configuration/color)** — Set color palettes, series coloring, and stacking behavior * **[Series configuration](/visualize-present/visualizations/configuration/series-configuration)** — Control individual series display, labels, and formatting * **[Series mapping](/visualize-present/visualizations/configuration/series-mapping)** — Map query fields to chart axes and dimensions * **[Size](/visualize-present/visualizations/configuration/size)** — Adjust chart dimensions and responsive behavior * **[Tooltips](/visualize-present/visualizations/configuration/tooltips)** — Customize hover information * **[X-axis](/visualize-present/visualizations/configuration/x-axis)** and **[Y-axis](/visualize-present/visualizations/configuration/y-axis)** — Configure axis labels, scaling, and formatting ## Custom visualizations For use cases that go beyond built-in chart types, Omni supports [custom visualizations](/visualize-present/visualizations/types/custom) using Vega-Lite specs or iframe-based Markdown tiles. This gives you full control over the rendering when you need it. # AI summary visualization Source: https://docs.omni.co/visualize-present/visualizations/types/ai-summary Generate a summary of the current query's results with the AI summary visualization type. ## Requirements To use this visualization type, you'll need: * A query built on [topic data](/modeling/topics) * To have the **AI Visualization Summary** setting enabled in [**AI Hub > General > Features**](/ai/settings/features#ai-visualization-summary). This is enabled by default. ## Building the query To get the best results in the summary, keep the following in mind when building the underlying query: * **Avoid pivoting or swapping rows/columns in the query**. This significantly reduces the context window, leaving little available for the actual data. * **Include calculations and totals in the query if you want the summary to reference them.** This approach will provide better results over relying on the AI for calculations in the summary itself. ## Adding context You can provide additional context in the chart's **Options** to guide the AI in generating the summary. ### Example: Specific audience and content This example was given this context: `Explain it to me like I am a ceo and give me 3 followup questions` Test? ### Example: Specific tone You can provide context to the AI that specifies the tone of the summary. For example, `Explain it to me like I am 5 in a pirate voice` Test? # Area charts Source: https://docs.omni.co/visualize-present/visualizations/types/area Basic Area: **Stacked Area:** **Stack 100 Area:** **Overlay Area:** ## Data Structures Area charts can work with pivoted or unpivoted data, using 2 dimensions and one measure. To stack or group a chart, one series should be moved to the color facet. **Unpivoted Data:** **Pivoted Data** Additionally area charts can plot using several measures at once: ## Line Configuration Notes Area chart lines offer the same configuration as line charts: ### Line Mark This is the line icon on each axis, and holds all of the overall configuration options. ### Show Points Points can be toggles on/off to show alongside the lines (default contains no points). ### Dashes vs Solid Lines Whether or not series are shown as solid lines or dashed lines is available (default solid). ### Line Thickness The weight or thickness can be controlled (default 1). ### Line Opacity Setting is available to make the line partially transparent (default solid). ### Point Interpolation for Lines The method for interpolation between points can be controlled (default linear). Options include: * Linear * Monotone (smoothed) * Step (point at midpoint of the step) * Step Before * Step After ## Overall Configuration Notes The mark selector at the top of the configuration sets the global chart configuration (configuration across all series). Note that each series can be set independently to bar, line, scatter, area independently under their y-axis controls. The color section controls overall stacking and grouping behavior overall. Additionally stack can be set independently on the different y-axis, under the y-axis series configuration (useful for overall grouping of two stacked grouplets): * Automatic: we'll guess for you * Stack: Series on same x-axis value, on top of each other * Group: Series offset from their baseline x-axis mark into grouplets * Overlay: Series *on top* of each other (usually very undesirable, but useful in rare cases) * Stack %: Series rebased to 100% across each x-axis value ## Other Notes * Time dimension axes are set to temporal with area charts, meaning points will be displayed along a continuous time axis. For charts where ordinal behavior is desired, it's recommended to toggle the individual series from a bar chart accelerator. * With time fields, order will be automatically set to ascending; other data types will obey the table ordering when graphing * Tooltips have two styles (see below): * On line charts with multiple measures, hover will highlight all available series along the x-axis vertically, vs just the series being hovered. * On line charts with a dimension mapped to color (and a single measure), the hover will only show the nearest point # Bar charts Source: https://docs.omni.co/visualize-present/visualizations/types/bar Basic Bar: **Group:** **Stack:** **Stack %:** **Stacked Measures:** **Grouped, Stacked Measures:** ## Data Structures Bar charts can work with pivoted or unpivoted data, using 2 dimensions and one measure. To stack or group a chart, one series should be moved to the color facet. **Unpivoted Data:** **Pivoted Data** Additionally bar charts can plot several measures at once: ## Configuration Notes #### Setting Marks The mark selector at the top of the configuration sets the global chart configuration (configuration across all series). Note that each series can be set independently to bar, line, scatter, area independently under their y-axis controls. #### Stacking Settings The color section controls overall stacking and grouping behavior overall. Additionally stack can be set independently on the different y-axis, under the y-axis series configuration (useful for overall grouping of two stacked grouplets): * Automatic: we'll guess for you * Stack: Series on same x-axis value, on top of each other * Group: Series offset from their baseline x-axis mark into grouplets * Overlay: Series *on top* of each other (usually very undesirable, but useful in rare cases) * Stack %: Series rebased to 100% across each x-axis value #### Show Totals Labels on Stacked Charts For color-by stacked charts, totals can be labeled under the y-axis series configuration (Series > Labels > Simple Totals). Right now totals are not available for multiple-measure stacks. Additional configuration is provided for styling and value formatting of the labels: * Positioning (Auto, Above, Below, Left, Right, Middle) * Font size and color * Bolding and italic * Value formatting ## Other Notes * Axes are set to ordinal with bars (vs temporal with line, scatter, and area charts). This means each bar will be labeled independently (not a continuous axis), the axes are not intelligent about time, and values that are not in the set will not be plotted. To fill missing rows, the data must be adjusted in the table - [more here](/analyze-explore/point-click-queries#filling-missing-data) * With time fields, order will be automatically set to ascending; other data types will obey the table ordering when graphing * Tooltips on stacked bars will be designated to the individual segment of the chart when using color by. # Boxplots Source: https://docs.omni.co/visualize-present/visualizations/types/boxplot Create boxplot (box and whiskers) charts in Omni to visualize data distributions with quartiles, medians, and outliers. Boxplot charts are a versatile and efficient way to summarize and compare data across categories. Sometimes called a box and whiskers chart, each boxplot shows the distribution of the data in that category by charting its five-number summary: * Minimum: start of the left whisker line * First quartile (Q1): left-edge of the box * Median (Q2): center line * Third quartile (Q3): right edge of the box * Maximum value: end of the right whisker line. To configure a boxplot in Omni, your results should have a category on the y-axis and the unaggregated numeric values on the x-axis. Looking to use dates within a Boxplot? You'll have to cast the date field to a string first! # Custom visualizations Source: https://docs.omni.co/visualize-present/visualizations/types/custom Omni supports the most common visualization types and settings out of the box. However, if your business needs customization, you can: * [Leverage an iframe tag in a Markdown tile](#iframe-custom-visualizations) * [Create a Vega-Lite visualization](#vega-lite-visualizations) ## iframe custom visualizations One way to create a custom visualization is to leverage an iframe tag in a Markdown tiles. The data in results + [postMessages](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) will render your custom iframes and provide a ton of flexibility. For example: ```html theme={null} ``` **Note**: Included images won't render if they are scheduled. Additionally, the file must be hosted outside of Omni. ## Vega-Lite visualizations Many of Omni's charts are backed by [Vega-Lite](https://vega.github.io/vega-lite/), which is a JSON-based spec for visualizations. You can directly edit a chart's code to customize it beyond what Omni provides out of the box. If you are unfamiliar with Vega-Lite, check out the [Vega-Lite documentation](https://vega.github.io/vega-lite/docs/) before perusing the [example gallery](https://vega.github.io/vega-lite/examples/). ### Accessing the advanced editor Before opening the advanced editor, note that: * **The existing visualization will break**. To experiment with the advanced editor, create a copy of the query so you don't lose your work. * **Drill functionality will be unavailable** In the **Chart** tab of any workbook query, there are two ways to access the advanced editor: * **In the Chart selector** - Click the `{ ... }` icon to select the **Vega code** option. This will open the advanced editor, but without any pre-populated Vega code. This can be useful to start from scratch, such as with an [example from Vega](https://vega.github.io/vega-lite/examples/) or [one from the example gallery on this page](#examples). * **In the chart editor** - For any chart powered by Vega-Lite, there will be a `{ }` icon in the chart editor. Clicking it will open a menu with the following options: * **View source** - Opens a dialog with the Vega-Lite JSON * **Open in advanced editor** - Copies the current chart code and opens it in the **Advanced editor** screenshot of the View Source menu ### Referencing data in the advanced editor To use data from the results query, you'll need to reference the field by its view and field name as they are defined in the model. This will look like `view_name\\.field_name` in the editor. The double forward-slashes (`\\`) are included because periods and brackets must be escaped. For example: | Omni object | Vega object | | ------------------------- | ------------------------------- | | `users.id` | `users\\.id` | | `users.age` | `users\\.age` | | `users.created_at` | `users\\.created_at` | | `users.created_at[date]` | `users\\.created_at\\[date\\]` | | `users.created_at[month]` | `users\\.created_at\\[month\\]` | | `id` | `id` | **Note**: In the last example, `id` would only occur from a raw SQL query as Omni will alias with the view. ### Saving and resetting changes Custom visualizations must be manually saved. While the visualization will update as you edit, the code is not auto-saved. Periodically click the **Save** button to save your changes. To remove all edits made to the code, click **Reset**. This will revert the code to its original version. Saving a Vega code visualization ## Examples In addition to custom Vega-Lite visualizations, you can also build custom visualizations using HTML, CSS and Markdown. Check out the [Markdown visualization examples](/visualize-present/visualizations/types/markdown) for some inspiration. ### US state map Omni recommends using the [native map visualization](/visualize-present/visualizations/types/map) for this visualization. **Query fields**: * `users.state` - Full-length state names are required for this visualization. To remove the legend, add `"legend":null` within `color{...` * `users.user_count` ```json expandable title="Visualization code" theme={null} { "layer": [ { "data": { "url": "https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json", "format": { "type": "topojson", "feature": "states" } }, "mark": { "fill": "lightgray", "type": "geoshape", "stroke": "black" } }, { "mark": "geoshape", "width": "container", "height": "container", "encoding": { "href": { "type": "nominal", "field": "url" }, "color": { "type": "quantitative", "field": "COLOR" }, "shape": { "type": "geojson", "field": "geo" }, "tooltip": [ { "field": "STATE", "title": "State" }, { "type": "quantitative", "field": "COLOR", "title": "User Count" } ] } } ], "width": "container", "height": "container", "transform": [ { "as": "STATE", "calculate": "datum['your_view.your_state']" }, { "as": "COLOR", "calculate": "datum['your_view.your_measure']" }, { "as": "geo", "from": { "key": "properties.name", "data": { "url": "https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json", "format": { "type": "topojson", "feature": "states" } } }, "lookup": "STATE" }, { "as": "url", "calculate": "'https://sandbox.proto.exploreomni.com/w/0a494c7e-3d8a-4f31-aa53-cb8d1e62f4fa/drill?ephemeral=DyXjRBEJ%2CRveZe1I6%2CZUK24UVr%2CHehug3WH%2CbuG0igrs%2CcNuuSY8a%2CnOHD__EL%2C3Dgpwy5c%2C0ta1FE8v%2CSsbC6Jdf&field=users.count&filters=%7B%7D&miniUuid=ZUK24UVr&row=%7B%22users.state%22%3A%22' + datum['users\\.state'] + '%22%2C%22state_id.state_id%22%3A%221%22%2C%22users.count%22%3A%221625%22%7D' " } ], "projection": { "type": "albersUsa" } } ``` ### US map with latitude and longitude Omni recommends using the [native map visualization](/visualize-present/visualizations/types/map) for this visualization. **Query fields:** * `users.zip` * `users.zip_first_digit` * `users.latitude_average` * `users.longitude_average` * `users.user_count` ```json expandable title="Visualization code" theme={null} { "layer": [ { "data": { "url": "https://vega.github.io/editor/data/us-10m.json", "format": { "type": "topojson", "feature": "states" } }, "mark": { "fill": "lightgray", "type": "geoshape", "stroke": "white" } }, { "transform": [ { "as": "LATITUDE", "calculate": "datum['users\\.latitude_average']" }, { "as": "LONGITUDE", "calculate": "datum['users\\.longitude_average']" }, { "as": "COLOR", "calculate": "datum['calc_1']" } ], "mark": { "type": "circle", "tooltip": true }, "encoding": { "size": { "value": 5 }, "color": { "type": "nominal", "field": "COLOR", "scale": { "scheme": "magma" }, "legend": null }, "latitude": { "type": "quantitative", "field": "LATITUDE" }, "longitude": { "type": "quantitative", "field": "LONGITUDE" } } } ], "width": "container", "height": "container", "projection": { "type": "albersUsa" } } ``` ### US map - zip code choropleth Omni recommends using the [native map visualization](/visualize-present/visualizations/types/map) for this visualization. **Query fields**: * `users.zip` * `users.user_count` ```json expandable title="Visualization code" theme={null} { "layer": [ { "data": { "url": "https://vega.github.io/editor/data/us-10m.json", "format": { "type": "topojson", "feature": "states" } }, "mark": { "fill": "white", "type": "geoshape", "stroke": "black" } }, { "mark": "geoshape", "width": "container", "height": "container", "encoding": { "color": { "type": "quantitative", "field": "users\\.count", "scale": { "domain": [ 0, 20 ], "scheme": "blues" }, "legend": null }, "shape": { "type": "geojson", "field": "geo" }, "tooltip": [ { "field": "ZIP" }, { "type": "quantitative", "field": "COLOR", "title": "Users Count" } ] } } ], "transform": [ { "as": "ZIP", "calculate": "datum['users.zip']" }, { "as": "COLOR", "calculate": "datum['users.count']" }, { "as": "geo", "from": { "key": "properties.zip", "data": { "url": "https://gist.githubusercontent.com/jefffriesen/6892860/raw/e1f82336dde8de0539a7bac7b8bc60a23d0ad788/zips_us_topo.json", "format": { "type": "topojson", "feature": "zip_codes_for_the_usa" } } }, "lookup": "ZIP" } ], "projection": { "type": "albersUsa" } } ``` ### US map with labeled points Omni recommends using the native map visualization for standard geographic plotting. However, if you need to add labels directly to your map marks, you will need to use a custom Vega-Lite visualization to do so. This visualization layers text marks directly inside colored coordinate points over a TopoJSON base map of the United States. It utilizes the `albersUsa` projection to automatically arrange the states appropriately. **Query fields**: * `view_name.latitude` - The latitude coordinate of the point. * `view_name.longitude` - The longitude coordinate (must be a negative number for the albersUsa projection). * `view_name.rank` - The text value to display inside the map marker. * `view_name.category` - The categorical field used to assign colors to the points. * `view_name.city` - Additional detail for the hover tooltip. * `view_name.state` - Additional detail for the hover tooltip. ```json expandable title="Visualization code" theme={null} { "$schema": "https://vega.github.io/schema/vega-lite/v6.json", "data": { "name": "query" }, "width": "container", "height": "container", "projection": { "type": "albersUsa" }, "layer": [ { "data": { "url": "https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json", "format": { "type": "topojson", "feature": "states" } }, "mark": { "type": "geoshape", "fill": "#e5e5e5", "stroke": "white", "strokeWidth": 1 } }, { "transform": [ { "calculate": "toNumber(datum['view_name.latitude'])", "as": "LATITUDE" }, { "calculate": "toNumber(datum['view_name.longitude'])", "as": "LONGITUDE" }, { "calculate": "datum['view_name.city']", "as": "CITY" }, { "calculate": "datum['view_name.state']", "as": "STATE" }, { "calculate": "datum['view_name.rank']", "as": "RANK" }, { "calculate": "datum['view_name.category']", "as": "COLOR_CAT" }, { "filter": "isValid(datum.LATITUDE) && isValid(datum.LONGITUDE)" } ], "encoding": { "longitude": { "field": "LONGITUDE", "type": "quantitative" }, "latitude": { "field": "LATITUDE", "type": "quantitative" }, "tooltip": [ { "field": "RANK", "type": "nominal", "title": "Rank" }, { "field": "CITY", "type": "nominal", "title": "City" }, { "field": "STATE", "type": "nominal", "title": "State" } ] }, "layer": [ { "mark": { "type": "circle", "size": 300, "stroke": "white", "strokeWidth": 1.5, "opacity": 1 }, "encoding": { "color": { "field": "COLOR_CAT", "type": "nominal", "scale": { "range": ["#F2B21B", "#6EC1F2"] }, "legend": null } } }, { "mark": { "type": "text", "baseline": "middle", "align": "center", "fontWeight": "bold", "fontSize": 11 }, "encoding": { "text": { "field": "RANK", "type": "nominal" }, "color": { "value": "black" } } } ] } ], "config": { "view": { "stroke": null } } } ``` ### US state map - zip code choropleth **Query fields:** * `users.zip` * `users.user_count` ```json expandable title="Visualization code" theme={null} { "layer": [ { "data": { "url": "https://raw.githubusercontent.com/OpenDataDE/State-zip-code-GeoJSON/master/dc_district_of_columbia_zip_codes_geo.min.json", "format": { "property": "features" } }, "mark": { "fill": "white", "type": "geoshape", "stroke": "black" } }, { "mark": "geoshape", "width": "container", "height": "container", "encoding": { "color": { "type": "quantitative", "field": "users\\.count", "scale": { "domain": [ 0, 20 ], "scheme": "blues" }, "legend": null }, "shape": { "type": "geojson", "field": "geo" }, "tooltip": [ { "field": "users\\.zip" }, { "type": "quantitative", "field": "users\\.count", "title": "Users Count" } ] } } ], "transform": [ { "as": "geo", "from": { "key": "properties.ZCTA5CE10", "data": { "url": "https://raw.githubusercontent.com/OpenDataDE/State-zip-code-GeoJSON/master/dc_district_of_columbia_zip_codes_geo.min.json", "format": { "property": "features" } } }, "lookup": "users\\.zip" } ], "projection": { "type": "albersUsa" } } ``` ### Radial chart A radial chart layers in exploding pie slices using the square root of the value. **Query Fields:** * `products.category` * `order_items.sale_price_sum` ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": { "type": "arc", "stroke": "#fff", "innerRadius": 30 } }, { "mark": { "dx": 4, "type": "text", "align": "center", "radiusOffset": 30 }, "encoding": { "text": { "type": "nominal", "field": "COLOR" } } } ], "height": "container", "width": "container", "encoding": { "color": { "type": "nominal", "field": "SIZE", "legend": null }, "theta": { "type": "quantitative", "field": "SIZE", "stack": true }, "radius": { "field": "SIZE", "scale": { "type": "sqrt", "zero": true, "rangeMin": 20 } }, "tooltip": [ { "type": "nominal", "field": "COLOR", "title": "Category" }, { "type": "quantitative", "field": "SIZE", "title": "Sales", "format": ",.2f" } ] }, "transform": [ { "as": "COLOR", "calculate": "datum['products.category']" }, { "as": "SIZE", "calculate": "datum['order_items.sale_price_sum']" } ] } ``` ### Cross-filtered chart pair This visualization aggregates the top visualization over the highlight selection. Two charts are built from the results table, stacked, and then wired together. **Note**: This visualization also uses pixel sizing, which isn't ideal for use on dashboards where `container` should be used for sizing. **Query fields:** * `order_items.created_at[date]` - Filtered to `2021`, the x-axis * `products.category` - Filtered to five products, forming the color facets * `order_items.sale_price_sum` - The y-axis * `order_items.count` - The bubble size ```json expandable title="Visualization code" theme={null} { "vconcat": [ { "mark": "point", "width": 600, "height": 300, "params": [ { "name": "brush", "select": { "type": "interval", "encodings": [ "x" ] } } ], "encoding": { "x": { "type": "temporal", "field": "X_AXIS", "title": "Date" }, "y": { "type": "quantitative", "field": "TOP_Y", "title": "Total Sales" }, "size": { "type": "quantitative", "field": "BOTTOM_Y", "title": "Count of Sales" }, "color": { "value": "lightgray", "condition": { "type": "nominal", "field": "COLOR", "param": "brush", "title": "Category" } } }, "transform": [ { "as": "X_AXIS", "calculate": "datum['order_items.created_at[date]']" }, { "as": "TOP_Y", "calculate": "datum['order_items.sale_price_sum']" }, { "as": "BOTTOM_Y", "calculate": "datum['order_items.order_count']" }, { "as": "COLOR", "calculate": "datum['products.category']" }, { "filter": { "param": "click" } } ] }, { "mark": "bar", "width": 600, "params": [ { "name": "click", "select": { "type": "point", "encodings": [ "color" ] } } ], "encoding": { "x": { "field": "TOP_Y", "title": "Sales", "aggregate": "sum" }, "y": { "field": "COLOR", "title": "Category" }, "color": { "value": "lightgray", "condition": { "field": "COLOR", "param": "click" } } }, "transform": [ { "as": "X_AXIS", "calculate": "datum['order_items.created_at[date]']" }, { "as": "TOP_Y", "calculate": "datum['order_items.sale_price_sum']" }, { "as": "BOTTOM_Y", "calculate": "datum['order_items.order_count']" }, { "as": "COLOR", "calculate": "datum['products.category']" }, { "filter": { "param": "brush" } } ] } ] } ``` ### Flag marks scatterplot This visualization won't render if used in a [delivery or alert](/share/deliveries). This chart uses data about each country's economy and a flag emoji to create a scatterplot. The flag emoji is used as the mark to represent the country. This example also uses log-scale. **Query fields:** * `flag` - Flag emoji * `name` - Country name * `rank` * `gdp` * `growth` * `population` * `gdp_per_capita` * `gdp_percent_share` **Example dataset**: ```json expandable title="Visualization code" theme={null} { "mark": { "type": "text", "fontSize": 30 }, "width": "container", "height": "container", "transform": [ { "as": "COUNTRY", "calculate": "datum['users.country']" }, { "as": "X_AXIS", "calculate": "datum['users.count']" }, { "as": "Y_AXIS", "calculate": "datum['order_items.sale_price_sum']" }, { "as": "ICON", "calculate": "datum['calc_1']" } ], "encoding": { "x": { "type": "quantitative", "field": "X_AXIS", "scale": { "type": "log" } }, "y": { "axis": { "labelOverlap": true }, "type": "quantitative", "field": "Y_AXIS", "scale": { "type": "log" } }, "text": { "type": "nominal", "field": "ICON" }, "tooltip": [ { "sort": null, "type": "nominal", "field": "ICON" }, { "sort": null, "type": "nominal", "field": "name", "title": "COUNTRY" }, { "sort": null, "type": "quantitative", "field": "X_AXIS" }, { "type": "quantitative", "field": "Y_AXIS" } ] } } ``` ### Waterfall This waterfall chart requires both a custom visualization spec and some query munging. In this example, a change occurs state-by-state, at which point special bars are appended for the starting and ending values. **Note**: The Vega spec contains a lot of calculation. This is intended to demonstrate the ability to extend the dataset to enhance the visualization. **Query fields**: * `label` * `value` #### Unioned queries The underlying data is brought together by using a SQL `UNION` clause. ```sql theme={null} ( SELECT 'Begin' AS "label", 1000 AS "amount" FROM users LIMIT 1 ) UNION ALL ( SELECT "users.state", "amount" FROM orders ) UNION ALL ( SELECT 'End', 0 FROM users LIMIT 1 ) ``` * **Begin row**: Start value. Must be named `'Begin'` for label; this can be replaced with the first value from the dataset in the future. * **Waterfall data set:** Build with the UI and drop in the SQL, or use the Advanced Editor to write SQL. When updating to your own query data, remember to [reference data](#referencing-data-in-the-advanced-editor) with the `view_name\\.field_name` syntax. * **End row:** Value must be `0`. Must be named `'End'`; this can be replaced in the future since it's all implied. ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": { "size": 45, "type": "bar" }, "encoding": { "y": { "type": "quantitative", "field": "previous_sum", "title": "Amount" }, "y2": { "field": "sum" }, "color": { "value": "#93c4aa", "condition": [ { "test": "datum.LABEL === 'Begin' || datum.LABEL === 'End'", "value": "#f7e0b6" }, { "test": "datum.sum < datum.previous_sum", "value": "#f78a64" } ] } } }, { "mark": { "type": "rule", "color": "#404040", "opacity": 1, "xOffset": -22.5, "x2Offset": 22.5, "strokeWidth": 2 }, "encoding": { "y": { "type": "quantitative", "field": "sum" }, "x2": { "field": "lead" } } }, { "mark": { "dy": -4, "type": "text", "baseline": "bottom" }, "encoding": { "y": { "type": "quantitative", "field": "sum_inc" }, "text": { "type": "nominal", "field": "sum_inc", "format": "bigusdcurrency_2", "formatType": "omniNumberFormat" }, "opacity": { "condition": { "test": "datum['sum_inc'] == 0", "value": "0" } } } }, { "mark": { "dy": 4, "type": "text", "baseline": "top" }, "encoding": { "y": { "type": "quantitative", "field": "sum_dec" }, "text": { "type": "nominal", "field": "sum_dec", "format": "bigusdcurrency_2", "formatType": "omniNumberFormat" }, "opacity": { "condition": { "test": "datum['sum_dec'] == 0", "value": "0" } } } }, { "mark": { "type": "text", "baseline": "middle", "fontWeight": "bold" }, "encoding": { "y": { "type": "quantitative", "field": "center" }, "text": { "type": "nominal", "field": "AMOUNT", "format": "bigusdcurrency_2", "formatType": "omniNumberFormat" }, "color": { "value": "white", "condition": [ { "test": "datum.LABEL === 'Begin' || datum.LABEL === 'End'", "value": "#725a30" } ] }, "opacity": { "condition": { "test": "datum['amount_percent'] < 0.07", "value": "0" } } } } ], "width": "container", "config": { "text": { "color": "#404040", "fontWeight": "bold" } }, "height": "container", "encoding": { "x": { "axis": { "title": "Months", "labelAngle": 0 }, "sort": null, "type": "ordinal", "field": "LABEL" } }, "transform": [ { "as": "LABEL", "calculate": "datum['label']" }, { "as": "AMOUNT", "calculate": "datum['amount']" }, { "window": [ { "as": "sum", "op": "sum", "field": "AMOUNT" } ] }, { "window": [ { "as": "lead", "op": "lead", "field": "LABEL" } ] }, { "joinaggregate": [ { "as": "total", "op": "sum", "field": "AMOUNT" } ] }, { "as": "lead", "calculate": "datum.lead === null ? datum.LABEL : datum.lead" }, { "as": "previous_sum", "calculate": "datum.LABEL === 'End' ? 0 : datum.sum - datum.AMOUNT" }, { "as": "amount", "calculate": "datum.LABEL === 'End' ? datum.sum : datum.AMOUNT" }, { "as": "text_amount", "calculate": "(datum.LABEL !== 'Begin' && datum.LABEL !== 'End' && datum.AMOUNT > 0 ? '+' : '') + datum.AMOUNT" }, { "as": "amount_percent", "calculate": "abs(datum.AMOUNT) / datum.total" }, { "as": "center", "calculate": "(datum.sum + datum.previous_sum) / 2" }, { "as": "sum_dec", "calculate": "datum.sum < datum.previous_sum ? datum.sum : ''" }, { "as": "sum_inc", "calculate": "datum.sum > datum.previous_sum ? datum.sum : ''" } ] } ``` ### Tapered funnel A tapered funnel is used to measure a funnel using several filtered measures. This chart calculates overall dropoff and step-by-step dropoff. You can add or remove stages by editing the `fold` section and then the subsequent steps, removing the backticks: `users\\.count` then `"measurename": "users.count"`. **Query fields:** * `users.count` * `users.count_california_seniors` * `users.count_minors` * `users.count_california_minors` ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": { "type": "bar", "color": "transparent" }, "encoding": { "x": { "axis": "", "type": "quantitative", "field": "stagePos" } } }, { "mark": { "type": "bar", "tooltip": true }, "encoding": { "x": { "axis": "", "type": "quantitative", "field": "negCount" }, "color": { "field": "stage", "scale": { "scheme": { "name": "oranges", "extent": [ 0.8, 0 ] } }, "legend": null }, "tooltip": [ { "type": "nominal", "field": "stage", "title": "Stage" }, { "type": "quantitative", "field": "count", "title": "Count" } ] } }, { "mark": { "dx": { "expr": "datum.labelLeft ? -4 : 4" }, "type": "text", "align": { "expr": "datum.labelLeft ? 'right' : 'left'" } }, "encoding": { "x": { "axis": "", "type": "quantitative", "field": "negCount" }, "text": { "field": "count" } } }, { "mark": { "dx": 4, "type": "text", "align": "left" }, "encoding": { "x": { "axis": "", "type": "quantitative", "field": "stagePos" }, "text": { "field": "stage" } } }, { "mark": { "type": "text", "align": "center" }, "encoding": { "x": { "axis": "", "type": "quantitative", "field": "cumulativePos" }, "text": { "field": "cumulativePct", "format": ".1%" } } }, { "mark": { "type": "text", "align": "center" }, "encoding": { "x": { "axis": "", "type": "quantitative", "field": "conversionPos" }, "text": { "field": "conversionPct", "format": ".1%" } }, "transform": [ { "filter": "isValid(datum.previousCount)" } ] }, { "mark": { "dx": { "expr": "datum.dx" }, "type": "text", "align": { "expr": "datum.align" } }, "encoding": { "x": { "axis": "", "type": "quantitative", "field": "pos" }, "y": { "axis": null, "type": "nominal", "datum": "0. Titles" }, "text": { "field": "caption" } }, "transform": [ { "filter": "!isValid(datum.previousCount)" }, { "as": "zero", "calculate": "0" }, { "as": [ "column", "pos" ], "fold": [ "stagePos", "zero", "cumulativePos", "conversionPos" ] }, { "from": { "key": "column", "data": { "values": [ { "dx": 4, "align": "left", "column": "stagePos", "caption": "Stage" }, { "dx": -4, "align": "right", "column": "zero", "caption": "Count" }, { "dx": 0, "align": "center", "column": "cumulativePos", "caption": "Overall" }, { "dx": 0, "align": "center", "column": "conversionPos", "caption": "Previous" } ] }, "fields": [ "caption", "align", "dx" ] }, "lookup": "column" } ] } ], "width": "container", "height": "container", "encoding": { "y": { "axis": "", "type": "nominal", "field": "stage" } }, "transform": [ { "as": [ "measurename", "count" ], "fold": [ "users\\.count", "users\\.count_california_seniors", "users\\.count_minors", "users\\.count_california_minors" ] }, { "from": { "key": "measurename", "data": { "values": [ { "stage": "1. Users", "measurename": "users.count" }, { "stage": "2. California ", "measurename": "users.count_california_seniors" }, { "stage": "3. Minors", "measurename": "users.count_minors" }, { "stage": "4. California Minors", "measurename": "users.count_california_minors" } ] }, "fields": [ "stage" ] }, "lookup": "measurename" }, { "joinaggregate": [ { "as": "maxCount", "op": "max", "field": "count" } ] }, { "sort": [ { "field": "stage", "order": "ascending" } ], "window": [ { "as": "previousCount", "op": "lag", "field": "count" } ] }, { "as": "cumulativePct", "calculate": "datum.count / datum.maxCount" }, { "as": "conversionPct", "calculate": "datum.count / datum.previousCount" }, { "as": "countPos", "calculate": "datum.maxCount * 0.5" }, { "as": "cumulativePos", "calculate": "datum.maxCount * 0.08" }, { "as": "conversionPos", "calculate": "datum.maxCount * 0.16" }, { "as": "stagePos", "calculate": "datum.maxCount * -1.2" }, { "as": "negCount", "calculate": "-datum.count" }, { "as": "labelLeft", "calculate": "datum.count < 0.1 * datum.maxCount" } ] } ``` ### Centered funnel #### Funnel with currency ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": "bar", "encoding": { "x": { "axis": false, "type": "quantitative", "field": "AMOUNT", "stack": "center" }, "color": { "type": "nominal", "field": "COLOR", "legend": null } } }, { "layer": [ { "mark": { "dx": 0, "type": "text", "align": "right" }, "encoding": { "text": { "type": "quantitative", "field": "AMOUNT", "format": "USDCURRENCY", "formatType": "omniNumberFormat" } } }, { "mark": { "dx": 10, "type": "text", "align": "left" }, "encoding": { "text": { "type": "quantitative", "field": "PERCENT", "format": "PERCENT", "formatType": "omniNumberFormat", "condition": { "test": "datum['PERCENT'] > 1", "value": "N/A" } } } } ] } ], "transform": [ { "as": "COLOR", "calculate": "datum['events.event_type']" }, { "as": "AMOUNT", "calculate": "datum['events.count']" }, { "window": [ { "field": "AMOUNT", "op": "lag", "as": "PREVIOUS_AMOUNT" } ] }, { "as": "PERCENT", "calculate": "datum.AMOUNT/datum.PREVIOUS_AMOUNT" } ], "width": "container", "height": "container", "encoding": { "y": { "axis": { "title": false }, "sort": null, "type": "nominal", "field": "events\\.event_type" } } } ``` #### Funnel with a dimension and a measure ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": "bar", "encoding": { "x": { "axis": false, "type": "quantitative", "field": "events\\.count", "stack": "center" }, "color": { "type": "nominal", "field": "events\\.event_type", "legend": null } } }, { "layer": [ { "mark": { "dx": 0, "type": "text", "align": "right" }, "encoding": { "text": { "type": "quantitative", "field": "events\\.count", "formatType": "omniNumberFormat" } } }, { "mark": { "dx": 10, "type": "text", "align": "left" }, "encoding": { "text": { "type": "nominal", "field": "phase" } }, "transform": [ { "as": "phase", "calculate": "datum.calc_1 + '%'" } ] } ] } ], "width": "container", "height": "container", "encoding": { "y": { "axis": { "title": false }, "sort": null, "type": "nominal", "field": "events\\.event_type" } } } ``` #### Funnel with three measures ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": "bar", "encoding": { "x": { "axis": false, "type": "quantitative", "field": "measure_value", "stack": "center" }, "color": { "type": "nominal", "field": "measure_name", "legend": null } } }, { "layer": [ { "mark": { "dx": 0, "type": "text", "align": "right" }, "encoding": { "text": { "type": "quantitative", "field": "measure_value", "formatType": "omniNumberFormat" } } }, { "mark": { "dx": 10, "type": "text", "align": "left" }, "encoding": { "text": { "type": "nominal", "field": "phase" } }, "transform": [ { "as": "phase", "calculate": "datum.calc_1 + '%'" } ] } ] } ], "width": "container", "height": "container", "encoding": { "y": { "axis": { "title": false }, "sort": null, "type": "nominal", "field": "measure_name" } } } ``` ### Gantt (timeline) chart This chart takes advantage of `x`, `x2` in Vega to create a start and end point for bars along a timeline for each user. It also includes config to improve the axis labels. Color could be included in an additional facet, using one more dimension to group different users together. **Query fields:** * `users.full_name` * `users.created_at[date]` * `order_items.created_at[date]` ```json expandable title="Visualization code" theme={null} { "mark": "bar", "encoding": { "y": { "field": "DIM", "type": "ordinal", "axis": { "title": "Name" } }, "x": { "field": "START", "type": "temporal", "axis": { "title": "Date" } }, "x2": { "field": "END", "type": "temporal" } }, "transform": [ { "as": "DIM", "calculate": "datum['users.full_name']" }, { "as": "START", "calculate": "datum['users.created_at[date]']" }, { "as": "END", "calculate": "datum['order_items.created_at[date]']" } ] } ``` ### Isotope (stacked icons) Unlike other charts, this chart requires the full granularity in the dataset to create the stacked icons. The core technique is to map the repeated values into icons and then stack them. **Note**: In this example, `users.id` is included in order to create one entry per row. **Query fields:** * `users.email_domain` * `users.id` ```json expandable title="Visualization code" theme={null} { "mark": { "type": "text", "baseline": "middle" }, "width": "container", "config": { "view": { "stroke": "" } }, "height": "container", "encoding": { "x": { "axis": null, "type": "ordinal", "field": "rank" }, "y": { "type": "nominal", "field": "DIM", "title": null }, "size": { "value": 40 }, "text": { "type": "nominal", "field": "emoji" } }, "transform": [ { "as": "DIM", "calculate": "datum['users\\.traffic_source']" }, { "as": "COUNTER", "calculate": "datum['users.id']" }, { "as": "emoji", "calculate": "{'Search': '\ud83d\udc04', 'Display': '\ud83d\udc0f', 'Organic': '\ud83d\udc16', 'Facebook': '\ud83d\udc22', 'Email': '\ud83d\udc22'}[datum.DIM]]" }, { "window": [ { "as": "rank", "op": "rank" } ], "groupby": [ "DIM" ] } ] } ``` ### Gauge A gauge chart resembles a speedometer or dial and is typically used to display a single value within a predefined range. This visualization is useful for evaluating progress against a goal. **Example dataset**: ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": { "type": "arc", "color": "lightgrey", "theta": { "expr": "datum['_arc_start_radians']" }, "radius": { "expr": "ring1_outer" }, "theta2": { "expr": "datum['_arc_end_radians']" }, "radius2": { "expr": "ring1_inner" }, "cornerRadius": 10 } }, { "mark": { "type": "arc", "theta": { "expr": "datum['_ring_start_radians']" }, "radius": { "expr": "ring1_outer" }, "theta2": { "expr": "datum['_ring_end_radians']" }, "radius2": { "expr": "ring1_inner" }, "cornerRadius": 10 }, "name": "RING", "encoding": { "color": { "value": "#307E31", "condition": [ { "test": "datum['ratio'] < 0.33", "value": "#880808" }, { "test": "datum['ratio'] < 0.66", "value": "#E49B0F" } ] } } }, { "mark": { "type": "text", "fontSize": 40 }, "encoding": { "text": { "field": "users\\.count", "format": "number", "formatType": "omniNumberFormat" }, "color": { "value": "#307E31", "condition": [ { "test": "datum['ratio'] < 0.33", "value": "#880808" }, { "test": "datum['ratio'] < 0.66", "value": "#E49B0F" } ] } } } ], "width": "container", "config": { "concat": { "spacing": 0 }, "autosize": { "type": "fit", "resize": true, "contains": "padding" } }, "height": "container", "params": [ { "name": "ring_max", "value": 160 }, { "name": "ring_width", "value": 20 }, { "name": "ring_gap", "value": 5 }, { "name": "label_color", "value": "#000000" }, { "name": "ring_background_opacity", "value": 0.3 }, { "name": "ring0_percent", "value": 100 }, { "expr": "ring_max+2", "name": "ring0_outer" }, { "expr": "ring_max+1", "name": "ring0_inner" }, { "expr": "ring0_inner-ring_gap", "name": "ring1_outer" }, { "expr": "ring1_outer-ring_width", "name": "ring1_inner" }, { "expr": "(ring1_outer+ring1_inner)/2", "name": "ring1_middle" }, { "expr": "220", "name": "arc_size" } ], "transform": [ { "as": "ratio", "calculate": "datum['users\\.count'] / ( datum['calc_1'] )" }, { "as": "_arc_start_degrees", "calculate": "360 - ( arc_size / 2 )" }, { "as": "_arc_end_degrees", "calculate": "0 + ( arc_size / 2 )" }, { "as": "_arc_start_radians", "calculate": "2 * 3.14 * ( datum['_arc_start_degrees'] - 360 ) / 360" }, { "as": "_arc_end_radians", "calculate": "2 * 3.14 * datum['_arc_end_degrees'] / 360" }, { "as": "_arc_total_radians", "calculate": "datum['_arc_end_radians'] - datum['_arc_start_radians']" }, { "as": "_ring_start_radians", "calculate": "datum['_arc_start_radians']" }, { "as": "_ring_end_radians", "calculate": "datum['_arc_start_radians'] + ( datum['_arc_total_radians'] * datum['ratio'] )" } ] } ``` ### Sunburst chart Sunburst charts display hierarchical data in an easy-to-read way. Each ring represents a level in the hierarchy, and the size of each section conveys its proportion in comparison to the whole. In this example, the inner slices are colored by order. **Query fields**: * `users.gender` * `users.traffic_source` * `users.count` **Example dataset**: ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": { "type": "arc", "tooltip": true, "innerRadius": { "expr": "min(width, height)/9" }, "outerRadius": { "expr": "min(width, height)/3" } }, "encoding": { "color": { "sort": "ascending", "type": "ordinal", "field": "OUT_IN", "scale": { "range": [ "#1DF9B9", "#1DE5B9", "#1DD1B9", "#1DBDB9", "#1DA9B9", "#3DF23B", "#3DDA3B", "#3DC23B", "#3DAA3B", "#3D923B" ] }, "title": "Inner Grouping" }, "order": { "sort": "ascending", "field": "OUT_IN" }, "theta": { "type": "quantitative", "field": "SIZE", "stack": true }, "tooltip": [ { "type": "nominal", "field": "OUTSIDE", "title": [ "Outer Grouping" ] }, { "type": "nominal", "field": "INSIDE", "title": [ "Inner Grouping" ] }, { "type": "quantitative", "field": "SIZE", "title": [ "Count" ], "format": "NUMBER", "formatType": "omniNumberFormat" } ] } }, { "mark": { "type": "arc", "tooltip": true, "innerRadius": { "expr": "min(width, height)/3" } }, "encoding": { "color": { "sort": "ascending", "type": "ordinal", "field": "OUTSIDE", "scale": { "range": [ "#1DD1B9", "#3DC23B" ] }, "title": "Outer Grouping" }, "order": { "sort": "ascending", "field": "OUTSIDE" }, "theta": { "sort": "ascending", "type": "quantitative", "field": "total_users", "stack": true, "title": [ "Users Count" ] }, "tooltip": [ { "type": "nominal", "field": "OUTSIDE", "title": [ "Outer Grouping" ] }, { "type": "quantitative", "field": "total_users", "title": [ "Count" ], "format": "NUMBER", "formatType": "omniNumberFormat" } ] }, "transform": [ { "groupby": [ "OUTSIDE" ], "aggregate": [ { "as": "total_users", "op": "sum", "field": "SIZE" } ] } ] } ], "transform": [ { "as": "OUTSIDE", "calculate": "datum['users.gender']" }, { "as": "INSIDE", "calculate": "datum['users.traffic_source']" }, { "as": "OUT_IN", "calculate": "datum.OUTSIDE + '-' + datum.INSIDE" }, { "as": "SIZE", "calculate": "datum['users.count']" } ], "resolve": { "scale": { "color": "independent" }, "legend": { "color": "independent" } } } ``` ### Trellis / Small Multiples / Faceted Charts Trellis charts allow you to show a grid of smaller charts, one for each category. To use this example, update the following values in the custom visualization code: * `DIM` to be the x-axis value in your query * `AMOUNT` as the y-axis value in your query * `FACET` to be the grouping field * `COLOR` for the mark color You can also adjust the mark type, the width and height of each small chart, and the number of columns to draw. **Example result set:** ```json expandable title="Visualization code" theme={null} { "mark": { "type": "line", "tooltip": true }, "width": 200, "height": 50, "resolve": { "scale": { "x": "shared", "y": "independent" } }, "encoding": { "x": { "axis": { "title": null, "format": "%b %-d, %Y", "formatType": "omniTimestampFormat", "labelOverlap": true }, "sort": "ascending", "type": "ordinal", "field": "DIM", "title": "Date", "timeUnit": "utcyearmonthdate" }, "y": { "axis": { "format": "bigusdcurrency_0", "orient": "left", "formatType": "omniNumberFormat", "labelOverlap": true }, "type": "quantitative", "field": "AMOUNT", "title": "Total Sales", "format": "bigusdcurrency_2", "formatType": "omniNumberFormat" }, "color": { "field": "COLOR", "title": "Category", "legend": null }, "facet": { "sort": "ascending", "type": "ordinal", "field": "FACET", "title": null, "columns": 4 } }, "transform": [ { "as": "DIM", "calculate": "datum['omni_dbt_ecomm__order_items.created_at[week]']" }, { "as": "AMOUNT", "calculate": "datum['omni_dbt_ecomm__order_items.total_sale_price']" }, { "as": "FACET", "calculate": "datum['omni_dbt_ecomm__products.category']" }, { "as": "COLOR", "calculate": "datum['omni_dbt_ecomm__products.category']" } ] } ``` ### Word cloud Word clouds are an eye-catching way to visualize text data by showing the most common words in a dataset. The more frequently a word appears, the bigger and bolder it is, which makes it easy to spot key themes at a glance. To use this example, change the following values in the custom visualization code: * `field` values should match the values in the table * Adjust the `range` to fit your query * Adjust the `domain` to fit your query ```sql title="Example query" theme={null} SELECT category, COUNT(*) AS frequency, RANDOM() * (0.9 - 0.1) + 0.1 AS height, RANDOM() AS width FROM productsGROUP BY 1ORDER BY 2 DESC LIMIT 25; ``` **Example dataset**: ```json expandable title="Visualization code" theme={null} { "mark": "text", "width": "container", "height": "container", "transform": [ { "as": "DIM", "calculate": "datum['category']" }, { "as": "SIZE", "calculate": "datum['frequency']" }, { "as": "COLOR", "calculate": "datum['department']" }, { "as": "X", "calculate": "random() * (0.9 - 0.1) + 0.1" }, { "as": "Y", "calculate": "random()" } ], "encoding": { "x": { "axis": null, "field": "X" }, "y": { "axis": null, "field": "Y" }, "size": { "field": "SIZE", "legend": null }, "text": { "field": "DIM" }, "color": { "field": "COLOR", "scale": { "scheme": "tableau20" }, "legend": null } } } ``` ### Scatter Plot with Color Quadrants Being able to show a scatter plot of values in and showing where they land within specific designated quadrants and above certain thresholds with the easy deliantion of different colors, makes it easily to see where each value lands at a glance. To use this example, change the following values in the custom visualization code: * `calc_1` `calc_2` `calc_3` `calc_4` set the values for your four quadrants, these can also be hard-coded or referenced from calculated fields as noted in the example * Adjust the `users.age` to fit your query * Adjust the `users.count` to fit your query ```sql title="Example query" theme={null} SELECT users.age, users.count, calc_1, calc_2, calc_3, calc_4 FROM users ``` **Example dataset**: ```json expandable title="Visualization code" theme={null} { "layer": [ { "layer": [ { "mark": { "line": false, "type": "area", "tooltip": false }, "encoding": { "y": { "type": "quantitative", "field": "calc_2" }, "color": { "value": "red" } } }, { "mark": { "line": false, "type": "area", "tooltip": false }, "encoding": { "y": { "type": "quantitative", "field": "calc_3" }, "color": { "value": "lightblue" } } }, { "mark": { "line": false, "type": "area", "tooltip": false }, "encoding": { "y": { "type": "quantitative", "field": "calc_1" }, "y2": { "type": "quantitative", "field": "calc_2" }, "color": { "value": "green" } } }, { "mark": { "line": false, "type": "area", "tooltip": false }, "encoding": { "y": { "type": "quantitative", "field": "calc_4" }, "y2": { "type": "quantitative", "field": "calc_3" }, "color": { "value": "purple" } } }, { "mark": { "type": "point", "tooltip": true }, "encoding": { "y": { "axis": { "title": "Users Count + (1)", "format": "NUMBER_0", "orient": "left", "formatType": "omniNumberFormat", "labelOverlap": true }, "type": "quantitative", "field": "users\\.count", "title": "Users Count" }, "color": { "datum": "Users Count" }, "tooltip": [ { "type": "quantitative", "field": "users\\.age", "title": "Age" }, { "type": "quantitative", "field": "users\\.count", "title": "Users Count", "format": "NUMBER_0", "formatType": "omniNumberFormat" }, { "type": "quantitative", "field": "users\\.age_max", "title": "Age Max" } ] } } ] }, { "mark": { "type": "rule", "tooltip": true, "strokeDash": [ 4, 2 ] }, "params": [ { "name": "hover", "select": { "on": "mouseover", "type": "point", "clear": "mouseout", "nearest": true } } ], "encoding": { "opacity": { "value": 0, "condition": { "test": { "empty": false, "param": "hover" }, "value": 1 } }, "tooltip": [ { "type": "quantitative", "field": "users\\.age", "title": "Age" }, { "type": "quantitative", "field": "users\\.count", "title": "Users Count", "format": "NUMBER_0", "formatType": "omniNumberFormat" } ] } } ], "width": "container", "height": "container", "encoding": { "x": { "axis": { "title": "Age", "labelOverlap": true }, "sort": "ascending", "type": "ordinal", "field": "users\\.age", "title": "Age" }, "color": { "scale": { "domain": [ "Users Count", "Age Max" ], "scheme": "omni" }, "legend": null } } } ``` ### Bullet charts Bullet charts are used to track a metric against a target. A bar is used to measure the actual value of the metric, a vertical line or marker for the target, and background bands for adding qualitative ranges. #### Single bullet chart **Example dataset** ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": "bar", "params": [ { "bind": "legend", "name": "omni_click", "select": { "type": "point", "fields": [ "omni__measure_name" ] } } ], "encoding": { "color": { "field": "omni__measure_name" }, "opacity": { "value": 0 } } }, { "layer": [ { "layer": [ { "mark": { "type": "bar", "tooltip": true }, "encoding": { "color": { "field": "omni__measure_name", "legend": null } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Pace" ] } } ] }, { "mark": { "type": "bar", "height": 7, "tooltip": true }, "encoding": { "color": { "field": "omni__measure_name", "legend": null } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Current" ] } } ] }, { "mark": { "type": "tick", "tooltip": true, "thickness": 3 }, "encoding": { "color": { "field": "omni__measure_name", "legend": null } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Target" ] } } ] } ], "encoding": { "x": { "axis": { "title": "Target", "format": "NUMBER_0", "orient": "bottom", "formatType": "omniNumberFormat", "labelOverlap": true }, "type": "quantitative", "field": "omni__measure_value", "stack": null, "title": "Target + (2)" }, "color": { "scale": { "range": [ "#000000ff", "#bcbcbcff", "#A66BBF" ], "domain": [ "Target", "Pace", "Current" ] } }, "order": { "sort": "descending", "type": "quantitative", "field": "omni__key_order" } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Target", "Pace", "Current" ] } } ] } ], "encoding": { "y": { "axis": { "title": null, "labelOverlap": true }, "type": "ordinal", "field": "CATEGORICAL", "title": [ "Category" ] }, "tooltip": [ { "type": "nominal", "field": "CATEGORICAL", "title": [ "Category" ] }, { "type": "quantitative", "field": "CURRENT", "title": [ "Current" ], "format": "NUMBER_0", "formatType": "omniNumberFormat" }, { "type": "quantitative", "field": "PACE", "title": [ "Pace" ], "format": "NUMBER_0", "formatType": "omniNumberFormat" }, { "type": "quantitative", "field": "TARGET", "title": [ "Target" ], "format": "NUMBER_0", "formatType": "omniNumberFormat" } ] }, "transform": [ { "as": [ "omni__measure_name", "omni__measure_value" ], "fold": [ "TARGET", "PACE", "CURRENT" ] }, { "as": "omni__measure_name", "calculate": "{\"TARGET\":\"Target\",\"PACE\":\"Pace\",\"CURRENT\":\"Current\"}[datum.omni__measure_name]" }, { "as": "omni__key_order", "calculate": "indexof([\"Target\",\"Pace\",\"Current\"], datum.omni__measure_name)" }, { "filter": { "param": "omni_click" } } ] } ], "width": "container", "height": "container", "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "transform": [ { "as": "TARGET", "calculate": "datum['products.count']" }, { "as": "PACE", "calculate": "datum['calc_2']" }, { "as": "CURRENT", "calculate": "datum['calc_1']" }, { "as": "CATEGORICAL", "calculate": "datum['calc_3']" } ] } ``` #### Multiple categories Same as the single bullet, just repeated across the categories. **Example dataset** ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": "bar", "params": [ { "bind": "legend", "name": "omni_click", "select": { "type": "point", "fields": [ "omni__measure_name" ] } } ], "encoding": { "color": { "field": "omni__measure_name" }, "opacity": { "value": 0 } } }, { "layer": [ { "layer": [ { "mark": { "type": "bar", "tooltip": true }, "encoding": { "color": { "field": "omni__measure_name", "legend": null } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Pace" ] } } ] }, { "mark": { "type": "bar", "height": 7, "tooltip": true }, "encoding": { "color": { "field": "omni__measure_name", "legend": null } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Current" ] } } ] }, { "mark": { "type": "tick", "tooltip": true, "thickness": 3 }, "encoding": { "color": { "field": "omni__measure_name", "legend": null } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Target" ] } } ] } ], "encoding": { "x": { "axis": { "title": "Target", "format": "NUMBER_0", "orient": "bottom", "formatType": "omniNumberFormat", "labelOverlap": true }, "type": "quantitative", "field": "omni__measure_value", "stack": null, "title": "Target + (2)" }, "color": { "scale": { "range": [ "#000000ff", "#bcbcbcff", "#A66BBF" ], "domain": [ "Target", "Pace", "Current" ] } }, "order": { "sort": "descending", "type": "quantitative", "field": "omni__key_order" } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Target", "Pace", "Current" ] } } ] } ], "encoding": { "y": { "axis": { "title": null, "labelOverlap": true }, "type": "ordinal", "field": "CATEGORICAL", "title": [ "Category" ] }, "tooltip": [ { "type": "nominal", "field": "CATEGORICAL", "title": [ "Category" ] }, { "type": "quantitative", "field": "CURRENT", "title": [ "Current" ], "format": "NUMBER_0", "formatType": "omniNumberFormat" }, { "type": "quantitative", "field": "PACE", "title": [ "Pace" ], "format": "NUMBER_0", "formatType": "omniNumberFormat" }, { "type": "quantitative", "field": "TARGET", "title": [ "Target" ], "format": "NUMBER_0", "formatType": "omniNumberFormat" } ] }, "transform": [ { "as": [ "omni__measure_name", "omni__measure_value" ], "fold": [ "TARGET", "PACE", "CURRENT" ] }, { "as": "omni__measure_name", "calculate": "{\"TARGET\":\"Target\",\"PACE\":\"Pace\",\"CURRENT\":\"Current\"}[datum.omni__measure_name]" }, { "as": "omni__key_order", "calculate": "indexof([\"Target\",\"Pace\",\"Current\"], datum.omni__measure_name)" }, { "filter": { "param": "omni_click" } } ] } ], "width": "container", "height": "container", "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "transform": [ { "as": "TARGET", "calculate": "datum['products.count']" }, { "as": "PACE", "calculate": "datum['calc_2']" }, { "as": "CURRENT", "calculate": "datum['calc_1']" }, { "as": "CATEGORICAL", "calculate": "datum['products.category']" } ] } ``` #### Multiple categories with conditional coloring Using the same result set as the multiple categories, the bars are colored by whether they are above or below the pacing. **Example dataset** ```json expandable title="Visualization code" theme={null} { "layer": [ { "mark": "bar", "params": [ { "bind": "legend", "name": "omni_click", "select": { "type": "point", "fields": [ "omni__measure_name" ] } } ], "encoding": { "color": { "field": "omni__measure_name" }, "opacity": { "value": 0 } } }, { "layer": [ { "layer": [ { "mark": { "type": "bar", "tooltip": true }, "encoding": { "color": { "field": "omni__measure_name", "legend": null } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Pace" ] } } ] }, { "mark": { "type": "bar", "height": 7 }, "encoding": { "color": { "value": "darkred", "condition": { "test": "datum.ON_PACE == true", "value": "darkgreen" } } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Current" ] } } ] }, { "mark": { "type": "tick", "tooltip": true, "thickness": 3 }, "encoding": { "color": { "field": "omni__measure_name", "legend": null } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Target" ] } } ] } ], "encoding": { "x": { "axis": { "title": "Target", "format": "NUMBER_0", "orient": "bottom", "formatType": "omniNumberFormat", "labelOverlap": true }, "type": "quantitative", "field": "omni__measure_value", "stack": null, "title": "Target + (2)" }, "color": { "scale": { "range": [ "#000000ff", "#bcbcbcff", "#A66BBF", "#b50000ff" ], "domain": [ "Target", "Pace", "Current", "On Pace" ] } }, "order": { "sort": "descending", "type": "quantitative", "field": "omni__key_order" } }, "transform": [ { "filter": { "field": "omni__measure_name", "oneOf": [ "Target", "Pace", "Current" ] } } ] } ], "encoding": { "y": { "axis": { "title": null, "labelOverlap": true }, "type": "ordinal", "field": "CATEGORICAL", "title": [ "Category" ] }, "tooltip": [ { "type": "nominal", "field": "CATEGORICAL", "title": [ "Category" ] }, { "type": "quantitative", "field": "CURRENT", "title": [ "Current" ], "format": "NUMBER_0", "formatType": "omniNumberFormat" }, { "type": "quantitative", "field": "PACE", "title": [ "Pace" ], "format": "NUMBER_0", "formatType": "omniNumberFormat" }, { "type": "quantitative", "field": "TARGET", "title": [ "Target" ], "format": "NUMBER_0", "formatType": "omniNumberFormat" }, { "field": "ON_PACE" } ] }, "transform": [ { "as": [ "omni__measure_name", "omni__measure_value" ], "fold": [ "TARGET", "PACE", "CURRENT", "ON_PACE" ] }, { "as": "omni__measure_name", "calculate": "{\"TARGET\":\"Target\",\"PACE\":\"Pace\",\"CURRENT\":\"Current\",\"ON_PACE\":\"On Pace\"}[datum.omni__measure_name]" }, { "as": "omni__key_order", "calculate": "indexof([\"Target\",\"Pace\",\"Current\",\"On Pace\"], datum.omni__measure_name)" }, { "filter": { "param": "omni_click" } } ] } ], "width": "container", "height": "container", "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "transform": [ { "as": "TARGET", "calculate": "datum['products.count']" }, { "as": "PACE", "calculate": "datum['calc_2']" }, { "as": "CURRENT", "calculate": "datum['calc_1']" }, { "as": "CATEGORICAL", "calculate": "datum['products.category']" }, { "as": "ON_PACE", "calculate": "datum.CURRENT > datum.PACE" } ] } ``` #### Bullet chart inside a table Additional detail per column, row banding, conditional coloring and sizing. Fancy! **Example dataset**: ```json expandable title="Visualization code" theme={null} { "data": { "name": "bullet_chart_data" }, "width": 640, "config": { "bar": { "binSpacing": 10 }, "axis": { "grid": false }, "view": { "stroke": null } }, "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "vconcat": [ { "height": 40, "hconcat": [ { "mark": { "type": "text", "align": "center", "baseline": "middle" }, "width": 120, "encoding": { "x": { "value": 60 }, "y": { "value": 20 }, "text": { "value": "Campaign" }, "color": { "value": "#1a7e83" } } }, { "mark": { "type": "text", "align": "center", "baseline": "middle" }, "width": 60, "encoding": { "x": { "value": 30 }, "y": { "value": 20 }, "text": { "value": "Length" }, "color": { "value": "#1a7e83" } } }, { "mark": { "type": "text", "align": "center", "baseline": "middle" }, "width": 80, "encoding": { "x": { "value": 40 }, "y": { "value": 20 }, "text": { "value": "Flight" }, "color": { "value": "#1a7e83" } } }, { "mark": { "type": "text", "align": "center", "baseline": "middle" }, "width": 360, "encoding": { "x": { "value": 180 }, "y": { "value": 20 }, "text": { "value": "" }, "color": { "value": "#1a7e83" } } } ], "spacing": 0 }, { "layer": [ { "mark": "rect", "encoding": { "x": { "value": 0 }, "y": { "axis": null, "sort": "ascending", "type": "ordinal", "field": "row_id" }, "x2": { "value": 660 }, "color": { "type": "nominal", "field": "is_even_row", "scale": { "range": [ "#f5f5f5", "white" ] }, "legend": null } } }, { "mark": { "type": "text", "align": "center", "baseline": "middle" }, "encoding": { "x": { "value": 60 }, "y": { "axis": null, "type": "ordinal", "field": "row_id" }, "text": { "field": "campaign_display" } } }, { "mark": { "type": "text", "align": "center", "baseline": "middle" }, "encoding": { "x": { "value": 150 }, "y": { "axis": null, "type": "ordinal", "field": "row_id" }, "text": { "field": "bullet_chart_data\\.creative_length" } } }, { "mark": { "type": "text", "align": "center", "baseline": "middle" }, "encoding": { "x": { "value": 220 }, "y": { "axis": null, "type": "ordinal", "field": "row_id" }, "text": { "field": "bullet_chart_data\\.flight" } } }, { "mark": { "size": 35, "type": "bar", "tooltip": true }, "encoding": { "x": { "axis": null, "type": "quantitative", "field": "bullet_chart_data\\.goal", "scale": { "range": [ 270, 620 ] } }, "y": { "axis": null, "type": "ordinal", "field": "row_id" }, "color": { "value": "#a0cfd2" } } }, { "mark": { "size": 10, "type": "bar" }, "encoding": { "x": { "type": "quantitative", "field": "bullet_chart_data\\.delivery__pacing_behind_", "scale": { "range": [ 250, 620 ] } }, "y": { "axis": null, "type": "ordinal", "field": "row_id" }, "color": { "value": "#f97068" } } }, { "mark": { "size": 20, "type": "bar" }, "encoding": { "x": { "type": "quantitative", "field": "bullet_chart_data\\.delivery__pacing_ahead_", "scale": { "range": [ 250, 620 ] } }, "y": { "axis": null, "type": "ordinal", "field": "row_id" }, "color": { "value": "#096184" } } }, { "mark": { "type": "tick", "color": "#ffbb61", "orient": "vertical", "thickness": 4 }, "encoding": { "x": { "type": "quantitative", "field": "flight_marker", "scale": { "range": [ 250, 620 ] } }, "y": { "axis": null, "type": "ordinal", "field": "row_id" } } }, { "mark": { "dx": 5, "type": "text", "align": "left", "baseline": "middle" }, "encoding": { "x": { "type": "quantitative", "field": "bullet_chart_data\\.goal", "scale": { "range": [ 250, 620 ] } }, "y": { "axis": null, "sort": "ascending", "type": "ordinal", "field": "row_id" }, "text": { "field": "pacing_percentage", "format": ".0%" } } } ], "height": 420 } ], "transform": [ { "sort": [ { "field": "bullet_chart_data\\.campaign", "order": "ascending" }, { "field": "bullet_chart_data\\.creative_length", "order": "ascending" } ], "window": [ { "as": "row_id", "op": "row_number" }, { "as": "prev_campaign", "op": "lag", "field": "bullet_chart_data\\.campaign" } ] }, { "as": "campaign_display", "calculate": "datum['bullet_chart_data.campaign'] === datum.prev_campaign ? '' : datum['bullet_chart_data.campaign']" }, { "sort": [ { "field": "bullet_chart_data\\.campaign", "order": "ascending" } ], "window": [ { "as": "campaign_band_group", "op": "dense_rank", "field": "bullet_chart_data\\.campaign" } ] }, { "as": "is_even_row", "calculate": "datum.campaign_band_group % 2 === 0" }, { "as": "flight_marker", "calculate": "datum['bullet_chart_data.goal'] * datum['bullet_chart_data.flight_completion__']" }, { "as": "pacing_percentage", "calculate": "(datum['bullet_chart_data.delivery__pacing_behind_'] + datum['bullet_chart_data.delivery__pacing_ahead_']) / datum['bullet_chart_data.goal']" } ], "description": "Campaign table with suppressed duplicate campaign names and banded rows grouped by campaign." } ``` # Funnel charts Source: https://docs.omni.co/visualize-present/visualizations/types/funnel Funnel charts visualize sequential stages in a process, showing conversion rates and drop-off between each step. A funnel chart displays values across sequential stages, with each stage represented as a progressively narrower segment. The width of each segment corresponds to its value, making it easy to identify where drop-off occurs in a process. Recreate this chart in Omni by downloading the [sample data](https://github.com/exploreomni/doc-sample-data/blob/main/visualizations/funnel.csv) and then [uploading the CSV as a source table](/analyze-explore/data-input-csvs)! ## Use cases Funnel charts are particularly useful for visualizing: * Conversion funnels showing user progression through a workflow * Sales pipelines tracking deals from lead to close * Customer journey stages from awareness to purchase * Application processes with multiple steps * Any sequential process where you want to highlight drop-off between stages ## Data structure Funnel charts require at least one dimension and one measure: * **Stage** - The sequential steps in your process (dimension) * **Value** - The count or value at each stage (measure) The funnel chart option becomes available once you have the required fields in your query. When setting up your query, keep the following in mind: * Stages should be ordered sequentially to accurately represent the flow * Values typically decrease at each stage, though this is not required * Use measures that make sense to compare across stages (e.g., user count, deal value) ## Configuration To view the configuration options for a funnel chart, open the **Chart options** panel in a workbook: ### Orientation and alignment The **Orientation** setting controls how the funnel is displayed: * **Vertical** - Stages arranged top to bottom with the widest segment at the top * **Horizontal** - Stages arranged left to right with the widest segment on the left And the **Alignment** setting controls the vertical positioning of the funnel: * **Left** - Aligns the funnel to the left * **Center** - Aligns the funnel in the center * **Right** - Aligns the funnel to the right ### Gap spacing The **Gap** setting controls the amount of whitespace (in pixels) between each stage in the funnel. ### Color Funnel charts support standard color configuration options: * Assign colors to individual stages * Use color palettes for automatic coloring * Apply [modeled colors](/visualize-present/visualizations/configuration/color#dimension-colors) when defined When coloring by a continuous numeric field, you can pin gradient color scale values (minimum, midpoint, and maximum) instead of using automatic data ranges. See [Gradient color scale values](/visualize-present/visualizations/configuration/color#gradient-color-scale-values) for more information. ### Labels Toggle data labels to display stage names and values on the chart. Access the following label options by clicking the icon above the **Color and legend** and **Value** sections. Click the **Data labels** checkbox to enable label visibility, which will display some label configuration options: * **Position** - Where labels appear relative to each segment. Available positions depend on the funnel orientation: * **Horizontal** - Top, bottom, or middle * **Vertical** - Left, right, or middle * **Font styling** - Adjust the label text size, color, and styling (bold, italic) * **Format** - Number formatting options, such as currency or percentage and decimal places * **% change** - Display a conversion percentage alongside each label. Options include: * **None** - No percentage will display * **Percent of first** - Each stage's value as a percentage of the first stage * **Percent of previous** - Each stage's value as a percentage of the preceding stage * **% change format** - Control how many decimal places appear in the percentage value ### Tooltips Tooltips appear when hovering over funnel segments and display information about each stage. By default, tooltips show both the percent of first and percent of previous stage values for each segment. You can format or hide these values individually. Use the [tooltip configuration](/visualize-present/visualizations/configuration/tooltips) to further customize what information appears and add additional fields. ## Next steps * Learn more about [color configuration](/visualize-present/visualizations/configuration/color) * Explore [tooltip customization](/visualize-present/visualizations/configuration/tooltips) * Review other [chart types](/visualize-present/visualizations/types/index) # Heatmap Charts Source: https://docs.omni.co/visualize-present/visualizations/types/heatmap Create heatmap visualizations in Omni to display data density and patterns using color gradients across two-dimensional grids. ## Examples **Heatmap:** ## Data Structures Heatmaps can work with pivoted or unpivoted data, using 2 dimensions and one measure, or with all dimensions where there is a numeric available for the color facet. They often use two time facets, for example: * `date` & `hour_of_day` * `week` & `day_of_week` * `month` & `year` ## Configuration There is no heatmap specific configuration, but [color](/visualize-present/visualizations/configuration/color) and [tooltip](/visualize-present/visualizations/configuration/tooltips) controls may be relevant. Heatmaps support gradient color scale value pins for the color field. You can pin specific minimum, midpoint, and maximum values for the color scale instead of using automatic data ranges. This is useful when you want to maintain consistent color mapping across multiple heatmaps or time periods. For details on configuring gradient color scales, see [Gradient color scale values](/visualize-present/visualizations/configuration/color#gradient-color-scale-values). # Overview Source: https://docs.omni.co/visualize-present/visualizations/types/index Browse all built-in Omni visualization types, including bar, line, area, map, pie, KPI, table, and custom Vega-Lite charts. Omni has many visualizations types out of the box for presenting data. Each chart type supports configuration options across the overall visualization, series, and chart facets like axes if applicable. Additionally, for configuration beyond the UI controls, any of the visualizations built from Vega-lite have an [advanced option](/visualize-present/visualizations/types/custom) to allow full customization of the Vega-lite spec. ## Built-in visualizations * [AI summary](/visualize-present/visualizations/types/ai-summary) * [Area charts](/visualize-present/visualizations/types/area) * [Bar charts](/visualize-present/visualizations/types/bar) * [Boxplot](/visualize-present/visualizations/types/boxplot) * [Funnel charts](/visualize-present/visualizations/types/funnel) * [Heatmap](/visualize-present/visualizations/types/heatmap) * [KPIs](/visualize-present/visualizations/types/kpi) * [Line charts](/visualize-present/visualizations/types/line) * [Maps](/visualize-present/visualizations/types/map) * [Markdown tiles](/visualize-present/visualizations/types/markdown) * [Pie & donut charts](/visualize-present/visualizations/types/pie) * [Sankey charts](/visualize-present/visualizations/types/sankey) * [Scatterplots](/visualize-present/visualizations/types/scatterplot) * [Single record](/visualize-present/visualizations/types/single-record) * [Tables](/visualize-present/visualizations/types/table) You can also build [custom visualizations](/visualize-present/visualizations/types/custom) with Vega! ## Configuring visualizations * [Series mapping](/visualize-present/visualizations/configuration/series-mapping) * [Series configuration](/visualize-present/visualizations/configuration/series-configuration) * [X-Axis](/visualize-present/visualizations/configuration/x-axis) * [Y-Axis (Left Axis, Right Axis)](/visualize-present/visualizations/configuration/y-axis) * [Color](/visualize-present/visualizations/configuration/color) * [Size](/visualize-present/visualizations/configuration/size) * [Tooltips](/visualize-present/visualizations/configuration/tooltips) # KPI Source: https://docs.omni.co/visualize-present/visualizations/types/kpi KPI visualizations highlight the metrics that matter most, with components for single values, comparisons, progress to a goal, sparklines, text, and images. KPI visualizations spotlight key metrics and data points, from a single headline number to side-by-side comparisons and progress toward a goal. Each KPI is built from one or more rows, and every row can be a different component type, giving you fine-grained control over layout and presentation. Overview of a KPI visualization showing several component types ## Adding components KPIs support several types of components, allowing you to customize the content and layout of your visualization. Click the **Add** button in the visualization to add a new component. ## Customizing components To customize the display of a component, click the component in the visualization editor. Use the **KPI Builder** tab in the chart configuration options to make changes to the component. ## Component types KPIs support several component types, each suited to a different way of presenting data. You can mix and match them within a single visualization. ### Number Highlights a single value. A KPI number component highlighting a single value Automatically scale the text size of number components by setting **KPI numbers** to **Dynamic size** in the chart configuration's **Style** tab. When set, numbers will dynamically change size as tiles are resized or dashboard layouts are changed. **Not supported for classic dashboards.** ### Comparison Comparison components compare one value to another and support comparing across columns and pivots. Select the same column for both comparison fields to compare two rows within a dataset. A KPI comparison component comparing one value to another ### Progress Compares two values. Useful for showing progress to a goal. Can be displayed as a bar (shown) or a circle. A KPI progress component shown as a bar Compare to a static number - like a goal - by adding a column to the query that always returns the same number. ### Chart Chart components display a mini sparkline, bar, or line chart. Renders a sparkline by default. A KPI chart component rendered as a sparkline ### Text [Markdown](https://www.markdownguide.org/cheat-sheet/) enabled free text. Useful for titles, headings, and descriptions. For complex layouts, use the [Markdown visualization](/visualize-present/visualizations/types/markdown). A KPI text component displaying Markdown-formatted text ### Image Images display an inline image. Configured by providing a URL to a publicly accessible image. A KPI image component displaying an inline image Use [Mustache](/visualize-present/mustache-reference) to parameterize the URL. For example, `https://en.gravatar.com/{{result._first.users.img_link}}` ## Styling options Use the **Style** tab in the chart configuration options to customize the alignment and text sizes for KPI components. The Style tab of the KPI chart configuration options ## Converting to raw Markdown If you want to customize a KPI beyond Omni's built-in options, you can convert the visualization directly to Markdown by changing the visualization type to **Markdown**. To undo changes, use the back button in your browser. # Line charts Source: https://docs.omni.co/visualize-present/visualizations/types/line Build line chart visualizations in Omni to display trends, time series, and comparisons with multi-series and stacking options. ## Examples **Basic Lines:** **Stack 100:** **Monotone:** **Dashed:** **Dual Axes:** ## Data Structures Line charts can work with pivoted or unpivoted data, using 2 dimensions and one measure. To stack or group a chart, one series should be moved to the color facet. **Unpivoted Data:** **Pivoted Data** Additionally line charts can plot using several measures at once: ## Line Configuration Notes Several configuration options are offered for how lines appear, including showing points, style, weight, interpolation, points ### Line Mark This is the line icon on each axis, and holds all of the overall configuration options. ### Show Points Points can be toggles on/off to show alongside the lines (default contains no points). ### Dashes vs Solid Lines Whether or not series are shown as solid lines or dashed lines is available (default solid). ### Line Thickness The weight or thickness can be controlled (default 1). ### Line Opacity Setting is available to make the line partially transparent (default solid). ### Point Interpolation for Lines The method for interpolation between points can be controlled (default linear). Options include: * Linear * Monotone (smoothed) * Step (point at midpoint of the step) * Step Before * Step After ## Overall Configuration Notes The mark selector at the top of the configuration sets the global chart configuration (configuration across all series). Note that each series can be set independently to bar, line, scatter, area independently under their y-axis controls. The color section controls overall stacking and grouping behavior overall. Additionally stack can be set independently on the different y-axis, under the y-axis series configuration (useful for overall grouping of two stacked grouplets): * Automatic: we'll guess for you * Stack: Series on same x-axis value, ontop of each other * Group: Series offset from their baseline x-axis mark into grouplets * Overlay: Series *ontop* of each other (usually very undesirable, but useful in rare cases) * Stack %: Series rebased to 100% across each x-axis value ## Other Notes * Time dimension axes are set to temporal with lines, meaning points will be displayed along a continuous time axis. For charts where ordinal behavior is desired, it's recommended to toggle the individual series from a bar chart accelerator. * With time fields, order will be automatically set to ascending; other data types will obey the table ordering when graphing * Tooltips have two styles (see below): * On line charts with multiple measures, hover will highlight all available series along the x-axis vertically, vs just the series being hovered. * On line charts with a dimension mapped to color (and a single measure), the hover will only show the nearest point # Maps Source: https://docs.omni.co/visualize-present/visualizations/types/map Omni currently supports point and region map types. ## Point maps Data with latitude-longitude pairs can be visualized as a point map. Points can be sized and colored by additional properties in the dataset. **Map with Color Pins** **Map with Sized Pins:** ## Region maps Data with region-based location information can be visualized as a region map. Omni offers region-based mappings for countries and US states out of the box, and offers a custom region option for greater flexibility. ### Built-in countries Country region data can be mapped against your dataset by either country name, 2-digit country code or 3-digit country code. | Dataset | Map | | -------------- | -------------- | | | | ### Built-in US States US state region data can be mapped against your dataset by either name or 2-digit code. | Dataset | Map | | -------------- | -------------- | | | | ### Custom Regions Omni allows you to specify your own region data via URL. You can specify an endpoint that returns region data complying to either the [GeoJSON](https://datatracker.ietf.org/doc/html/rfc7946) or [TileJSON](https://github.com/mapbox/tilejson-spec/blob/84008d750e54f37739e24785276596f40ccafeab/3.0.0/README.md) specifications. In order to use custom regions, you'll need to set your region type to "Custom" and then fill out the following fields: * **Source type** - specify whether your region source is GeoJSON or TileJSON * **Source URL** - the URL from which to load your GeoJSON or TileJSON data * **Source layer** (TileJSON only) - the layer within the TileJSON specification you want to map against * **Region property** - the property in the GeoJSON or TileJSON data that you want to map against | Dataset | Map | | -------------- | -------------- | | | | ## Color configuration Both region maps (filled maps) and point maps support gradient color scale value pins when coloring by continuous numeric fields. This allows you to pin specific minimum, midpoint, and maximum values for the color scale instead of always using the automatic data range. For example, if you want to ensure that a specific value always maps to the same color across different time periods or regions, you can pin the min and max values of the color scale to maintain consistent color mapping. For more information about configuring gradient color scales and pinning values, see [Gradient color scale values](/visualize-present/visualizations/configuration/color#gradient-color-scale-values). ## Projection types Point and region maps support 2D (mercator) and 3D (globe) projections. | 2D (Mercator) | 3D (Globe) | | -------------- | -------------- | | | | Point maps also support heatmap projections: ## Initial viewport When working in the workbook editor, you can save a fixed map viewport (center and zoom level) for both point and region maps. Once saved, the map will maintain your chosen view instead of automatically fitting to the data. To set an initial viewport, pan and zoom the map to your desired view, then click the **Set current view as initial view** control in the map toolbar. The map will display **Fixed view** in the visualization settings once a viewport is saved. When an initial viewport is set, the map will maintain that view even when data or filters change. To restore the default auto-fit behavior, click **Reset to fit data** in the visualization settings, or use the **Reset map** control on the map itself. The initial viewport feature is only available in the workbook editor. It is not available on dashboards or in embedded/read-only sessions. ## Custom visualizations More complex map visualizations can be unlocked using [advanced visualization](/visualize-present/visualizations/types/custom). # Markdown visualizations Source: https://docs.omni.co/visualize-present/visualizations/types/markdown Build custom Markdown visualizations in Omni that combine text, images, links, iframes, and live query data in a single tile. Markdown visualizations allow for a combination of Markdown elements and query variables. You can use it to create a visualization that includes text, images, links, data, iframes, and more. ## Creating Markdown with AI You can use the [Query Helper](/ai/queries) to generate markdown visualizations based on natural language prompts. The AI will create rich, flexible data displays that combine HTML, CSS, Mustache template variables, and [custom Omni components](#adding-visual-components) like `` and ``. To create a Markdown visualization with AI: Create a query in a workbook. Open the Query Helper. Ask Blobby to create a custom layout (e.g., "Create a custom HTML layout for this data" or "Show this as a formatted text display with sparklines") Review and refine the generated Markdown visualization as needed. Once generated, you can continue to refine the visualization through the chat or manually edit it using the Markdown editor. To learn more about building visualizations with AI, refer to [Generating visualizations with AI](/ai/visualizations). ## Using the Markdown editor When you select **Markdown** as the visualization type, a Markdown editor will display in the chart's **Options** pane. As changes are made, the chart area will automatically update. At the top of the editor is a toolbar to help you generate correct [Markdown syntax](https://www.Markdownguide.org/cheat-sheet/) for common formatting actions. The Markdown editor in the Options pane with a formatting toolbar at the top You can also access the Markdown editor in a draft dashboard by clicking the icon on a Markdown tile and selecting **Edit in chart**. The tile will update as you make changes in the editor. Editing a Markdown tile from a draft dashboard using the Edit in chart option ### Including HTML The Markdown editor interprets Markdown first and foremost. While it is possible to incorporate HTML, it helps to think of these more as text documents than true HTML files. When formatting your code, keep the following in mind: * **Indentation is interpreted as a code block**. Keep your code flush to the left to prevent unintended code blocks. * **Empty lines may cause odd behavior**. In Markdown, these are paragraph indicators. This occurs because the `div` is included in a code block as plain text, which will strand its closing tag. Omni sanitizes your HTML and CSS to prevent potential security vulnerabilities. This includes removing JavaScript and interactive elements such as `
`, ``, and `