For developers

Know exactly what you're integrating — before you install

Hotspot Studio ships as a Shopify theme app extension. This is its complete public surface: two storefront events, one global hook, cart integration modes, and the attribution contract. Everything on this page is real, shipping behavior — the same guide lives inside the app.

2
public storefront events
1
global hook — window.HotspotStudio()
~10 KB
core script, zero dependencies
0
theme code edits required
Storefront events

Two events cover the whole shopper journey

Both are plain CustomEvents dispatched on document — attach your listeners to document (they don't bubble from anywhere else). No library, no App Bridge, no jQuery.

EventFiresevent.detail
hotspot-studio:product Every time a product hotspot's popup opens (info and link hotspots don't fire it). productGid, variantGid (when a variant is pinned), handle, showPriceRange, fbt — plus product: a Promise of the prefetched /products/<handle>.js JSON (resolves null if the fetch failed).
hotspot-studio:added After every successful add to cart from any Hotspot Studio path — popup button, variant picker, Shop the Look, and the recommendations row — once the item is already in the cart server-side. Empty by design — read /cart.js for the fresh cart state; it's already consistent with the new line.

event.detail may carry additional private fields — only the ones listed above are stable.

Enrich the popup when it opens
document.addEventListener("hotspot-studio:product", function (e) {
  const { productGid, variantGid, handle } = e.detail;
  e.detail.product.then(function (product) {
    if (!product) return; // fetch failed — product JSON unavailable
    // product = /products/<handle>.js JSON — render reviews, badges, stock…
  });
});
Forward adds to GA4 / your data layer
document.addEventListener("hotspot-studio:added", function () {
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({ event: "hotspot_add_to_cart" });
});
Re-hydrate hook

window.HotspotStudio() for AJAX themes

On a normal page load everything boots itself — sections hydrate lazily as they scroll near the viewport. The hook exists for markup that arrives later: quick-view modals, soft navigation, "load more".

  • Idempotent — call it as often as you like; already-hydrated sections are skipped, only new [data-hs-root] elements are picked up.
  • Still lazy — newly found sections hydrate when they approach the viewport, exactly like on first load.
  • One rule when injecting markup — keep the block's inline <script type="application/json"> data tags intact; that's where the section's content lives.
  • One prerequisite — the hook exists once the page has rendered at least one Hotspot Studio block (its Liquid loads the core; <script> tags injected via innerHTML never execute, so an injected section can't bootstrap it alone).
Inject a section via the Section Rendering API, then hydrate it
fetch(location.pathname + "?section_id=" + sectionId)
  .then(function (r) { return r.text(); })
  .then(function (html) {
    container.innerHTML = html;   // inject the freshly-rendered section
    if (window.HotspotStudio) {
      window.HotspotStudio();     // hydrate any new [data-hs-root] inside it
    }
  });
Cart integration

Work with our cart handling — or replace it entirely

One store-wide setting controls what happens after every add (popup, Shop the Look, recommendations, variant picker):

  • Open the cart drawer (default) — drives the theme's own drawer automatically on Dawn-family and Horizon themes, with event and selector fallbacks for everything else.
  • Advanced: drawer open selector — a Settings field (no code) that tells the fallback exactly which element toggles your drawer.
  • Reload the page / Go to the cart page — the boring reliable options.
  • Do nothing — added silently, and the app's cart script isn't even loaded. Pair it with hotspot-studio:added to take over completely:
Drive your own drawer (Cart behavior: "Do nothing")
document.addEventListener("hotspot-studio:added", function () {
  fetch("/cart.js")
    .then(function (r) { return r.json(); })
    .then(function (cart) {
      // update your UI from `cart`, then open your own drawer
    });
});
Attribution contract

How revenue lands on the right image

Every add made through the app tags the cart line with properties that power revenue attribution and section-scoped automatic discounts:

  • _hs_section — on every line added through the app (the section's public id).
  • _hs_hotspot — additionally on popup and variant-picker adds (the hotspot id).
  • _hs_b — additionally on Shop-the-Look "add all" lines; the discount function uses it to apply the bundle deal instead of the per-product one.
  • If you re-create cart lines yourself (custom cart logic, upsell apps), preserve every property with the _hs_ prefix — attribution and the discount function depend on them.
Performance & accessibility

Built like you'd build it

Strict byte budgets

The core is capped at ~10 KB minified, zero dependencies. Companion scripts have their own hard caps and load deferred, only when enabled — per section for the variant picker, Shop the Look, recommendations and carousel; store-wide for cart handling (skipped entirely on "Do nothing").

💤

Lazy by default

Sections hydrate via IntersectionObserver as they approach the viewport; product JSON is prefetched at hydration and cached per handle, so popups open with live prices instantly.

Real dialog semantics

Popups are role="dialog" with labels, Escape and outside-click close, focus moves in on open and restores on close, modals trap Tab, and prefers-reduced-motion is respected.

The fine print

This page is the whole stable surface: the two events, the hook, the _hs_-prefixed cart-line properties, and [data-hs-root]. Everything else — internal class names, the JSON inside the data tags, coordination events between our own scripts — is private and may change in any release. If you need something that isn't here, tell us instead of scraping the DOM; useful hooks get added.

Building something on top of it?

Agencies and theme developers get straight answers from the person who wrote the code — usually the same day.

Talk to the developer