Embedding a dashboard takes a day. The seven layers around it — RLS, custom domains, SOC 2 audit, SSO, token refresh — take months, and break differently for every BI vendor.

A 2-hour iframe demo is what every BI vendor’s sales engineer shows you. It works, you think. We can ship this in a sprint.

You can’t.

The iframe is the only thing in the demo that scales linearly. Every piece of plumbing around it — the part that matters when you have 200 paying customers instead of 1 internal stakeholder — bends to a different shape per vendor and keeps bending as you add the next.

Here’s what actually shows up in the backlog after the demo.

1. Multi-tenant row-level security

Your warehouse has a column called tenant_id. Your customers have to see only their rows. Tableau calls this User Filters. Power BI calls it Effective Identities. QuickSight calls it Session Tags. Metabase calls it Sandboxing. Each ships a different way of declaring who the viewer is, and a different failure mode when you get it wrong: silent data leak, blank dashboard, or — worst case — a 500 your customer sees and you don’t.

When you add the second BI vendor, you don’t get to reuse the rules. You re-implement them. See Row-level security across BI vendors for the actual contract per vendor.

2. White-label theming and custom domains

The default embed comes with the vendor’s chrome — fonts, padding, modal styles, “Powered by Tableau” badges. Your enterprise customers will not accept this on a screen branded with their logo. So you negotiate the embed CSS, which only works for some elements, and only on some plans.

Then someone asks for analytics.acme.com instead of embed.yourapp.com. The vendor supports this on Enterprise tier. The price triples.

3. Token lifecycle and refresh

The vendor gives you a JWT. It expires in 5 minutes. Cool, sign a new one server-side. Except the embed is already rendered in the iframe and the vendor’s SDK doesn’t tell you when expiry is coming. The dashboard goes blank mid-presentation. Now you’re writing token refresh logic that runs in the parent frame, listens for postMessage events from the iframe, and rotates without flickering.

You wrote this for vendor A. For vendor B the postMessage events are different. For vendor C there are no events — you have to poll.

4. SSO and identity mapping

Your customer signs in with Okta. The token asserts sub: user@acme.com. Tableau wants siteUserId. Power BI wants effectiveIdentities[0].username. QuickSight wants a session role ARN. Metabase wants a Metabase user ID.

For every user signing into your product, your code now translates one identity into N vendor-specific identities, lazily provisions viewer accounts with matching attributes, and rotates them when the user’s role changes. None of this is in any vendor’s docs.

5. SOC 2-grade audit trail

Your customer’s auditor asks: “Show me every report viewed by user X between January and March.” This is reasonable. None of the embedded BI vendors give you this out of the box.

Tableau’s logs are buried in the server admin panel and don’t include embed context. Power BI’s tenant audit log doesn’t capture embed events. QuickSight has CloudTrail, which is technically logging but unstructured for SOC 2 narratives. Metabase has activity tracking that doesn’t survive an instance reset.

So you build it yourself: every signed token, scoped to a tenant, logged immutably, retained for 7 years, exportable to your customer’s SIEM.

6. Cross-vendor consistency

You shipped Power BI embedding because your first 5 customers asked for it. Customer 6 has Tableau. Customer 7 has QuickSight (they’re an AWS shop). Customer 8 has Metabase (they’re cost-sensitive).

Now you maintain four parallel implementations of the same feature set. New row-level security rule? Implement four times. New audit requirement? Four times. New 2FA flow for embed previews? Four times. The first vendor took six months. The fourth one will also take six months — none of the previous work transfers.

7. The edge cases nobody asks about until they’re broken

A viewer hits the dashboard from an airplane. Token expires while they’re offline. They land, refresh, get a 401. Your support engineer has to explain why the demo at the all-hands didn’t work. Multiply by every viewer with patchy WiFi.

Or: the viewer is on iOS Safari. Third-party cookie blocking nukes the embed. You spend three weeks on partitioned cookies and the Storage Access API.

These bugs do not exist in the iframe demo. They exist in production.

What this is actually telling you

The iframe is a 2-day project. The seven things around it are 6 to 12 months — and “around it” is where every customer-facing requirement lives. Build vs. buy isn’t really a question of “can we wire up an iframe” (you can). It’s “do we want to own seven systems we don’t sell, in addition to the one we do?”

If your team’s roadmap has the words “embedded analytics” on it for next quarter, the honest version of that line item is: “build a customer-facing identity, RLS, audit, theming, token-refresh, and multi-vendor abstraction layer, on top of which we render charts.”

That’s what Embedportal is. For the pricing-side of this argument, see How embedded analytics pricing actually works in 2026 — the iframe is free; the seven layers are what you’re actually paying for.

 

 

 

Curious how this would work on your own data?

Try EmbedPortal →
Scroll to Top