Skip to main content
For static sites, CMS pages, Webflow, newsletters-turned-landing-pages — anywhere you can drop HTML but not run a bundler. The IIFE bundle exposes window.Cesto and auto-binds every [data-cesto-invest] element on your page.
The script binds on DOMContentLoaded (or immediately, if the DOM is already parsed), so defer is safe. Elements are bound once — the loader marks them with data-cesto-bound="true" — so a second bind pass never double-fires a button.
The bundle is also served from unpkg: https://unpkg.com/@cesto/web-sdk/dist/cesto-invest.iife.js. Pin a version in production (@cesto/web-sdk@0.1.0) so a future release can’t change the flow under you.

Attributes

¹ Required per element unless you supply a fallback key via bindInvestButtons({ apiKey }). The element’s data-cesto-pk wins when both are present. A themed button, in full:
The theme attributes are serialized onto the invest URL as query params, so they apply in popup mode too — it is the same page. See Theming for what each token does and how values are validated.
A missing slug or key does not throw: the loader logs [Cesto] data-cesto-invest element is missing a basket slug or a publishable key and the click does nothing. Check the console first when a button seems dead.

Binding manually

Call bindInvestButtons() yourself when elements arrive after page load (a CMS block that renders late, a modal, an infinite-scroll list), or to set fallbacks shared by every button:
It returns the number of elements newly bound, so calling it repeatedly is safe and cheap:
Callbacks passed to bindInvestButtons apply to every element it binds — there is no per-element callback attribute. If different buttons need different handlers, either bind them in separate calls scoped with root, or use the JavaScript API directly.

Progressive enhancement with anchors

data-cesto-invest works on any element, so an anchor pointing at the basket page is a good no-JavaScript fallback:
With the script loaded, the click opens the dialog and the navigation is suppressed. Without it, the link goes to the basket page as normal.
Once bound, the loader calls preventDefault() on every click — including one where opening the flow fails (a rejected data-cesto-base-url, for example). It logs [Cesto] could not open the invest flow rather than silently navigating to the href, so a misconfigured button is visible instead of quietly degrading.

When not to use this

bindInvestButtons is built for pages where elements are added but not churned: it never removes its click listeners and never prunes its loader cache. Both are bounded by the number of distinct key + origin pairs on the page — one, for a real integration — not by the number of buttons or clicks. A long-lived SPA that repeatedly mounts and unmounts invest buttons should use @cesto/react (useCestoInvest) or hold its own Cesto instance, so listeners follow the component lifecycle.

Next

Theming

Every token, and how a bad value fails safe.

Events

What you can hook into from bindInvestButtons.