Acumatica · Embedded

Embedded Analytics Patterns — A Field Guide

Embedded Analytics Patterns — A Field Guide is the work that turns raw data into decisions. The pipeline from "we have data" to "we have a model that runs in production" is the.

John Kihiu12 min read

Embedded analytics means putting charts, dashboards, and reports directly inside the product a customer already uses, instead of sending them to a separate BI tool. Done well it feels like a native feature; done poorly it feels like an iframe someone forgot to style — and the difference is almost entirely in a handful of decisions made early: build vs. buy, multi-tenancy, and how much interactivity to expose.

Build your own charts or embed a BI platform

Two real paths exist. The first is building on a charting library (Recharts, Observable Plot, ECharts, D3 directly for anything custom) against your own aggregation queries — full design control, but you own every filter, drilldown, and export feature yourself. The second is embedding a BI platform designed for this: Looker embedded, Tableau Embedded Analytics, Superset, Metabase's embedding SDK, or Cube for the semantic/metrics layer paired with any frontend. Embedding a BI tool gets you pivot tables, saved filters, and export-to-PDF for free; it also means shipping another vendor's design language wrapped in your CSS, with a ceiling on how deeply you can customize it.

Most teams underestimate "just build it"

A single well-designed dashboard with 4-6 charts against a pre-aggregated table is a few days of work with a charting library. The complexity people actually pay for — ad-hoc filtering, saved views, drilldowns into raw data — is where a dedicated embedded-BI platform starts paying for itself.

Row-level security is the part that can't be an afterthought

In a multi-tenant SaaS product, every embedded query has to be scoped to the requesting customer's data, and that scoping has to happen at the query layer, not filtered client-side after the fact. The reliable pattern is a tenant ID injected server-side into every query — either as a mandatory `WHERE tenant_id = :current_tenant` enforced by a query-building layer the frontend can't bypass, or via database-level row-level security (Postgres RLS policies keyed off a session variable) so even a raw SQL mistake can't leak across tenants.

SQL · Postgres row-level security
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON orders
  USING (tenant_id = current_setting('app.current_tenant')::uuid);

-- Set once per connection/session before running any query
SET app.current_tenant = 'a1b2c3d4-...';
Client-side filtering is not isolation

Fetching all tenants' data and filtering to the current tenant in the browser is a data leak waiting for a bug — dev tools, a race condition, or a caching layer will eventually expose the unfiltered response. Isolation has to happen before the data leaves the database or API layer.

Dashboards need pre-aggregated data, not live OLTP queries

Running dashboard queries directly against the production OLTP database works for a demo and falls over under real usage — a GROUP BY over millions of transactional rows on every dashboard load competes with the application's own write traffic. The standard fix is a separate read path: a materialized view, a nightly or streaming ETL into a columnar store (ClickHouse, DuckDB, or a warehouse), or a semantic layer like Cube that caches aggregated results. The dashboard queries the pre-aggregated layer; the OLTP database never sees analytical query load.

Iframe vs. SDK vs. native components

The three common embedding mechanisms are an iframe pointed at a hosted dashboard (fastest to ship, least customizable, and awkward for passing auth/context), a JavaScript SDK that renders components into your own DOM (Looker's embed SDK, Tableau's, most modern platforms), or fully native components built against a metrics API where you control every pixel. SDK-based embedding is the common middle ground now — real integration with your app's auth and styling, without building the entire visualization layer yourself.

ApproachCustomizationBuild effort
Iframe embedLowLowest
BI platform SDK embedMedium-HighMedium
Fully custom (charting lib + own API)FullHighest

Wrapping up

The decisions that matter most in embedded analytics happen before a single chart is drawn: whether to build or embed, how tenant isolation is enforced at the query layer, and whether dashboards read from a pre-aggregated store instead of production OLTP tables. Get those three right and the visualization layer is the easy part.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.