Skip to content

Embedding

Changelog

Every change to the embed since it shipped, newest first. Nothing here has ever been breaking: every parameter, method and event that worked on the day it landed works the same way today.

This page is **append-only**. Entries are written from the commits that shipped them and are not edited afterwards. Where a decision is reversed, the reversal is a new entry: see 2026-08-25 and 2026-08-24. There is no version number, because the loader is served from a single URL and updated in place, so there is no version to pin; compare the date against your own integration instead.

Scrolling back on our data asks for a screen of history at a time

A fully zoomed-out chart on Vertical data fills in older history in one request instead of ten; a host datafeed is asked exactly as before.

  • ChangedOlder pages on Vertical data are sized to the screen

    On the embed's own market data, scrolling back now asks for as many bars as the screen shows, between 500 and 5,000, and asks while the reader is still a screen away from the oldest bar loaded. At the default zoom the page is still 500 bars, and pages are still requested one at a time, in order. With datafeed=host nothing changes: getBars with firstDataRequest: false is still asked for 500 bars, 100 bars before the edge, because a feed that errors on a large countBack, or returns [] whenever a page holds fewer bars than asked, would stop scrolling back under larger pages. Library release 0.7.0 carries the same behaviour behind the screen_sized_history_pages option, off by default.

    getBars

The live chart gains its full option set

The library’s live chart adds interaction, annotations, custom elements and complete styling control.

  • AddedScrolling, zooming, order tickets and draggable levels

    Drag to scroll back through history and pinch or ctrl-scroll to zoom, with callbacks for paging older data and an app-owned viewport for syncing charts. A tap can drop a price reticle that reports its level, and reference lines can be dragged with snapping and bounds, so a working order can live on the chart. The crosshair gains placements, dimming, per-candle and per-series readouts, and marker matches. See The live chart.

  • AddedAnnotations, gaps and your own elements

    Reference lines come in four forms (a level, a moving line, a value band, a time band) with pill and price badges; markers gain glyphs, images and clustering; a threshold colours the line above and below a benchmark; sessions can be labelled and focused; declared data gaps break the line without inventing prices. Tooltips, markers, line tags and badges can be replaced by your own elements, which the chart positions as it moves. See Annotations.

  • ChangedLibrary release 0.6.0

    The live chart in live/ grows from about 14 KB to about 43 KB gzip to carry the new options. Every existing option keeps its name and behaviour. Nothing changes for the full chart.

The live chart, in the embed and in the library

A small animated price chart for cards, tickers and landing pages ships alongside the full chart.

  • AddedA live chart for places where a price should look alive

    A lightweight chart that draws a line, candlesticks or several series on one canvas, with the tip gliding toward each new value and the time axis scrolling continuously. It is meant for a dashboard card, a ticker or the hero of a landing page, beside the full chart rather than instead of it, and it fetches nothing: you pass the points, with times in unix seconds. It carries a small VerticalProp logo at the bottom-left of the plot.

    live

  • AddedThe library package carries it under live/

    Library release 0.5.0 adds live/ to the signed package: @warburgai/vp-charts/live for a bundler, @warburgai/vp-charts/live/react for React (React 18 or later, an optional peer used only by that entry) and @warburgai/vp-charts/live/global for a script tag, which defines window.VPLive. Every file is in release-manifest.json, so your existing verification covers it. The small VerticalProp logo is part of the licence, as the full chart’s mark is, and has no off switch. See The live chart.

Starred timeframes survive a reload, and the badge is smaller on phones

The timeframes a reader stars now travel with the chart state, and a touch device shows the brand logo alone.

  • AddedsaveState carries the starred timeframes

    The embed writes no storage, so a starred timeframe used to vanish on the next page load. saveState now returns them under favoriteIntervals and loadState restores them; a state saved earlier, without the key, leaves them alone. favoriteIntervalsChanged fires when the reader stars or unstars one, so a page can save at that moment. See Events.

    saveStateloadStatefavoriteIntervalsChanged

  • ChangedThe brand badge stays a logo on touch devices

    On a device that cannot hover the badge used to open permanently into its full wording, which on a phone covered a large share of the chart. It now stays the logo disc, which still links to VerticalProp; the wording opens on hover and keyboard focus as before.

Trading line geometry and protection-label styles

Pill spacing, outlines, corner radii, buttons and bracket labels are configurable.

  • AddedOrder and position controls gained detailed style properties

    Control horizontal and vertical padding, right-edge inset, border width, separate body, quantity and button radii, button width and icon stroke. Positions also expose P&L colors, protection-label fonts, padding, radius, outline and colors, and separate drag-out button colors. Nullable overrides reset to the shared or theme default. Every property works on embed creation and update and has matching setters and getters in the compiled library. See the styling guide.

  • FixedTrading controls resize with their fonts

    Quantity width is measured in its own font. Row height accommodates body, quantity and active drag-out handle fonts, so larger type keeps its full click target.

Left padding for trading line controls

Order and position pills can sit away from the left chart border.

  • AddedTrading lines gained bodyPaddingLeft

    Pass bodyPaddingLeft: 16 with bodyAlignment: 'left' on creation or update to inset the full control group by 16 pixels. TP/SL, breakeven and preview labels follow. Defaults to zero. The compiled library also exposes setBodyPaddingLeft() and getBodyPaddingLeft().

Redrawn drawing-tool icons, and brushes up front

The drawing toolbar reads as one set, the tools reached for most sit nearest the top, and the brush draws only the stroke.

  • FixedThe brush and highlighter no longer draw a line back to the start

    While a stroke was being drawn, its preview joined the pointer back to the point the drag began with a straight segment, the whole way through the gesture. The preview is now the stroke alone. What was published on release was always correct; only the in-progress drawing was wrong.

  • ChangedEvery drawing-tool icon is redrawn as one family

    Tools you place by clicking show their anchors as hollow rings with the lines stopping short of them, the way the chart draws its own handles. The arrow stickers, arrow marker, ball and signpost are tinted outlines instead of solid blocks that out-weighed their neighbours. The brush is a paintbrush, the highlighter a marker, and the icon picker has its own sticker glyph rather than sharing the smiley sticker’s. Nothing about what the tools draw has changed.

  • ChangedThe toolbar is ordered by how often a tool is reached for

    Brushes & shapes is now third on the rail and rests on the brush, so one click arms it; Text & notes, then Positions & forecasting and Measure follow, with Patterns and Icons & stickers last. Inside each menu the most-used tools come first. A group’s first tool is what its button activates, so this also changes what a plain click on some buttons picks. Saved layouts and starred favourites are unaffected.

  • ChangedThe favourites bar opens centred along the top of the chart

    It used to appear in the bottom-left corner, far from the toolbar it was starred from. It now opens at the top centre of the plot. A position a reader has already dragged it to is still remembered.

Footprint charts on your own order flow

The footprint chart type, and three datafeed doors for the per-level volume it draws.

  • AddedsetChartType and data-type accept footprint

    The fifth chart type draws volume per price level inside each bar. It draws only what your feed supplies and never a distribution invented from the candle, so on a feed with no order flow it shows bars with no cells. The parameters page keeps its four-panel showreel to the visual types for that reason.

    setChartTypetype

  • AddedgetFootprint, subscribeTrades and unsubscribeTrades on the datafeed

    getFootprint(symbol, resolution, period) answers { time, levels, levelStep?, footprintSource? } per bar for a window, asked once per history page while the footprint chart is showing; subscribeTrades is the subscribeBars twin for live prints, pushed as datafeedTrade messages and folded into the forming bar. Both are opened only while the footprint type is showing and closed when it is left. Every slice and print is validated by shape and refused by index, like a bar.

    getFootprintsubscribeTradesunsubscribeTradessubscribeBars

  • Addedlevels, levelStep and footprintSource on a bar

    A bar from getBars may carry its order flow directly. Absent and empty are different facts: no levels means you supplied none for that bar, levels: [] means nothing traded. Documented on the objects and datafeed reference pages, with the same rule stated on the loader’s type declarations.

    getBars

  • FixedThe attribution mark clears the footprint delta tape

    On a footprint chart the mark sat on the CVD and delta rows along the bottom of the plot. It now clears the tape the chart reserves there, and moves the moment the chart type changes rather than on the next resize.

Trading sessions on the symbol’s clock

A sessions parameter and a setSessions command replace the hardcoded US equity hours.

  • Addedsessions parameter and setSessions command

    data-sessions="us" tints the two US equity bands; label@HH:mm-HH:mm[@days], comma-separated, spells your own. chart.setSessions(bands) takes full band objects with a colour and an optional timezone, replaces the set, and clears it with []. The chart ships with no bands, because crypto trades around the clock.

    sessionssetSessions

  • FixedSession hours are read on the symbol’s clock

    Band hours were documented as the symbol’s own zone and evaluated in UTC, which put a New York pre-market tint in the middle of the New York night. They now follow the zone the symbol resolved with, or the band’s own timezone; a band with no zone on a UTC symbol draws exactly as before.

    setSessions

Drawing tools, arrows and colour controls

A pass over the drawing tools shipped to the library and the embed together.

  • ChangedArrows, fibs, notes and the colour picker

    Filled arrows are one tapered polygon and the four sticker arrows are sized by a two-anchor box with the rectangle’s eight handles; fib levels span their anchors and extend only on request; table notes, balloons and anchored text edit in place; the price note draws its pill at the dropped end; a rectangle can carry a 50% midline; the sine line drags by its body; the Forecast tool is folded into Projection; and every colour control offers the same picker. A saved layout from an earlier build loads unchanged.

Host datafeeds control their intervals and pair selector

Hide the pair selector independently, and use host resolutions such as three minutes.

  • AddedsymbolSearch hides only the built-in pair selector

    With the toolbar enabled, pass data-symbolSearch="false" to the loader or symbolSearch=0 in the iframe URL. The other toolbar controls and setSymbol remain available. Defaults to true.

    symbolSearchtoolbar

  • FixedHost intervals follow supported_resolutions

    For a host datafeed declaring onReady().supported_resolutions, data-interval="3" and setInterval("3") now use that list rather than the fixed first-party intervals. Unsupported commands reject before changing the chart; unsupported opening intervals report a data error. The first-party feed retains its existing intervals.

    intervalsetIntervalonReady

Chart settings close on an outside click

Dismiss the floating settings panel by clicking back on the chart.

  • FixedChart settings gained outside-click dismissal

    Clicking outside chart settings now closes the floating panel, keeping changes already applied. Its colour pickers and dropdown menus remain interactive. The close button and Escape continue to work. Standalone integrations with their own pair selector can hide the built-in symbol button using disabled_features: ["header_symbol_search"], as explained in the library guide.

The chart-type button follows the selected chart

The toolbar shows the current chart type instead of always showing candles.

  • FixedThe selected chart type updates the button icon

    Choosing a chart type now updates the toolbar button to the same icon shown in the menu. Its tooltip and accessible name also identify the selected type. Changes through setChartType and restored layouts follow the same path, and rapid selections cannot leave an older icon on the button.

    setChartType

Trading line controls can sit on the left

Keep order and position controls away from the latest candles on narrow charts.

  • AddedOrder and position lines gained bodyAlignment

    Pass bodyAlignment: 'left' when creating an order or position line, or through handle.set() afterward. Quantity, labels, P&L and available action buttons move together; position TP/SL, breakeven and drag-preview labels follow. Right remains the default. The standalone library accepts the same creation option and exposes setBodyAlignment() and getBodyAlignment(). Alignment is independent of line length and price-axis placement. See the styling guide.

    createOrderLinecreatePositionLine

Numbers read the way the reader writes them

Every number on the chart follows the reader’s own locale by default, and a publisher can pin one of four formats instead.

  • ChangedThe default number format is the reader’s locale

    Prices, the crosshair readout, the legend, volumes and study values were all written the American way, 1,234.56, for every reader everywhere. They now follow the locale of the browser the chart is drawn in: a German reader sees 1.234,56, a French one 1 234,56, with nothing configured. An embed that never mentions the format changes with its readers, which is the point; one that must not can pin a format with the parameter below. A reader with the toolbar on can also pick a format in the chart’s own settings (Scales › Numbers), and that choice outranks the page’s on their next visit.

    numberFormat

  • AddednumberFormat, and setNumberFormat

    data-numberFormat takes one of auto (the default: the reader's locale), standard (1,234.56), european (1.234,56), plain (1234,56) or spaced (1 234,56), and chart.setNumberFormat(name) is the same choice after mount, for a page with its own switch. The four presets are the chart's own, so european here and “European” in the settings dialog are one table rather than two.

    numberFormatsetNumberFormat

The last price can glide toward each tick

The last bar’s close, and the last-price line beside it, can ease toward each live print instead of snapping. Off by default, opt in per embed.

  • AddedpriceAnimation, opt-in

    Every tick jumps the last candle's close and the last-price line straight to the new print, which on a fast-moving symbol reads as a flicker rather than a price moving. priceAnimation=true eases the DRAWN value from the previous print toward the new one over ~160ms (ease-out: fast start, gentle finish), on the frame, never touching what is stored — indicators, trade markers and every other reader of the bar see the true print the instant it lands. Off by default, matching the library and every other chart it runs on.

    priceAnimation

Dragging out a stop shows you what it costs

The span between the entry and the level under the pointer is washed in that leg’s colour while the drag is in flight: red down to a stop, green up to a target.

  • ChangedA drag-out shades the region it is proposing

    A level on its own says WHERE a stop goes; what a reader is actually deciding is HOW MUCH of the position they are willing to lose, and that is the span between the level and the entry rather than the level itself. So the gesture now paints the span, in that leg’s own colour, fading out to the left so it does not flatten the candles it crosses. It is drawn at the same strength as the depth wash in the price gutter, so a chart showing both reads as one thing. Nothing changes about what the gesture DOES: the wash belongs to the drag and is gone the instant the release books the leg, because a resting stop is a level and not a region. It only ever appears on a handle you turned on, so a chart that never offered canAddTakeProfit is unchanged.

    createPositionLineupdateLine

  • AddedprotectFillOpacity

    How loud that wash is, 0 to 1, defaulting to 0.16. 0 turns it off and leaves the rest of the gesture (the dashed level, its price, the wrong-way arrow) exactly as it was. Deliberately a strength and not a fill COLOUR: takeProfitColor and stopLossColor already decide what colour each leg is, and they already paint its level, its handle and its in-flight line, so a separate fill colour would be a second answer to a question that has one. Its own kind of value, too: unlike a percentage, zero is a real answer here, and is the one most likely to be sent after somebody tries the shading and changes their mind.

    createPositionLineupdateLine

A fill can be a bubble instead of an arrow

Execution markers take a shape. The label moves inside a roundel sitting against the price, which is the form a trade history is readable in.

  • AddedmarkerStyle on createExecutionShape

    badge draws the marker as a roundel carrying the label INSIDE it, against the fill price, instead of a triangle with a caption beside it. That is the difference between a history that reads as a column of B / S bubbles and one that reads as a field of triangles each trailing a label placed wherever it did not collide. Its near EDGE sits at the price, so the candle at that level is marked rather than covered, and it mirrors to the other side of the price when there is no room. arrow remains the default and is unchanged to the pixel, so a chart already on your site moves only if you ask it to.

    createExecutionShapeupdateLine

  • ChangedThree properties mean something slightly different in badge mode

    They are the same properties, read against a different ground. text is drawn inside the roundel rather than beside the arrow, so it wants a glyph or two — a longer one grows the roundel into a pill rather than being clipped, and the words belong in tooltip. textColor is drawn ON arrowColor rather than on the chart, so the two have to contrast: set them from the same place, or the letter ends up the colour of the disc it is inside. And arrowHeight is the roundel’s radius, clamped to 7–14. The reference table says all three in the rows themselves.

    createExecutionShape

A line has a shape, and now that is yours too

Corner radius, fonts, leg names and the drag-out buttons’ labels. Everything that was a literal in the renderer is a property.

  • AddedborderRadius, on both kinds of line

    The corner of every box on a line: the label body, the quantity chip and each button. ONE number rather than one per box, because they sit in a single row at a single height and a body at 8 beside a button at 2 does not read as a design. 0 is square, 2 is what it has always been, and anything past half the row’s height clamps to a full pill, so 999 is a legal way to ask for one. It is a distinct kind from a line width for one reason: zero is a legal radius and is not a legal width, and it is the value most likely to be sent after somebody tries rounded and changes their mind.

    createOrderLinecreatePositionLineupdateLine

  • AddedEvery bracket leg has a name, a width and a dash

    takeProfitLabel / stopLossLabel / breakevenLabel set what a leg is CALLED on the pill at the end of its level, and an empty one draws no pill, which is how you turn a label off. Breakeven’s is empty by default, since it has always been an unlabelled dotted reference. protectLineWidth and protectLineStyle are the legs’ own line, independent of the entry’s: the entry has carried both since the beginning and the legs were pinned at one solid pixel, so thickening the entry left a hairline stop beside it.

    createPositionLineupdateLine

  • AddedThe drag-out handles take a label, and grow to fit it

    addTakeProfitLabel / addStopLossLabel / protectFont. The handle measures its own label, so + TP is legible rather than clipped, and a two-letter one is unchanged to the pixel because the old fixed width is still the floor. Deliberately not the same property as the leg name above: they look like the same string and are not, one being the text on a button and the other a name printed beside a price, so writing + TP on the button would otherwise put + TP 83,000 on the level.

    createPositionLineupdateLine

  • ChangedThe Styling and Trading guides cover all of it

    The previous release added these properties to the reference tables and to the type declarations, and left the two written guides describing the world before them. Styling now has the rounded, branded position and the full bracket palette; Trading has the drag-out handles, what to do when one fires, and why side matters when you offer them.

The trading lines are yours to style, and to switch off

Every part of an order line, a position line and its bracket can now be coloured, lettered and withdrawn, including the drag-out take-profit and stop handles, which the embed could not offer at all.

  • AddedDrag-out take-profit and stop handles

    A position line can now grow the two small squares a reader pulls away from the pill to ask for a bracket leg at the price they release on, reported as positionAddTakeProfit and positionAddStopLoss with the RELEASED price rather than the entry. They are OFF until you set canAddTakeProfit / canAddStopLoss, because turning one on is a promise to answer that event with a real order, the same reason the Buy/Sell rows need setTrading. Set side whenever you offer them: a long takes profit above its entry and stops below it, and with the side unset the gesture constrains nothing, so a reader can draw a take-profit into a loss and find out from your venue.

    createPositionLineupdateLinepositionAddTakeProfitpositionAddStopLoss

  • AddedThe bracket legs take your colours

    The take-profit and stop levels were a fixed green and red: the two lines a reader actually watches were the only chrome on the chart you could not brand. takeProfitColor, stopLossColor and breakevenColor set them, and null puts the built-in colour back. A leg's colour also paints its drag-out handle and the level in flight, so it is one colour for the whole life of that leg.

    createPositionLineupdateLine

  • AddedEvery button, tooltip and font on a line

    Both lines gained the chrome that was on the adapter and not on the wire: each button's border, fill and glyph colour (close, reverse, cancel), each button's own tooltip, the label and quantity fonts, lineLength, and extendLeft on a position line as well as an order line. An execution marker gained font. A position line can also be made editable, which lets a reader drag it and reports positionMove. It is off by default, because a position line stands for a fill whose price is not theirs to move.

    createOrderLinecreatePositionLinecreateExecutionShapeupdateLinepositionMove

  • AddedIcons and a disabled state on your toolbar buttons

    A header button takes an icon: a NAME from a fixed list we draw ourselves, never markup, a data URI or a URL, since any of those would put your DOM or a fetch you can watch on our origin. It also takes disabled, for a control that does not apply right now: announced as disabled, skipped by the Tab key, and its presses are not reported, which is what you want instead of removing the button and making the header shuffle on every symbol change.

    createToolbarButtonupdateToolbarButton

  • AddedA click on a line is distinct from a drag

    orderModify and positionReverse complete the set: the first fires when a line's body is pressed without travelling, which is a request for whatever ticket you keep for it rather than a new level, and the second when the reverse control is used. reversible shows that control and is off by default.

    orderModifypositionReverse

  • FixedA toolbar button set `active` disappeared

    A stylesheet rule for an unrelated control had been inserted into the middle of the pressed-state selector list, which silently moved aria-pressed="true" onto display: none. Any button you marked as a pressed toggle vanished from the header the moment it was switched on. It is styled again, and a check now fails if a pressed-state selector ever shares a block with a rule that hides it.

    createToolbarButtonupdateToolbarButton

  • Fixed`closeable` and `reversible` did nothing

    Both were accepted, reported as applied, and dropped. The property named a setter the chart did not have, so a position line you asked to draw without a close button drew one anyway. Both work now, and every property is checked against the real chart object, so one cannot be accepted and silently ignored again.

    createPositionLineupdateLine

The community run loop ships with the library

A self-hosting licensee had the engine that runs an indicator somebody else wrote, and not the part that decides whether it may.

  • AddedA community entry in the package

    The chart could always register and sandbox a script. The loop around it could not: it lives in a module our own two products share, and it was in neither the package nor the documentation. That is a safety gap rather than a missing convenience, because the loop is where a withdrawal lands. It asks the server on every load so a takedown reaches a chart that is already open, hashes the bytes on the client so the answer means something, takes the study off the chart the moment a refusal arrives, and separates a refusal from an outage under a bounded grace. Each of those is one line to leave out of a reimplementation and none of them fails visibly. See the community section of Installing the library.

  • AddedInstallable, reproducible, watermarked packages

    A release now also produces a tarball per licensee with an integrity hash, so the library can be installed from a private registry rather than cloned. Each build carries a fingerprint compiled into its bundles and into the signed manifest, which is the only recourse that survives the fact that nothing recalls code once it has been handed over: revocation governs the next version, the fingerprint governs the last one. The archive is stamped at the epoch and gzipped without a timestamp, so identical bytes always produce an identical hash and "is this the artifact that was signed" stays a question you can answer by comparison.

A third way to get the chart

The chart is also available as a library you host yourself, with your own market data wired in. It is documented for the first time.

  • AddedThe self-hosted library, documented and requestable

    Two shapes were described here: our script on your page, and a frame with a bridge you write. Both are the same product, a chart we host that you point at. There is a third, and it has been built and signed by every release for as long as there have been releases without anything saying so: the chart as files you serve from your own origin, with the whole interface in your page instead of across a boundary. It is meant for a trading platform or an exchange, it is commercial, and it comes with the hosting, the market data and the upgrades as your responsibility. See Host the chart yourself.

  • AddedOne package, and the wrapper for each framework

    There is no separate build for React or for Vue. The chart mounts into a plain element, so what changes between stacks is where you create it and when you tear it down; Installing it prints those twenty lines for vanilla JavaScript, React and Vue, and says which part of each is the one that leaks a chart per navigation when it is left out. The package ships as a native module, as a single file that defines a global, and as TypeScript declarations for both.

  • ChangedThe embed overview says when not to use an embed

    The comparison is deliberately on the embed page as well, and it is written to send most readers back: a chart in an article, on a landing page or in a dashboard is an embed, and it is not a lesser one. The two rows that decide it are who holds the files and who chooses when a chart changes.

Documented examples run on the page

Every runnable example in these guides now starts by itself, with the code beside it, instead of behind a button that opened another tab.

  • ChangedExamples run in place, without a click

    A playground was a button that opened an editor somewhere else. For a reader that is a link, and a link is what you are handed when a page has run out of room: you lose your place, and the sentence explaining the example ends up one tab away from it. Each example is now a live editor in the page, code on the left and the chart on the right, started when it scrolls into view. It is deliberately not started at page load: an editor and a chart engine fetched for somebody who may never scroll that far is a cost they did not ask for.

  • ChangedThe printed source is the file that runs

    One document is composed and handed to the block, to the live editor, and to the new-tab button, so what you read is what runs and what you copy. It previously omitted the stylesheet, which the editor received separately, so a copied example rendered unstyled for no visible reason. The source now sits below the running copy rather than above it, because a two-thousand-pixel code block between a reader and a working example is a wall in front of the thing it describes.

  • ChangedA new tab still works without JavaScript

    The second door is a plain form post, so the button works with scripting off. Together with the printed source it is the whole of what a reader in that state can reach, which is why it was kept rather than replaced with a scripted control.

The price scale, for drawing your own layers

Where a price lands in pixels, published to the host page rather than answered one question at a time.

  • AddedA synchronous price-to-pixel mapping on the chart object

    A page that draws its own layer over the chart, a band, a rail of labels, a set of levels in its own canvas, had no way to know where a price was. chart.priceToY(price), yToPrice, priceToCoordinate, coordinateToPrice and getPriceScale() answer that, and they are the only synchronous methods on the chart object. That is the point rather than an optimisation: an overlay is repainted inside a requestAnimationFrame callback while the reader pans, and a promise cannot be spent there, so a per-point round trip would draw the layer a frame or more behind the candles it is pinned to. The frame publishes the whole mapping when it moves and the loader keeps the last one. See Methods.

    priceScaleChanged

  • AddedpriceScaleChanged, and a one-off read

    The event fires when the visible range moves, when the iframe is resized, and when the reader switches to a logarithmic or inverted scale, at most once per animation frame and never repeating a mapping you already hold. It also fires once as soon as the chart has laid out, so a page can subscribe at mount and draw immediately instead of waiting for its reader to move something. chart.getVisiblePriceRange() is the promise-returning read for a page that wants the mapping once rather than following it; it also refreshes what the synchronous methods return.

    getVisiblePriceRange

  • AddedThe mapping carries the plot band, the scale type and the flip

    The visible bounds alone cannot place a level. The plot band is not the iframe, the price gutter, the time axis and any indicator pane sit outside it, so top, height, left and width are sent in the frame’s own coordinates. scale and inverted are sent because the reader can switch to a logarithmic scale or flip the axis from the chart’s own settings without the host page hearing about it, and a layer mapped linearly onto a logarithmic scale is wrong in a way that looks plausible near the middle of the plot. See Objects.

Marker labels stay inside the plot

A fourth entry for the same day, because the fix came out of photographing the previous one.

  • FixedA marker label with no room on its own side is mirrored

    A sell marker's arrow sits above the price and its label above that, so a fill at the high of the visible range drew its label off the top of the chart. The label is now placed on the other side of the price when there is no room, and the collision offset follows it. Arrow positions are unchanged.

    createExecutionShape

  • ChangedKnown: a label near the top of the plot can sit under the legend

    Reported rather than fixed. The legend is drawn over the canvas and its height is not published to the drawing layers, so nothing on the canvas can avoid it, and the same applies to any indicator or drawing in that band. Correcting it needs a legend-aware inset rather than a clamp.

    createExecutionShape

Drawing introspection, method aliases, marker fixes

Drawings can be listed as well as created, two methods gained a second accepted spelling, and three defects in execution markers are fixed.

  • AddedgetShapes lists every drawing on the chart

    Returns { id, name } per drawing, where name is the tool. The id is the one removeEntity takes, so a single drawing can now be removed; previously only removeAllShapes was reachable, because no method handed back an id. Ids and tool names only. Use getDrawings when you want geometry.

    getShapes

  • AddedgetAllShapes and getAllStudies are accepted as aliases

    They resolve to getShapes and getStudies respectively, so code written against the conventional spelling runs unchanged. The alias is resolved before validation, so each pair has one validator and one implementation and the two spellings cannot answer differently. See Aliases.

    getShapesgetStudies

  • ChangedReading a reader’s drawings is now permitted, and documented as such

    getAllShapes was previously listed as deliberately absent, on the grounds that reading a stranger’s drawings reveals what they drew. That position was inconsistent with getDrawings, which was already shipping and returns every anchor, price, time and any text the reader typed, while the method being refused returned only tool names. The policy is now stated once: **artefacts a reader deliberately created are readable; involuntary behaviour is not.** crossHairMoved remains unavailable, as does anything touching identity, storage or navigation. See Deliberately absent.

    getDrawings

  • FixedcreateExecutionShape accepted seconds where the engine expected milliseconds

    Markers placed with the documented second-precision timestamp were silently dropped: no error, no warning, no arrow. Both units are now accepted, so existing code that compensated is unaffected.

    createExecutionShape

  • FixedExecution labels no longer overlap

    Two markers a few bars apart drew their labels on top of one another. A clashing label is now offset away from its arrow, so it never crosses the price it describes. Arrow positions are unchanged.

    createExecutionShape

  • FixedThe tooltip property on an execution marker is rendered

    It was accepted and stored but never drawn. The hover region spans the arrow and its label.

    createExecutionShape

Persistence, timezone, view locks, study introspection, data export

Ten commands, four optional datafeed methods and one URL parameter, covering the capabilities most often needed in the first week of an integration.

  • AddedSave and restore a reader’s chart

    saveState and loadState transfer the whole chart as plain data. getDrawings and setDrawings transfer only the annotations, for a page that owns the symbol and interval itself: a full state carries the symbol it was saved on, so restoring one would replace the instrument your page selected. See Remember the reader’s chart.

    saveStateloadStategetDrawingssetDrawings

  • AddedSet the time axis timezone, as a parameter and a method

    Available both ways because a page with a timezone picker changes it after mount, and a page without one needs it correct on first paint. IANA names only. A UTC offset such as +02:00 is refused, since it cannot express daylight saving.

    setTimezonetimezone

  • AddedLock scrolling and zooming

    Constrains the pointer without hiding any control, so the toolbar range buttons continue to work. Set both to pin a chart to one window.

    setScrollEnabledsetZoomEnabled

  • AddedList indicators on the chart, and indicators available to add

    getStudies returns the ids removeEntity needs, so a single indicator can be removed. getAvailableStudies reads the engine registry, so a picker built from it stays consistent with what createStudy accepts.

    getStudiesgetAvailableStudies

  • AddedExport the visible bars as CSV

    exportData narrows the series already loaded and issues no request, so on a host-supplied datafeed it never consumes your rate limit. Returns null when no bars are loaded, which is distinct from a file containing only a header row.

    exportData

  • AddedFour optional datafeed methods

    getServerTime supplies your clock to the forming-bar countdown. getMarks supplies per-bar badges. getTimescaleMarks supplies gutter roundels, and is **concatenated** with ours rather than replacing them, unlike getMarks: a bar mark states what happened on a bar, so two sources would contradict each other, while a timescale mark states that something happened at a moment, and two sources are compatible. searchSymbolsPaginated supplies a catalogue longer than one page. All four are optional. See Use your own data.

    getServerTimegetMarksgetTimescaleMarkssearchSymbolsPaginated

  • FixedTwo defects found in browser testing

    setScrollEnabled and setZoomEnabled were dispatched to the chart object rather than the widget, so both returned commandError. getAvailableStudies returned seven of sixty-eight indicators, because the remainder are in lazily loaded packs that had not been requested.

    setScrollEnabledsetZoomEnabledgetAvailableStudies

Per-bar marks

Round badges beneath bars, with a tooltip on hover. The renderer already existed; no method reached it from outside the frame.

  • AddedsetMarks and clearMarks, and getMarks on the datafeed

    Two entry points, for two integration shapes. setMarks and clearMarks push a set directly, which is what a page using our market data needs, since it has no datafeed to attach a callback to. getMarks is the datafeed method, for a page already supplying its own bars. When both are present, the pushed set takes precedence, being the later and more specific statement.

    setMarksclearMarksgetMarks

  • AddedTimestamps must match a bar exactly

    A mark is looked up by the bar it belongs to rather than positioned by pixel, so time must be a bar’s own opening time, in epoch seconds. A daily bar is anchored by its venue, which is not always midnight UTC. Millisecond values are refused with an explanatory error rather than converted, because a converted value that misses a bar draws nothing and reports nothing.

    setMarks

Ten colour roles, toolbar buttons, TypeScript declarations

The palette became addressable after mount as well as at it, a host gained one supported place for its own control inside the frame, and the loader gained type declarations.

  • AddedsetStyle, and ten colour roles instead of five

    The palette was previously five roles read once at construction. The crosshair, secondary text, hairlines, chrome and accent are now addressable. Engine tokens that no role reaches are listed with a reason and paired against the theme in both directions, so a new token becomes a decision rather than a colour that silently cannot be set. See Styling.

    setStylecolors

  • AddedA host-defined button in the chart toolbar

    Carries a label, a tooltip and a side, and reports presses as toolbarButtonClick. Requires data-toolbar: with the header disabled the engine still returns an element, so without the check a host would receive a working handle for a control no reader can see, and the call is refused instead.

    createToolbarButtonupdateToolbarButtonremoveToolbarButtontoolbarButtonClick

  • Addedembed.d.ts, served beside the loader

    The loader is a script at a URL rather than a package, so nothing supplied types with it. Every method, event, property and colour role is now declared and paired against the runtime in both directions, so a declaration cannot describe a call the frame would refuse. See TypeScript types.

Chart colours are set by the host

`data-colors` accepts role and value pairs and repaints the plot.

  • ChangedA URL may now recolour the chart

    This reverses a documented position. The previous argument was that a URL able to recolour the plot could make one chart resemble another; in practice the URL is written by the embedder, who already selects the instrument, so it protected nothing while preventing the ordinary case of matching a chart to the surrounding page. The protection that does matter is unchanged: the attribution mark cannot be disabled.

    colors

  • AddedHexadecimal values only

    These values reach the canvas fill style, and a CSS colour may be a url(...), which would make the chart issue a request. A single strict form is checkable at a glance. An invalid colour in a URL is dropped and the chart still renders; an invalid colour passed to a method is refused by name, because a URL is written once and read by every visitor, while a method call has an error channel back to its author.

    colorssetStyle

The economic calendar became opt-in

Macro roundels were previously enabled unconditionally on our own datafeed and unavailable on a host-supplied one.

  • Changedcalendar is a parameter, disabled by default, honoured in both datafeed modes

    Disabled is the appropriate default for a chart published on another site: the roundels are our data, drawn on a page that may have supplied its own, and fetched on that site’s reader’s behalf. Requesting them by name makes them a choice. See Economic calendar.

    calendar

  • AddedA limits reference

    Every cap the embed enforces, on one page, read from the constants that enforce them. See Limits.

The message protocol became a public contract

The datafeed RPC was previously reachable only through our loader and was undocumented. It is now versioned and specified, so a host can implement it directly.

  • AddedEvery postMessage type, in both directions

    Some organisations cannot include a third-party script on a page that also renders customer data, since that script is arbitrary code execution on their origin, outside their review and revocable by us. The loader was never required: an iframe and roughly thirty lines of postMessage in your own repository is the whole integration. See Wire messages and Without our script.

  • ChangedPublishing the protocol constrained what we may change

    While the loader was the only entry point, both ends shipped together and a rename was a deployment. A host-authored bridge is on its own release cycle, so PROTOCOL_VERSION now governs compatibility, and the documented example is pinned to it.

  • AddedDisplay currency

    Draws a chart in another currency, converted at the rate in effect for each bar. The currency and the market its rate is read from are supplied together in one parameter, so a chart cannot be asked for a currency it has no rate source for. On a host-supplied datafeed you name the market, because a bare code refers to our symbols. See Display currency.

    currency

  • AddedOrder lines, position lines and the trading handshake

    Levels are drawn in the price scale rather than over it, so they move with the chart and can be dragged. setTrading is the handshake: order rows appear in the price scale menu only once your page has declared it can receive them.

    setTradingorderSubmitorderMoveorderCancelpositionClosepositionModify

  • FixedSix ways to spend another site’s consent

    An adversarial review, on the assumption that the embedding page is hostile. Two examples. The literal string null was treated as a site: an opaque origin serialises that way, so every sandboxed document shared one grant and the consent screen displayed “null” as the site being trusted. And a URL parser canonicalises rather than merely parsing, so 12345 was accepted and returned as the host 0.0.48.57; the bare-host path now round-trips and refuses anything the parser invented.

  • FixedThe plain-HTTP refusal now explains itself

    Reader sign-in is withheld on a plain-HTTP page, because a credential bound to an origin that any network intermediary can rewrite cannot mean what the consent screen states. Previously the control was simply absent, with nothing in the console or network tab. It now names the reason. See Troubleshooting.

The documented datafeed quickstart threw

Found on the first run of a demo that serves the embed from a genuine third-party page.

  • FixedThe loader tag in the datafeed snippet must not be async

    embed.js assigns window.vpEmbed when it executes, and there is no pre-load stub, so an inline script calling vpEmbed.datafeed(...) beside an async loader threw vpEmbed is not defined and registered nothing. The chart then remained on “Loading market data”, which resembles an unavailable venue rather than an incorrect snippet. Markup-only snippets retain async and are unaffected, since they call nothing and the loader scans for .vp-chart on arrival.

Initial release

A chart that can be published on any site: served from our origin, under our content security policy, with none of our code running in the host page.

  • AddedAn iframe rather than a script tag

    A script-tag embed would place our bundle in the host realm and would require every customer to permit worker-src blob: in their own policy for community indicators. The iframe keeps the origin, the policy, the storage and the untrusted-script sandbox on our side. See Embed a chart and the Quickstart.

    symbolintervalthemetypetoolbarlegendlocale

  • AddedHost-supplied market data, and enforcement of it

    We distribute a charting engine rather than market data. With datafeed=host the chart requests symbols and bars from your page and issues no market-data request of its own, verified across a genuine site boundary. A frame whose top-level site is not ours and which supplies no datafeed is refused, naming data-datafeed. The check fails closed on unknown ancestry. See Use your own data.

    datafeed

  • AddedThe host control API

    Drives a mounted chart from the page that framed it and reports reader actions back. One inbound message type rather than one per method, because that list is a security surface and is intended to be reviewable in a single reading; method names are an allowlist with a validator each. Line handles take an options object rather than a chained setter, so one update is one message and one repaint. An unrecognised property is refused by name rather than ignored. See Control the chart.

    setIntervalsetChartTypesetVisibleRangecreateOrderLinecreatePositionLinecreateExecutionShapeupdateLineremoveLinecreateShapecreateMultipointShaperemoveEntityremoveAllShapescreateStudyremoveAllStudiesgetSymbolgetIntervalgetChartTypegetVisibleRangesymbolChangedintervalChangedchartTypeChangeddataLoadedvisibleRangeChanged

  • AddedCommunity indicators, with optional reader sign-in

    Indicators run without an account, so most readers never encounter a sign-in path. A reader may optionally connect their VerticalProp account so that indicators they have installed also run. The frame never receives the session cookie, which a browser withholds from a third-party frame in any case; it receives a ten-minute single-scope token bound to the embedding site, minted by a consent screen and revocable from the reader’s profile. See Indicators and the Security model.

    indicators

  • AddedAn operational kill switch, and a snippet builder

    The switch is read at runtime, so it is a restart rather than a rebuild. Listing and revoking a grant remain available while it is off, since a reader must always be able to withdraw a permission. The builder emits only non-default values, so a generated snippet does not pin the current defaults into a host page permanently.

  • FixedThe attribution badge received no pointer events

    A transparent input layer covering the plot collects pan, zoom and crosshair gestures, and the badge was beneath it, so it never opened on hover and its link could not be clicked. It now sits above that layer and below every control.

  • FixedThe type parameter had no effect

    It parsed and validated, but nothing read it, so every embed rendered candles.

    type