DevelopersIntermediate

Embed a Swap Widget in Your App and Earn Fees

Embed the ChainBridge swap widget with an iframe, preset tokens and theme, listen to swap events and set a partner fee on every trade your users make.

ChainBridge ResearchUpdated 5 min read

On this page6 sections

Key takeaways

  • One iframe (or one script tag) adds a full ChainBridge swap to your site: quotes from 0x, KyberSwap and ParaSwap, wallet connection and safety checks included.
  • Six URL parameters preset the tokens, network, theme and your partner fee.
  • A partner fee of up to 300 bps applies only to an allowlisted feeRecipient and replaces the platform fee on swaps made in your widget.
  • Swap and wallet events reach your page through postMessage, only on origins ChainBridge has allowlisted; always check event.origin.

Embed in one snippet

Paste the iframe where the swap should appear. Visitors connect their own wallet and sign every transaction themselves: funds never pass through your site or through ChainBridge. The script tag does the same thing and is handy in a CMS where you can only add HTML attributes.

<style="color:#e06c75">iframe
  src=style="color:#98c379">"https:style="color:#5c6370style="color:#98c379">">//www.chainbridge.trading/widget?sellToken=ETH&buyToken=USDC&chainId=style="color:#d19a66">8453&theme=auto"
  width=style="color:#98c379">"style="color:#d19a66">420"
  height=style="color:#98c379">"style="color:#d19a66">560"
  title=style="color:#98c379">"Swap tokens"
  allow=style="color:#98c379">"clipboard-write"
  loading=style="color:#98c379">"lazy"
  style=style="color:#98c379">"border: style="color:#d19a66">0; border-radius: 16px"
></style="color:#e06c75">iframe>

A height of 520 to 600 px fits the swap card without scrolling; widths from 360 px work. If your site sends a Content-Security-Policy, allow https://www.chainbridge.trading in frame-src (and in script-src for widget.js).

URL parameters

Every parameter is optional. Without any, the widget opens on Ethereum with the light theme and the standard platform fee.

Widget URL parameters
ParameterValuesDescriptionScript attribute
sellTokenSymbolETH, USDC, WBTC... Matched against the built-in token list of the chain; unknown symbols are ignored.data-sell-token
buyTokenSymbolToken preselected on the receive side.data-buy-token
chainIdNumber1, 10, 56, 137, 8453, 42161, 43114 or 59144. Default 1 (Ethereum).data-chain-id
themelight | dark | autoDefault light. auto follows the visitor’s OS setting.data-theme
feeRecipientAddressYour partner wallet. Must be allowlisted by ChainBridge, otherwise quotes are rejected.data-fee-recipient
feeBps0 to 300Your fee in basis points (100 = 1%). Ignored without an allowlisted feeRecipient.data-fee-bps

With the script tag, data-width and data-height set the iframe size (default 420 × 520 px).

Partner fees

Partners earn a fee on every swap their users make in the widget. The fee is taken on-chain in the swap transaction and paid to your address on the network of the swap: no invoices, no payout schedule.

  1. Register your fee address

    Ask ChainBridge to add your address to the partner allowlist. Until it is listed, leave feeRecipient out: the quote API rejects unregistered recipients, so the widget would show no quotes.

  2. Add feeRecipient and feeBps

    feeBps goes from 0 to 300 (3%). Your fee replaces the ChainBridge platform fee (0.05% under $1,000, 0.1% from $1,000 to $9,999, 0.2% from $10,000) on those swaps; it is not added on top.

  3. Users see it before they sign

    The fee is part of the quote and shown on the review screen. Positive slippage stays with the user.

Example monthly earnings
Volume through your widget (example)Your feeYou earn
$50,00025 bps (0.25%)$125
$250,00025 bps (0.25%)$625
$250,00050 bps (0.50%)$1,250

Events

The widget posts messages to the page that embeds it. Every message has the same envelope: { source: 'chainbridge-widget', type, data?, timestamp }.

Widget postMessage events
typedataWhen
widget:ready(none)The widget has loaded.
wallet:connected{ address, chainId }A wallet connects or changes account or network.
wallet:disconnected(none)The wallet disconnects.
swap:started{ sellToken, buyToken, sellAmount }The user confirmed a swap. Tokens are symbols, amount is human-readable.
swap:success{ txHash, sellToken, buyToken, sellAmount, buyAmount, chainId }The swap settled. txHash can be missing for a gasless order.
swap:error{ error, isUserCancellation }The swap failed or the user rejected it in the wallet.

Swap events cover same-chain swaps; cross-chain transfers started in the widget do not emit them.

React example

A typed component that builds the URL and forwards events after three checks. It works in any React app, including Next.js client components.

SwapWidget.tsx
'use client'

import { useEffect, useRef } from 'react'

const WIDGET_ORIGIN = 'https://www.chainbridge.trading'

type WidgetEvent = {
  source: 'chainbridge-widget'
  type: 'widget:ready' | 'wallet:connected' | 'wallet:disconnected' | 'swap:started' | 'swap:success' | 'swap:error'
  data?: Record<string, unknown>
  timestamp: number
}

export function SwapWidget({ onEvent }: { onEvent?: (e: WidgetEvent) => void }) {
  const frame = useRef<HTMLIFrameElement>(null)

  useEffect(() => {
    const handler = (e: MessageEvent) => {
      if (e.origin !== WIDGET_ORIGIN) return "color:#5c6370">// 1. right origin
      if (e.source !== frame.current?.contentWindow) return "color:#5c6370">// 2. our iframe, not another one
      if (e.data?.source !== 'chainbridge-widget') return "color:#5c6370">// 3. widget envelope
      onEvent?.(e.data as WidgetEvent)
    }
    window.addEventListener('message', handler)
    return () => window.removeEventListener('message', handler)
  }, [onEvent])

  const params = new URLSearchParams({
    sellToken: 'ETH',
    buyToken: 'USDC',
    chainId: '8453',
    theme: 'auto',
    feeRecipient: '0xYourPartnerAddress', "color:#5c6370">// must be allowlisted
    feeBps: '25',
  })

  return (
    <iframe
      ref={frame}
      src={`${WIDGET_ORIGIN}/widget?${params}`}
      title="Swap tokens"
      allow="clipboard-write"
      className="h-[560px] w-full max-w-[440px] rounded-2xl border-0"
    />
  )
}
Usage
<SwapWidget
  onEvent={(e) => {
    if (e.type === 'swap:success') analytics.track('swap', e.data)
    if (e.type === 'swap:error' && !e.data?.isUserCancellation) showHelp()
  }}
/>

Security notes

  • Check the origin. Accept a message only if event.origin is exactly https://www.chainbridge.trading and event.source is your iframe. Any page or frame can call postMessage.
  • Treat events as hints, not proof. Before crediting a user or granting a reward, verify txHash on-chain with your own RPC.
  • Do not ask for keys or seed phrases. The widget never needs them; the user's wallet signs inside the iframe.
  • Safety checks stay on. Token safety screening, transaction simulation and the contract allowlist run in the widget exactly as on ChainBridge. See token safety checks.
  • Handle personal data with care. wallet:connected gives you the visitor's address. Treat it as personal data under your privacy policy.

Need quotes without a UI? Use the REST API directly.

Ready to embed?

The developer portal has the embed snippet and the full parameter list.

Open developer portal