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.
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.
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-...';
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.
| Approach | Customization | Build effort |
|---|---|---|
| Iframe embed | Low | Lowest |
| BI platform SDK embed | Medium-High | Medium |
| Fully custom (charting lib + own API) | Full | Highest |
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.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.