Skip to main content

Fastest path: AI assistants

Paste this into any AI coding agent — Claude Code, Cursor, Windsurf, ChatGPT, or anything that can fetch a URL:
Fetch https://compasslabs.ai/llms-widgets.md and integrate Compass widgets into this project.
The agent will pull the full integration guide, install dependencies, generate the provider/server/widget files, and wire up your env. Claude Code users can install the slash command for repeat use:
mkdir -p .claude/commands
curl -o .claude/commands/integrate-compass-widgets.md \
  https://compasslabs.ai/integrate-compass-widgets.md
Then run /integrate-compass-widgets.

How it works

  1. User connects their wallet
  2. Widget shows yield opportunities (Aave, Morpho vaults, Pendle, credit, rebalancing)
  3. User picks a market, enters an amount, signs an EIP-712 transaction
  4. Your server relays the signed transaction to Compass; gas can be sponsored
  5. Each user gets a non-custodial product account — they sign every transaction themselves

Installation

npm install @compass-labs/widgets @tanstack/react-query react react-dom
You also need a wallet library. Anything that gives you an EIP-712 signer works — Privy, RainbowKit + wagmi, etc.

Quick start

Three steps: wrap with providers, add a server route, drop in a widget.

1. Providers

// components/providers.tsx
"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { PrivyProvider, usePrivy, useWallets } from "@privy-io/react-auth";
import { CompassProvider } from "@compass-labs/widgets";

const queryClient = new QueryClient();

function CompassWithPrivy({ children }: { children: React.ReactNode }) {
  const { login, logout } = usePrivy();
  const { wallets } = useWallets();
  const wallet = wallets[0];

  return (
    <CompassProvider
      defaultChain="base"
      wallet={{
        address: wallet?.address ?? null,
        signTypedData: async (data) => {
          const provider = await wallet?.getEthereumProvider();
          return provider.request({
            method: "eth_signTypedData_v4",
            params: [wallet.address, JSON.stringify(data)],
          });
        },
        login,
        logout,
      }}
    >
      {children}
    </CompassProvider>
  );
}

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <PrivyProvider appId={process.env.NEXT_PUBLIC_PRIVY_APP_ID!} config={{ /* ... */ }}>
      <QueryClientProvider client={queryClient}>
        <CompassWithPrivy>{children}</CompassWithPrivy>
      </QueryClientProvider>
    </PrivyProvider>
  );
}
Using RainbowKit, wagmi, or another library? See llms-widgets.md for full provider examples.

2. Server route

// app/api/compass/[...path]/route.ts
import { createCompassHandler } from "@compass-labs/widgets/server";

const handler = createCompassHandler({
  apiKey: process.env.COMPASS_API_KEY!,
  gasSponsorPrivateKey: process.env.GAS_SPONSOR_PK, // optional
  rpcUrls: {
    ethereum: process.env.ETHEREUM_MAINNET_RPC_URL,
    base: process.env.BASE_MAINNET_RPC_URL,
    arbitrum: process.env.ARBITRUM_MAINNET_RPC_URL,
  },
});

export const GET = handler;
export const POST = handler;
import { CompassModule } from "@compass-labs/widgets/server/nestjs";

@Module({
  imports: [
    CompassModule.register({
      apiKey: process.env.COMPASS_API_KEY!,
      rpcUrls: { /* ... */ },
    }),
  ],
})
export class AppModule {}
CompassModule.registerAsync() is also available if you need to inject config from another module (e.g. ConfigService). Routes are served at /api/compass/* — no global prefix needed.

3. Add a widget

// app/layout.tsx
import "@compass-labs/widgets/styles.css";
// app/page.tsx
"use client";
import { EarnAccount } from "@compass-labs/widgets";

export default function Home() {
  return <EarnAccount />;
}
Tailwind users — register the package as content:
// Tailwind v3
content: [..., "./node_modules/@compass-labs/widgets/**/*.{js,mjs,ts,tsx}"]

// Tailwind v4 (in CSS)
@source "../node_modules/@compass-labs/widgets/dist/**/*.{js,mjs}";

Available widgets

WidgetWhat it does
EarnAccountBanking-style savings account — variable (Aave, Morpho) + fixed (Pendle) markets, deposit/withdraw, P&L
CompassEarnWidgetUnified earn interface combining variable and fixed markets
CreditAccountCredit borrowing UI on top of an earn position
RebalancingWidgetAutomated portfolio rebalancing across positions
TraditionalInvestingWidgetTokenized stocks interface
Each widget accepts theming and sizing props. For full prop references, see llms-widgets.md or hover the types in your IDE.
<EarnAccount
  title="Savings Account"
  defaultMarketTab="variable"
  chain="base"
  onDeposit={(market, amount, txHash) => {}}
  onWithdraw={(market, amount, txHash) => {}}
/>

Building custom UIs

Prefer to compose your own layout? The SDK exports building blocks:
  • Shared componentsChainSwitcher, WalletStatus, EarnAccountGuard, CreditAccountGuard, EarnAccountBalance, AccountBalancesModal, DepositWithdrawForm, SwapForm, PnLSummary, TransactionHistory, CopyableAddress, ActionModal
  • Data hooksuseSwapQuote, useRebalancingData, useRefreshBalances
  • Context hooksuseCompassWallet, useCompassChain, useCompassApi, useEarnAccount, useCreditAccount

Theming

Six built-in presets: compass-dark, compass-light, minimal-dark, minimal-light, high-contrast-dark, high-contrast-light.
<CompassProvider theme="compass-dark" defaultChain="base">
  {/* widgets */}
</CompassProvider>
Override specific values:
<CompassProvider
  theme={{
    preset: 'compass-dark',
    overrides: { colors: { brand: { primary: '#8b5cf6' } } },
  }}
>
The full schema (colors, typography, spacing, shape, effects) is exported as the Theme type — your IDE will autocomplete every override.

Wallet adapter

CompassProvider needs a wallet prop bridging your wallet library to the widgets:
interface WalletAdapter {
  address: Address | null;
  chainId?: number;
  signTypedData: (data: TypedDataToSign) => Promise<string>;
  switchChain?: (chainId: number) => Promise<void>;
  login?: () => void;
  logout?: () => Promise<void>;
  ready?: boolean;
  fundWallet?: (params: FundWalletParams) => Promise<void>;
  sendTransaction?: (params: SendTransactionParams) => Promise<string>;
  hasExternalWallet?: boolean;
}
signTypedData is the critical one — every transaction is EIP-712 signed by the user, then your server relays it (and optionally sponsors gas).

Supported chains

ethereum, base, arbitrum.

Gas sponsorship

Set gasSponsorPrivateKey and rpcUrls on the server handler. Widgets automatically use sponsored transactions when configured. See Gas Sponsorship.

Next steps

LLM Integration Guide

Full reference for AI-assisted integration.

Earn

The underlying Yield API.

Fixed Earn

Add fixed-yield Pendle markets to your product.

Gas Sponsorship

Sponsor gas so users never need ETH.