Widget Embed Guide

How to easily add staking and DeFi to your application

Overview

The Blockdaemon Earn Widget lets you offer staking and DeFi lending in your application via a hosted widget, without building protocol integrations or on-chain logic in-house. Blockdaemon deploys the widget on a per-client basis and connects directly to the Blockdaemon Earn Stack.​

The purpose of this guide is to support the evaluation and integration of the widget into your staging or production environments.​


Supported Features

The Blockdaemon Earn Widget currently supports the following functionality:​

  • Staking: Ethereum (via Stakewise vaults); Solana support is planned.​
  • DeFi lending: Aave on Ethereum, Base, Arbitrum, Optimism; Morpho and additional chains (Solana, Polygon) are planned.​
  • Swaps: Ethereum, Base, Arbitrum, Optimism, Kaia.​

Implementation Checklist

When preparing to go live, typical steps include:​

  • Widget Deployment: Confirm your https://<client-slug>.widget.blockdaemon.com deployment and target environment (staging vs production).
  • Embedding the Widget: Embed and size the iframe appropriately within your UI.
  • Configuration Model: Align features configuration with your product scope (staking, DeFi, swaps) and regulatory requirements.
  • Appearance & Branding: Configure appearance to meet brand, theme, locale, and currency guidelines.
  • Wallet Integration Modes: Select wallet mode (internal vs external) and, for external mode, implement the postMessage integration contract.
  • Validate transaction flows, balances, and lifecycle (connect / transact / disconnect) in your staging environment.

Widget Deployment

Each customer receives a dedicated widget instance hosted at:

https://<client-slug>.widget.blockdaemon.com

Blockdaemon manages the deployment lifecycle, upgrades, and configuration of the widget instance. A client-specific slug will be provided as part of your implementation onboarding.​


Embedding the Widget

To embed the widget, add the iframe to the relevant view or component in your application:​

<iframe
  src="https://<client-slug>.widget.blockdaemon.com" // Your Widget Instance URL
  id="blockdaemon-widget"
  title="Blockdaemon Earn Widget"
  allow="clipboard-write"
  style="width: 100%; height: 100%;">  
</iframe>

Consider the following when embedding:​

  • Sizing: The widget supports two sizing modes via appearance.sizingMode.
    • Fixed mode: Use fixed mode when you want a predictable, static widget footprint. The numeric sizing limits require a width between 375 and 1000 and a height between 480 and 1200.
    • Responsive mode: Use the responsive mode when the widget should adapt to the host layout. In this mode, the widget requires a minimum width of 375px and a minimum height of 480px.
    📘

    Recommended Usage

    • Use responsive mode + host CSS for adaptive embeds.
    • Use fixed mode for stable, known-size placements.
    • Use URL overrides for per-placement tuning or testing.
  • Scroll behavior: The widget's internal scroll area depends on host container sizing. Constrained iframe heights trigger internal scrolling, while unconstrained heights shift it to the outer page.
  • Security & Content Security Policy (CSP): Ensure you allow the widget origin in frame-src, e.g. https://<client-slug>.widget.blockdaemon.com.

Configuration Model

Blockdaemon currently manages widget configuration on your behalf; self-serve configuration will be provided via the Blockdaemon Partner Portal in a future release. Configuration can be applied per widget instance, with these specific parameters also available via URL query parameters:

  • colorScheme: Overrides theme (light or dark).
  • width: Overrides widget width (mobile, tablet, or numeric 375-1000)
  • height: Overrides widget height (mobile, tablet, or numeric 480-1200)
  • currency: Overrides currency (USD, KRW, JPY)
  • locale: Overrides locale (en-US, ko-KR, ja-JP)

Features Configuration

The widget’s functionality is controlled through a features configuration object:​

"features": {
   "portfolio": { "enabled": false },
   "staking": { "enabled": true },
   "swap": {
     "enabled": false,
     "chains": { "allowList": [], "blockList": [] },
     "assets": { "allowList": [], "blockList": [] },
     "dexes": { "allowList": [], "blockList": [ ] },
     "bridges": { "allowList": [], "blockList": [] },
     "fees": { "enabled": false }
   },
   "defi": {
     "enabled": true,
     "markets": [],
     "chains": { "allowList": [], "blockList": [] },
     "assets": { "allowList": [], "blockList": [] },
     "customVaults": false
   },
   "walletInfo": false,
   "walletMode": "internal/external"
 }
FieldDescription
portfolioEnables a unified view to track and manage user balances.
stakingProvides the interface for depositing assets to earn protocol rewards.
swapEnables token exchanges within a single chain or across chains.
defiConnects users to liquidity markets for lending and borrowing assets.
walletInfoControls the visibility of connected wallet addresses and balance data.
walletModeDetermines whether the widget or host application manages wallet connectivity.

Typical configuration patterns include:​

  • Enabling only staking for a particular chain or product line.
  • Restricting swap or DeFi to a curated allow-list of assets, chains, or markets.
  • Selecting wallet mode (internal vs external) to match your custody or wallet strategy.

Configuration changes are coordinated with your Blockdaemon contact and applied to your dedicated widget deployment.​

Appearance & Branding

The widget supports appearance configuration to align with your brand and layout:​

 "appearance": {
   "width": "375px"
   "height": "667px",
   "theme": "light",
   "builtByBlockdaemon": true,
   "logoUrl": "",
   "locale": "en-US",
   "currency": "USD"
 }

Field

Description

width

Sets the horizontal size of the widget using presets or custom pixel values to fit your application's layout.

Once configured, the iframe container should be adjusted to match the widget’s configured size to ensure a proper visual fit.

`height

Sets the vertical size of the widget using presets or custom pixel values to fit your application's layout.

Once configured, the iframe container should be adjusted to match the widget’s configured size to ensure a proper visual fit.

theme

Configuration supports light or dark modes with a default option available. Apps with a light / dark toggle should update this parameter to reflect the active selection.

logoUrl

The widget supports a single logo or individual logos tailored for light and dark color schemes.

builtByBlockdaemon

The flag determines whether the "Built by Blockdaemon" logo appears at the bottom of the widget UI.

locale

Determines language for balances and yields.​

currency

Determines displayed currency for balances and yields.​


Wallet Integration Modes

The widget supports two wallet integration modes:​

  1. Internal mode The widget manages wallet connection and network switching within the iframe. Users connect and approve transactions directly in the widget UI.
  2. External mode The host application owns wallet state, connection flow, and transaction execution. The widget requests wallet actions via postMessage, and the host responds with wallet state and transaction results.

In both modes, wallet connectivity is non-custodial and your application remains in control of user session and authentication outside the widget.​

Before a wallet is connected, the widget displays a default, disconnected state; once a wallet is connected, the widget updates to a fully interactive state.


External Wallet Mode: Messaging Contract

When using external wallet mode, the host application and the widget communicate via the standard window.postMessage API. All postMessage events must be filtered by origin, and only the widget origin (https://<client-slug>.widget.blockdaemon.com) should be trusted.​

Message Types

The widget may send the following message types to your application:​

  • getWalletState: Widget requests the latest host wallet state.
  • sendTransaction: Widget requests host submission of a transaction payload.
  • switchNetwork: Widget requests that the host switch to a target network.

Your application is expected to respond with:​

  • walletState: Host sends current wallet connection/network state.
  • sendTransactionResponse: Host returns transaction success/failure and result details.

Example: App ↔ Widget Integration

Below is a reference implementation illustrating event handling and wallet state propagation:​

<script>
const WIDGET_ORIGIN = "https://<client-slug>.widget.blockdaemon.com";
const iframe = document.getElementById("blockdaemon-widget");

// Host-owned wallet state (external mode)
let walletState = {
  isConnected: false,
  address: null,
  chainId: null, // CAIP-2, e.g. "eip155:1"
  walletInfo: "Client Wallet",
  namespace: "eip155",
};

function postToWidget(message) {
  if (!iframe?.contentWindow) return;
    iframe.contentWindow.postMessage(message, WIDGET_ORIGIN);
}

function sendWalletState() {
  postToWidget({
    type: "walletState",
    data: walletState,
  });
}

async function handleSendTransaction(transactionData) {
  try {
    // TODO: execute host wallet transaction
    const txHash = "0xtxhash...";
    postToWidget({
      type: "sendTransactionResponse",
      success: true,
      data: {
        hash: txHash,
        chainId: walletState.chainId, // required
      },
    });
  } catch (error) {
    postToWidget({
      type: "sendTransactionResponse",
      success: false,
      error: error instanceof Error ? error.message : "Transaction failed",
    });
  }
}

async function handleSwitchNetwork(request) {
  // request: { chainId: "eip155:137" } (CAIP-2)
  // TODO: trigger host wallet network switch flow
  // After switch completes, update walletState and notify widget:
  walletState = { ...walletState, chainId: request?.chainId ?? walletState.chainId };
  sendWalletState();
}

window.addEventListener("message", (event) => {
  // Validate origin + source
  if (event.origin !== WIDGET_ORIGIN) return;
  if (event.source !== iframe?.contentWindow) return;

  const { type, data } = event.data || {};

  switch (type) {
    case "getWalletState":
      sendWalletState();
      break;
    case "sendTransaction":
      handleSendTransaction(data);
      break;
    case "switchNetwork":
      handleSwitchNetwork(data);
      break;
    default:
      // ignore unknown message types
  }
});

// Initial sync
iframe?.addEventListener("load", () => {
  setTimeout(sendWalletState, 0);
});
</script>

The following table serves as the formal communication contract between the Widget and the Host:

Direction

Type

Payload

Purpose

Required Host Behavior

Widget
->
Host

getWalletState

none

Request current wallet status

Respond with walletState

Widget ->
Host

sendTransaction

transaction request object (to, optional value, data, optional chainId)

Ask host to submit a transaction

Execute with host wallet, then respond with sendTransactionResponse

Widget
->
Host

switchNetwork

{ chainId: "<caip2>" }

Ask host to switch wallet network

Trigger network switch flow, then publish updated walletState

Host
->
Widget

walletState

{ isConnected, address?, chainId?, walletInfo?, namespace? }

Provide latest host wallet state

Send on getWalletState and after any wallet/network change

Host
->
Widget

sendTransactionResponse

{ success, data?: { hash, chainId }, error?: string }

Return tx result to widget

Include hash + chainId on success; include error on failure


Next Steps and Support

For configuration changes, production cutover, or to discuss additional feature flags and chains, please contact your Blockdaemon representative or support channel. Blockdaemon can work with you to align widget behavior, branding, and wallet flows with your institutional requirements.​


👋 Need Help?

Contact us through email or our support page for any issues, bugs, or assistance you may need.