Non-custodial · 19 chains · ~4,900 assets

Embed crypto swaps anywhere.
Fully yours to theme.

MizuSwap is a drop-in, fully-themeable swap widget. Quote, deposit, and track — all powered by a public affiliate code, never a secret key in the browser. Style every pixel with CSS custom properties.

npm i mizuswap-component
MizuSwap
You send
You get

// why mizuswap

Built for the people who own the front end.

~4,900
tradeable assets
19
supported chains
0
secret keys in browser
theme combinations

Non-custodial

Funds flow address-to-address. The widget never holds keys or custody — it orchestrates quotes and orders only.

Zero infrastructure

No backend, no proxy, no server code. Paste the widget, add your affiliate code and API key, and it runs — we even host the end-user IP lookup it needs.

Fully themeable

Every color, radius, font, and width is a --mizu-* CSS custom property. Four presets, or override any token.

Drop-in anywhere

A React component (mizuswap-component) and a framework-free <mizu-swap> web component (mizuswap-js). Same config shape.

// the flow

Three steps. Quote, deposit, track.

01

Quote

Pick a deposit asset + amount and a settle asset. MizuSwap fetches a live quote with rate, receive amount, and an expiry countdown.

02

Deposit

Enter your destination (and optional refund) address. The widget creates an order and shows a deposit address with QR, exact amount, and memo.

03

Track

The widget polls order status every ~8s through a clean stepper — waiting → processing → completed — surfacing tx hashes as they appear.

// live playground

Theme the real widget. Copy the embed code.

This is the actual MizuSwap widget running in mock mode — get a quote, create an order, watch it track. Tune the controls and the generated React and script snippets update in real time.

Theme controls

Every change drives the real widget & both embed snippets.

Colors
You send
You get
Embed code
App.tsx
import { MizuSwap } from 'mizuswap-component';

export default function SwapPage() {
  return (
    <MizuSwap
      config={{
        "theme": {
          "preset": "midnight",
          "radius": "16px",
          "fontFamily": "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif",
          "fontFamilyMono": "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"
        },
        "defaultDepositAsset": {
          "blockchainTicker": "BTC",
          "contractId": "BTC"
        },
        "defaultSettleAsset": {
          "blockchainTicker": "ETH",
          "contractId": "ETH"
        },
        "lockDepositAsset": false,
        "lockSettleAsset": false,
        "layout": "full",
        "rateType": "both",
        "branding": "none"
      }}
    />
  );
}

// install

Two ways to drop it in.

Same config shape across both packages, and no backend required. Supply affiliateCode and apiKey — both are required, the API returns 401 without them — and the end-user IP the API also needs is resolved for you from our own endpoint.

React

mizuswap-component
terminal
npm i mizuswap-component
App.tsx
import { MizuSwap } from 'mizuswap-component';

export default function App() {
  return (
    <MizuSwap
      config={{
        // Both are required — omit either and the API returns 401
        // (no assets load, no quotes are recorded).
        affiliateCode: 'your-affiliate-code',
        apiKey: 'your-api-key',
        // That's it — no backend, no proxy. The API also needs the end-user
        // IP; the widget gets it from https://mizuswap.com/api/ip for you.
        theme: { preset: 'midnight' },
        defaultDepositAsset: { blockchainTicker: 'BTC', contractId: 'BTC' },
        defaultSettleAsset: { blockchainTicker: 'ETH', contractId: 'ETH' },
        // Avoid logging the full order (contains addresses); use the id.
        onComplete: (order) => console.log('swap complete', order.orderId),
      }}
    />
  );
}

Vanilla JS

mizuswap-js
terminal
npm i mizuswap-js   # or use the hosted bundle below
index.html
<script src="https://mizuswap.com/mizuswap.min.js"></script>

<!-- affiliate-code AND api-key are both required (missing either → 401). -->
<mizu-swap id="swap" affiliate-code="your-affiliate-code" api-key="your-api-key"></mizu-swap>

<script>
  document.getElementById('swap').config = {
    // .config wins over the attributes above.
    affiliateCode: 'your-affiliate-code',
    apiKey: 'your-api-key',
    // End-user IP is resolved automatically from https://mizuswap.com/api/ip —
    // no backend needed on your side.
    theme: { preset: 'midnight' },
    defaultDepositAsset: { blockchainTicker: 'BTC', contractId: 'BTC' },
    defaultSettleAsset: { blockchainTicker: 'ETH', contractId: 'ETH' },
  };
</script>