Skip to content

Reference

Wire messages

Every message in both directions. You need this page only if you are bridging the protocol yourself; the loader speaks it for you.

The envelope

Every message, both directions, carries a namespace and a version. Anything without them is ignored, so your handler can share a page with any other postMessage traffic.

Every message
{ "ns": "vp-embed", "v": 1, "type": "…", … }

The version is 1. It exists because a snippet pasted today outlives a server we redeploy a hundred times, a newer frame can recognise an older host and behave rather than going silent. If it ever changes, the old value keeps working.

Frame → your page

typeFieldsMeaning
readyheightThe chart is mounted and will accept commands. Sent once.
resizeheightThe chart's natural height changed. Apply it, or keep a fixed height.
errorreasonThe chart could not start, a refused symbol, or a missing datafeed.
datafeedCallid, method, argsThe chart is asking your feed for something. Answer with datafeedResult or datafeedError, quoting the same id.
commandResultid, valueA command you sent succeeded. value is whatever that method returns, often a handle.
commandErrorid, reasonA command you sent was refused, and why. An unknown property is named here rather than dropped.
eventname, payloadSomething happened on the chart you asked to hear about, see Events.

Your page → frame

typeFieldsMeaning
datafeedResultid, resultThe answer to one datafeedCall. id must match the call.
datafeedErrorid, reasonThat call cannot be answered. reason reaches the console, not the reader.
datafeedTickid, barA realtime bar. id is the subscriberUID from subscribeBars, NOT a call id.
datafeedTradeid, tradeOne executed print, { price, size, side, timestamp }, for a footprint chart. id is the subscriberUID from subscribeTrades, the same rule as a tick.
setSymbolsymbolChange the instrument. The host already chose one in the URL, so this decides nothing new.
setThemethemelight or dark, for a page with its own toggle.
commandid, method, argsDrive the chart. One type for the whole control API; the methods are on Methods you call.
A datafeedTick’s id is a subscription, not a call. Every other message pairs a reply to the id of the call that asked for it. Ticks are unsolicited, so they are addressed to the subscriberUID you were handed in subscribeBars. Send a call id there and the chart has nothing listening, the bar is dropped, silently.

Pin the origin and the source

Check both. event.origin proves the message came from our document; event.source proves it came from THIS frame. Origin alone is not enough, a page embedding two of our charts would let either answer for the other, and the bug only appears on the page that has two.

The guard, in full
if (ev.origin !== EMBED_ORIGIN) return;
if (ev.source !== frame.contentWindow) return;
if (!ev.data || ev.data.ns !== 'vp-embed' || ev.data.v !== 1) return;

The frame cannot check your origin, because anybody may embed us, so it validates shape instead and rejects unknown fields. It does check the source: a message is accepted only when event.source is the window that embeds the frame. Send from the page that holds the iframe; a message posted from any other frame or a popup is ignored, so another frame on your page cannot drive your chart. That asymmetry is deliberate and is explained on the security model page.

A complete host

The whole bridge, with a working datafeed behind it, is on Without our script copy-pasteable, and run against a real chart by our browser suite on every change.