Skip to main content

Configuration Options

Trails is easy to get started, however we have deep configuration options to address most use cases.

Core Props

PropTypeRequiredDescription
apiKeystringYesYour project access key provided by Trails
mode"pay" | "fund" | "earn" | "swap"YesWidget operation mode
toAddressstringNoDestination address for payments
toAmountstringNoExact amount for payments (used in pay mode)
toChainIdnumber | stringNoDestination chain ID
toTokenstringNoDestination token symbol or contract address
toCalldatastringNoCustom calldata for contract interactions

UI & Rendering Options

PropTypeRequiredDescription
renderInlinebooleanNoRender widget inline instead of as a modal (default: false)
childrenReact.ReactNodeNoCustom button content (when not renderInline)
buttonTextstringNoCustom text for the trigger button (auto-generated if not provided)
theme"light" | "dark" | "auto"NoColor theme; auto follows system preference (default: "auto")
customCssstring | Record<string, string>NoCustom CSS styles to apply to the component
disableCssbooleanNoDisable default CSS injection (for custom styling)
toastbooleanNoShow toast notifications for transaction updates
hideDisconnectbooleanNoHide the disconnect button in the widget
payMessagestringNoCustom message to display during payment flow

Wallet & Connection Options

PropTypeRequiredDescription
walletConnectProjectIdstringNoWalletConnect project ID for WalletConnect integration
walletOptionsstring[]NoArray of wallet connector IDs to show (e.g., ["metamask", "walletconnect"])
isSmartWalletbooleanNoIndicate if the connected wallet is a smart wallet (for ERC-4337 support)
decoupleWagmibooleanNoDecouple from wagmi provider (use external wagmi config)
wagmiConnectorsConnector[]NoCustom wagmi connectors to use

Transaction Options

PropTypeRequiredDescription
paymasterUrlsArray<{ chainId: number; url: string }>NoConfigure per-chain paymaster endpoints for gasless transactions
swapProviderRouteProviderNoPreferred swap provider: "AUTO", "LIFI", "RELAY", "SUSHI", "ZEROX", or "CCTP". Default: "AUTO" automatically selects best provider
bridgeProviderRouteProviderNoPreferred bridge provider: "AUTO", "LIFI", "RELAY", "CCTP". Default: "AUTO" automatically selects best provider for cross-chain transfers
slippageTolerancenumber | stringNoSlippage tolerance for swaps (e.g., 0.005 for 0.5%)
priceImpactWarningThresholdBpsnumberNoPrice impact threshold in basis points before showing a warning (e.g., 500 for 5%)
priceImpactWarningMessagestringNoCustom message to display when price impact exceeds threshold
priceImpactFallbackBridgeUrlstringNoURL to redirect users when price impact is too high

App Metadata (for WalletConnect)

PropTypeRequiredDescription
appNamestringNoYour app’s name (shown in wallet connect dialogs)
appUrlstringNoYour app’s URL
appImageUrlstringNoYour app’s logo URL
appDescriptionstringNoShort description of your app

Smart Contract Interactions

Execute custom contract calls with payments:
import { encodeFunctionData } from 'viem'

const calldata = encodeFunctionData({
  abi: contractABI,
  functionName: 'mintNFT',
  args: [recipient, tokenId]
})

<TrailsWidget
  apiKey="YOUR_API_KEY"
  mode="pay"
  toAddress="0x..." // Contract address
  toAmount="0.1"
  toChainId={1}
  toToken="ETH"
  toCalldata={calldata}
  onCheckoutComplete={(result) => {
    console.log('NFT minted:', result)
  }}
/>

Event Handling Examples

Complete Event Handling

import { getIsUserRejectionError } from '0xtrails'

<TrailsWidget
  apiKey="YOUR_API_KEY"
  mode="pay"
  toAddress="0x..."
  toAmount="1"
  toChainId={8453}
  toToken="USDC"
  onOriginConfirmation={({ txHash, chainId, sessionId }) => {
    console.log('Origin tx confirmed:', { txHash, chainId, sessionId })
  }}
  onDestinationConfirmation={({ txHash, chainId, sessionId }) => {
    console.log('Destination tx confirmed:', { txHash, chainId, sessionId })
  }}
  onCheckoutStatusUpdate={({ sessionId, transactionStates }) => {
    transactionStates.forEach((state, index) => {
      console.log(`Step ${index + 1}: ${state.label} - ${state.state}`)
      if (state.state === 'confirmed') {
        console.log('Transaction confirmed:', state.transactionHash)
      }
    })
  }}
  onCheckoutComplete={({ sessionId }) => {
    console.log('Transaction completed successfully:', sessionId)
  }}
  onCheckoutError={({ sessionId, error }) => {
    console.error('Transaction failed:', sessionId, error)
    
    // Check if user rejected the transaction
    if (getIsUserRejectionError(error)) {
      console.log('User rejected the transaction')
      // Handle user rejection (e.g., show "Transaction cancelled" message)
    } else {
      // Handle other errors (show error notification, retry logic, etc.)
    }
  }}
/>

Handling User Rejection

User rejection occurs when a user declines to sign a transaction in their wallet. This is handled through the onCheckoutError callback:
import { getIsUserRejectionError, TrailsWidget } from '0xtrails'

<TrailsWidget
  apiKey="YOUR_API_KEY"
  mode="pay"
  toAddress="0x..."
  onCheckoutError={({ sessionId, error }) => {
    if (getIsUserRejectionError(error)) {
      // User cancelled the transaction
      showNotification('Transaction cancelled by user')
    } else {
      // Other error occurred
      showNotification('Transaction failed: ' + error)
    }
  }}
/>