Overview
When you embed a shared dashboard (/share/application/:id) as an iframe, Upsolve
keeps its URL filter state in sync with your host application over the browser
postMessage
API. This lets you:
- Read the embedded view’s filter state — e.g. mirror it into your own URL so the dashboard’s filtered state is deep-linkable and survives a refresh.
- Drive the embedded view from your own UI — push filter changes down without reloading the iframe.
- Size the iframe to its content so the dashboard scrolls with your page instead of inside a fixed-height box — see Auto-height.
This applies to embeds of
/share/application/:id. Filters are expressed as
URL query params — see URL Filter Parameters
for the f_ omnibar param format.Message schema
Every message has atype and a numeric version v. Pin to the version you build
against; we bump v for any breaking change to a payload shape.
Current version:
v: 1.
Security: lock down origins
The iframe never posts to"*". Instead, you declare your origin to the iframe
via a parentOrigin query param in the iframe src:
parentOrigin is a well-formed http(s) origin, only accepts
messages whose event.origin matches it, and only posts back to it. On your side,
always validate event.origin against the iframe’s origin before trusting a
message, and pass an explicit targetOrigin when you post — never "*".
Auto-height
An iframe has no intrinsic height. It is a replaced element with a spec default of 300×150 and no content-driven sizing, soheight: auto does nothing and
height: 100% only resolves if every ancestor has a definite height. Whatever
height you pick, the dashboard lays itself out inside it and everything past it
scrolls inside the frame: your reader gets a second scrollbar, your page can
never scroll the dashboard as part of its own content, and a print or
full-page screenshot of your page captures only the visible slice.
Add autoHeight=true to the iframe src and the embed instead:
- lays out from its content rather than pinning itself to the iframe viewport (nothing inside the embed scrolls on its own), and
- posts
embed:heightwith that content height, on load and on every change — a chart finishing its load, a filter bar wrapping to a second line, a re-layout after you resize the frame.
autoHeight needs parentOrigin — as with every other message, the embed will
not post to "*", so without a declared origin there is nothing to listen for.Notes
- Give the frame a starting height anyway. The first
embed:heightarrives after the page mounts; until then the frame is whatever CSS says it is. A sensible initial height (or a skeleton) avoids a visible jump from 150px. - Nothing scrolls inside the frame. Auto-height removes the embed’s internal
scroll containers on purpose — with one in place, content that sits outside the
normal flow ends up in its scroll area rather than in the height we report to
you, i.e. behind a scrollbar you cannot see. A dashboard wider than the frame
therefore scrolls the frame’s own document horizontally rather than a panel
inside it; keep the iframe at
width: 100%and that does not arise. - Sticky elements stop being sticky. The dashboard’s filter bar sticks to the top of the scrollport, and in an auto-height embed there is no scrollport inside the frame — your page owns the scrolling. The bar scrolls away with the content.
- Width still comes from you. Auto-height is height only: keep the iframe at
width: 100%and the dashboard reflows to it. - Heights are capped at 20,000px. A page that somehow sized itself off the viewport could otherwise grow a little on every round trip; past the cap the embed simply scrolls internally again.
- Older embeds ignore the param. If you host a pinned Upsolve version that
predates this,
autoHeight=trueis inert and noembed:heightever arrives — so keep whatever height fallback you have today and let a reported height supersede it.
Consumer reference implementation
Drop this into the page that hosts the iframe. It mirrors the iframe’s filter state into your own URL bar, and (optionally) pushes your URL’s filters down on load.Pushing filters live
To change the embedded view’s filters from your own UI after load — without reloading the iframe — post anembed:set-params message at any time:
Notes & gotchas
- Send params only after
embed:ready. If you postembed:set-paramsbefore the iframe is listening, it is silently dropped. Wait for the handshake. embed:paramsechoes. After you applyembed:set-params, the iframe will emit anembed:paramsreflecting the canonical (normalised) query string. The reference handler above mirrors it withhistory.replaceState, which does not re-emit — so there is no feedback loop.searchis the source of truth. Both directions speak the URL query string, so the samef_/filter_param formats documented in URL Filter Parameters apply.- Auth tokens stay in the iframe
src. Keepjwt/dbAuthTokenin the iframe URL you construct; they don’t need to be (and shouldn’t be) round-tripped throughpostMessage.