> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hizz.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Buy Widget

> Embed the Hizz buy/sell box on any website with a single script tag, a container, a custom element, or a raw iframe.

export const HizzBuyLiveDemo = () => {
  const containerRef = useRef(null);
  const [error, setError] = useState("");
  useEffect(() => {
    let cancelled = false;
    const loaderSrc = "https://www.hizz.io/widget/hizz-buy.js";
    const loadWidget = () => {
      if (window.HizzBuyWidget) {
        return Promise.resolve(window.HizzBuyWidget);
      }
      if (window.__hizzBuyWidgetLoaderPromise) {
        return window.__hizzBuyWidgetLoaderPromise;
      }
      window.__hizzBuyWidgetLoaderPromise = new Promise((resolve, reject) => {
        const existingScript = document.querySelector(`script[src="${loaderSrc}"]`);
        if (existingScript) {
          existingScript.addEventListener("load", () => resolve(window.HizzBuyWidget), {
            once: true
          });
          existingScript.addEventListener("error", reject, {
            once: true
          });
          return;
        }
        const script = document.createElement("script");
        script.src = loaderSrc;
        script.async = true;
        script.onload = () => resolve(window.HizzBuyWidget);
        script.onerror = reject;
        document.head.appendChild(script);
      });
      return window.__hizzBuyWidgetLoaderPromise;
    };
    loadWidget().then(widget => {
      if (cancelled || !widget || !containerRef.current) return;
      widget.mount(containerRef.current, {
        asset: "279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f534e454b",
        theme: "dark",
        height: 700,
        title: "Hizz buy widget live demo"
      });
    }).catch(() => {
      if (!cancelled) setError("Unable to load the Hizz widget demo.");
    });
    return () => {
      cancelled = true;
    };
  }, []);
  return <div ref={containerRef} data-hizz-buy-live-demo style={{
    width: "100%",
    maxWidth: "420px",
    minHeight: "700px"
  }}>
      {error ? <div style={{
    minHeight: "360px",
    border: "1px solid rgba(148, 163, 184, 0.35)",
    borderRadius: "18px",
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    padding: "24px",
    textAlign: "center"
  }}>
          {error}
        </div> : null}
    </div>;
};

The Hizz Buy Widget drops the buy/sell box onto any site. It renders in an
isolated iframe served from `https://www.hizz.io/embed/buy`, so partner pages never
load the full Hizz app or its styles — they just get the trade box.

* **Loader script:** `https://www.hizz.io/widget/hizz-buy.js`
* **Frame URL:** `https://www.hizz.io/embed/buy?asset=<policyId|assetId>`
* **Version:** `window.HizzBuyWidget.version` (`1.1.2`) · no API key required

<Note>
  The loader auto-detects its own origin from the `<script src>`, so the iframe
  always points back to wherever the script was loaded from. Use
  `https://www.hizz.io` unless you self-host.
</Note>

## Live demo

The real widget, embedded cross-origin. This example uses SNEK; swap in any
Cardano `asset`.

<Note>
  This preview loads `https://www.hizz.io/widget/hizz-buy.js` and mounts with
  `window.HizzBuyWidget.mount(...)`, the same path as a partner site using the
  loader. Wallets that only inject into the top-level page, including VESPR,
  can be bridged into the frame when `window.cardano.vespr` exists on this page.
</Note>

<Frame caption="Live — SNEK / ADA, dark theme">
  <HizzBuyLiveDemo />
</Frame>

## Quick start

The fastest integration — drop one tag where the widget should appear. When the
script itself carries `data-asset`, the loader inserts a host element right
after it and mounts. Nothing else required.

```html theme={null}
<script
  src="https://www.hizz.io/widget/hizz-buy.js"
  data-asset="279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f534e454b"
  data-theme="dark"
  async
></script>
```

## Integration methods

### 1. Container element (recommended)

Full control over placement. The loader scans for `[data-hizz-buy-widget]` on
load and mounts each match.

```html theme={null}
<div
  data-hizz-buy-widget
  data-asset="279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f534e454b"
  data-theme="light"
></div>

<script src="https://www.hizz.io/widget/hizz-buy.js" async></script>
```

### 2. Custom element

```html theme={null}
<hizz-buy-widget
  asset="279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f534e454b"
  theme="snek"
></hizz-buy-widget>

<script src="https://www.hizz.io/widget/hizz-buy.js" async></script>
```

### 3. Programmatic mount

For containers that appear after load (modals, SPA routes, infinite scroll).
`mount(target, options)` takes a CSS selector or an element, returns the iframe,
and is idempotent per element.

```html theme={null}
<div id="hizz-buy"></div>
<script src="https://www.hizz.io/widget/hizz-buy.js" defer></script>
<script defer>
  // `defer` guarantees the loader ran before this call.
  window.HizzBuyWidget.mount("#hizz-buy", {
    asset: "279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f534e454b",
    theme: "dark",
    height: 640,
  });
</script>
```

<Warning>
  `window.HizzBuyWidget` is created synchronously when the loader runs. If you
  load it with `async`, its order relative to your inline call is not
  guaranteed — use `defer` (as above) or attach your `mount()` call to the
  script's `onload`.
</Warning>

### 4. Raw iframe (fallback only)

For strict CSP or static-only pages. This can render the trade box, but it
should **not** be the primary integration when wallet connect matters. You lose
automatic height resizing — pick a fixed height that fits — **and the wallet
bridge**: wallets that only inject into the top-level page (e.g. VESPR) will not
be connectable inside the frame.

<Warning>
  If you need VESPR or mobile in-app browser support, do not ship a standalone
  raw iframe. Use methods 1-3, or add the loader script below so it can adopt the
  iframe and bridge top-level wallets into the widget.
</Warning>

<Tip>
  Already shipped a raw iframe? Just add the loader script tag anywhere on the
  same page — it **adopts** existing `/embed/buy` iframes automatically,
  enabling auto-resize and the wallet bridge with no markup changes:

  ```html theme={null}
  <script src="https://www.hizz.io/widget/hizz-buy.js" async></script>
  ```
</Tip>

```html theme={null}
<iframe
  src="https://www.hizz.io/embed/buy?asset=279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f534e454b&theme=dark"
  title="Hizz buy widget"
  loading="lazy"
  allow="clipboard-write; web-share"
  referrerpolicy="strict-origin-when-cross-origin"
  style="width:100%;max-width:420px;height:620px;border:0;border-radius:18px;background:transparent;"
></iframe>
```

## Options

Pass options as kebab-case `data-*` attributes on the host element/script, as
attributes on the custom element, or as camelCase keys in `mount(target, options)`.

| Option    | Aliases                          | Default           | Notes                                                                                                                                                |
| --------- | -------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `asset`   | `token`, `token-id`, `policy-id` | — (**required**)  | Cardano **policy ID** (56 hex chars) or full **asset ID** (policy + hex-encoded name). A bare policy ID resolves to its primary asset automatically. |
| `theme`   | —                                | `dark`            | `dark` · `light` · `snek` · `transparent`.                                                                                                           |
| `partner` | —                                | —                 | Attribution tag, surfaced on the frame as `data-partner`.                                                                                            |
| `ref`     | —                                | —                 | Referral code (`ref` query param).                                                                                                                   |
| `width`   | —                                | `100%`            | CSS width of the iframe. Loader only.                                                                                                                |
| `height`  | —                                | `620`             | Initial height (px) before auto-resize. Loader only.                                                                                                 |
| `radius`  | —                                | `18px`            | iframe `border-radius`. Loader only.                                                                                                                 |
| `title`   | —                                | `Hizz buy widget` | iframe `title` (accessibility). Loader only.                                                                                                         |

### Themes

* **`dark`** — default Hizz dark surface with a soft brand glow.
* **`light`** — light surface.
* **`snek`** — Snek "spotlight" mint-on-charcoal theme (good for snek.fun tokens).
* **`transparent`** — no page background, border, or padding. Use this to sit the
  box flush inside your own card or section.

## Auto-resize

The framed page measures its content and posts its height to the parent:

```js theme={null}
{ source: "hizz", type: "hizz:buy-widget:resize", height: <px> }
```

The loader listens for this and adjusts the matching iframe (floor 360px), so
the box grows and shrinks as users switch between buy / sell / recover. If you
embed a raw iframe (method 4) you can subscribe to the same message:

```js theme={null}
window.addEventListener("message", (event) => {
  if (event.origin !== "https://hizz.io") return;
  const data = event.data || {};
  if (data.source === "hizz" && data.type === "hizz:buy-widget:resize") {
    iframe.style.height = Math.max(360, Number(data.height)) + "px";
  }
});
```

## Trading & sign-in inside the embed

The embedded box uses the same trade engine as hizz.io, but it runs in a
**cross-origin iframe** on your page, which limits how users can authenticate.

**CIP-30 wallets** are the only sign-in path inside an embed (social login is
hidden there). Two ways a wallet becomes available in the frame:

1. **Direct injection** — most extensions (Eternl, Lace, ...) inject
   `window.cardano` into every frame, so the widget sees them natively.
2. **Wallet bridge (loader v1.1.0+)** — some wallets, VESPR in particular,
   only inject into the **top-level page**. The loader script running on your
   page detects them and proxies the CIP-30 calls into the frame over
   `postMessage`. This is automatic — no partner code, no config. Approval and
   signing prompts are still rendered by the wallet itself.
   Loader `1.1.1+` also keeps watching for widgets/iframes inserted after page
   load and re-checks the parent page's wallets while the connect dialog is
   open, which helps mobile in-app browsers whose providers inject late.

<Warning>
  **Hizz managed wallet & social login** (email, Google, Telegram) rely on
  first-party hizz.io cookies and OAuth redirects, both blocked in cross-origin
  iframes and under third-party-cookie restrictions in Safari, Brave, and
  Chrome. Full account login is **not available** inside a cross-origin
  embed — the widget hides those options and offers wallet connect only. Link
  out to the token page on hizz.io for the full account experience.
</Warning>

## Requirements

* **HTTPS only** — clipboard, Web Share, and secure cookies need a secure
  context on both pages.
* **One widget per container.** Mounting is idempotent per element.
* The `/embed/*` page sets no `X-Frame-Options`, so it embeds from any origin.
* The loader script is edge-cached for 5 minutes; frame content is always fresh.

## Troubleshooting

| Symptom                                                    | Likely cause                                                                                                                                                                                                                                                                                                |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "Widget unavailable — Missing or invalid Cardano asset id" | `asset` is empty or not valid hex ≥ 56 chars. Pass a policy ID or asset ID.                                                                                                                                                                                                                                 |
| "Token not found"                                          | The policy ID has no resolvable asset on the supported DEXes.                                                                                                                                                                                                                                               |
| Blank box / nothing mounts                                 | Loader ran before the container existed — use programmatic `mount()` or move the `<script>` after the container.                                                                                                                                                                                            |
| Height never adjusts                                       | Raw iframe without subscribing to the resize message (see [Auto-resize](#auto-resize)).                                                                                                                                                                                                                     |
| Stuck on "connect wallet"                                  | Cross-origin embed; extension wallet not injecting, or account login attempted (unsupported in-frame).                                                                                                                                                                                                      |
| VESPR missing from the wallet list                         | The page is a standalone raw iframe (no loader → no wallet bridge), the top-level page does not expose `window.cardano.vespr`, or the loader is cached older than `1.1.2`. Fix by adding `https://www.hizz.io/widget/hizz-buy.js` or switching to methods 1-3; the script cache refreshes within 5 minutes. |
