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.
// why mizuswap
Built for the people who own the front end.
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.
Quote
Pick a deposit asset + amount and a settle asset. MizuSwap fetches a live quote with rate, receive amount, and an expiry countdown.
Deposit
Enter your destination (and optional refund) address. The widget creates an order and shows a deposit address with QR, exact amount, and memo.
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.
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-componentnpm i mizuswap-componentimport { 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-jsnpm i mizuswap-js # or use the hosted bundle below<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>