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.
No secret keys in the browser
Auth is a public affiliate code, never a server API key. Omit it entirely and the dev API returns mock data for demos.
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"
},
"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. Start in mock mode with no affiliate code, then add your public affiliate code when you go live — no secret API key ever touches the browser.
React
mizuswap-componentnpm i mizuswap-componentimport { MizuSwap } from 'mizuswap-component';
export default function App() {
return (
<MizuSwap
config={{
// Your PUBLIC affiliate code (attribution). Omit it for the mock demo.
// Never put a secret API key in the browser — the widget never needs one.
affiliateCode: 'your-affiliate-code',
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>
<!-- Public affiliate code only — never a secret API key. Omit for the mock demo. -->
<mizu-swap id="swap" affiliate-code="your-affiliate-code"></mizu-swap>
<script>
document.getElementById('swap').config = {
affiliateCode: 'your-affiliate-code', // public attribution; .config wins over the attribute
theme: { preset: 'midnight' },
defaultDepositAsset: { blockchainTicker: 'BTC', contractId: 'BTC' },
defaultSettleAsset: { blockchainTicker: 'ETH', contractId: 'ETH' },
};
</script>