Widget

The orda Widget is a comprehensive, embeddable React component that enables multi-chain cryptocurrency payments in your application — swap, on-ramp, and off-ramp flows with built-in wallet connection, all wrapped around the orda TypeScript SDK.

Replaces the old /developers/widget-beta page. The widget moved out of @ordanetwork/sdk/react (deleted in the SDK v2 release) into its own package @ordanetwork/[email protected]. If you were on the beta, see Migrating from @ordanetwork/sdk/react at the bottom.Try the widget →

What it does

  • Multi-chain support — EVM (Ethereum, Polygon, Arbitrum, Base, Optimism, plus plasma / stable / megaeth) and Solana

  • Three transaction flows — Swap, Off-ramp (crypto → BRL via PIX), On-ramp (BRL → crypto via PIX)

  • Wallet integration — WalletConnect / Reown AppKit modal mounted for you

  • Lifecycle callbacks — 10 typed events for quote / transaction / wallet / error, plus a firehose for analytics

  • Recipient management — save and manage payment recipients

  • Token prices & balances — real-time USD prices and multi-chain balance fetching

  • Responsive UI — desktop and mobile

  • Customizable theming — CSS variables

Prerequisites

  1. WalletConnect / Reown project id — cloud.reown.com

  2. orda API credentials — clientId and clientSecret

  3. React 18 or React 19

  4. Node.js 18+

Installation

Version compatibility

Package
Version

@ordanetwork/widget

^1.0.0

@ordanetwork/sdk

^1.3.0 || ^2.0.0

react

^18.0.0 || ^19.0.0

react-dom

^18.0.0 || ^19.0.0

@tanstack/react-query

^5.0.0

wagmi

^2.0.0

viem

^2.0.0

@solana/web3.js, @reown/appkit*, and the radix-ui primitives are direct dependencies of @ordanetwork/widget — you don't need to install them yourself.

Quick start

Step 1 — Set environment variables (.env.local)

Step 2 — Create the JWT auth route (app/api/auth/jwt/route.ts)

The widget calls config.getToken() to obtain a JWT; you handle credential exchange server-side so the secret never reaches the browser.

Step 3 — Create the provider (app/providers.tsx)

Step 4 — Mount the provider + styles in your root layout (app/layout.tsx)

Step 5 — Drop in the Widget (app/page.tsx)

Step 6 — Run

Lifecycle callbacks

All optional props on <Widget />. Every event fires alongside onAnalyticsEvent — dedupe by event.id if you wire both (see Analytics firehose below).

Callback
Fires when

onQuoteRequested

The widget asked the SDK for a quote (before network round-trip).

onQuoteAccepted

A quote returned successfully (or was served from the 30 s cache — payload.cached: true).

onQuoteFailed

Quote request failed (network / validation / SDK error).

onTransactionInitiated

User confirmed; the wallet was asked to sign / submit.

onTransactionSettled

Transaction confirmed on-chain or settled by the backend.

onTransactionFailed

Transaction reverted, was rejected, or failed before settling.

onWalletConnected

An EVM or Solana wallet just connected.

onWalletDisconnected

A wallet just disconnected.

onError

Any user-visible error (fires alongside the specific *_failed callback when applicable).

onAnalyticsEvent

Firehose — every event in order.

Every event payload shares the same envelope:

Analytics firehose

onAnalyticsEvent fires for every event, alongside the specific callback. Dedupe by event.id when you wire both:

Payload redaction (PII)

  • quote_accepted carries only a serializable summary — transactionId, provider, fromSymbol/toSymbol, fromAmount/toAmount, fromChainId/toChainId, estimatedDuration, and cached. It does not include PIX key / QR code, deposit address, reference id, raw transactionRequest / approvalTxParams (signed calldata), or wallet addresses.

  • quote_failed, transaction_failed, and error expose a human-readable message plus an optional causeMessage string. The underlying error object is never forwarded — viem / RPC errors embed tx params and request payloads, so only a message string crosses the callback boundary.

If you need the full, unredacted quote (e.g. to render PIX deposit instructions yourself), read it from the hook return values (useOnRamp().quote, etc.) rather than from events.

Configuration flags

All optional on the config object passed to <OrdaProvider>:

Field
Default
Effect

getToken

— (required)

Returns { jwt, expiresAt }. Called on mount and ~5 min before expiry.

appKitConfig

— (required)

From createAppKitConfig({ projectId, metadata }).

debug

false

Verbose console logs for SDK init / refresh.

notifications

true

When true, mounts a Sonner <Toaster />. When false, in-progress states render as inline <Alert /> banners and success / error states surface only through lifecycle callbacks.

disableOnRamp

false

Hide on-ramp (fiat → crypto) flows.

disableOffRamp

false

Hide off-ramp (crypto → fiat) flows.

enableOfframpSolana

false

Allow Solana as a source chain for off-ramp.

Apps controlling these via env (e.g. NEXT_PUBLIC_ON_RAMP_DISABLED) should map the env value to the config field when constructing the provider — the widget does not read process.env.* directly.

SSR / RSC

@ordanetwork/widget is a client component. The bundle starts with 'use client'; so importing it from a React Server Component is safe — you get the 'use client' boundary automatically. You do not need to wrap it.

createAppKitConfig() must be called at module scope (outside components) for SSR safety — see Step 3 above.

Wallet mode

@ordanetwork/[email protected] ships one wallet mode: appkit (the default). The widget mounts Wagmi + the Reown AppKit modal internally; you supply a projectId via createAppKitConfig.

BYOW (wallet: 'external') is coming in 1.1.0 — for hosts that already own a <WagmiProvider> and want the widget to consume it. The plumbing exists internally; a few downstream call sites are still being migrated. Tracked as COR-963.

TypeScript

All types ship with the package; no @types/... install needed.

The full event union is discriminated by type, so narrowing in a callback works without casts.

Security note

Migrating from @ordanetwork/sdk/react

If you integrated against the beta (when the widget lived inside the core SDK), here's the migration:

Before (@ordanetwork/sdk/react)

After (@ordanetwork/widget)

npm install @ordanetwork/sdk

npm install @ordanetwork/widget @ordanetwork/sdk

import { OrdaProvider, Widget, createAppKitConfig } from '@ordanetwork/sdk/react'

import { OrdaProvider, Widget, createAppKitConfig } from '@ordanetwork/widget'

import '@ordanetwork/sdk/react/styles.css'

import '@ordanetwork/widget/styles.css'

No runtime behavior changes — the same components, the same OrdaProvider config shape, the same Widget props. The split is purely about packaging: the React UI now ships independently of the core SDK so it can version on its own cadence.

The @ordanetwork/sdk itself remains a peer dependency (the widget uses it internally for quote / transaction / recipient API calls).

Last updated