> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bluvo.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# iFrame vs. Whitelabel

> A technical comparison of headful iFrame widgets and headless whitelabel APIs for crypto exchange connectivity and withdrawal flows

## TL;DR

Two integration models for exchange connectivity and withdrawal flows:

* **Headful iFrame widget.** The vendor hosts the UI in a cross-origin `<iframe>` and communicates with the host page via `postMessage`.
* **Headless whitelabel API.** The vendor exposes REST endpoints and optional SDKs; the integrator builds and owns the UI.

Bluvo ships only the headless model: REST APIs at `api-bluvo.com`, plus optional [`@bluvo/sdk-ts`](https://www.npmjs.com/package/@bluvo/sdk-ts) and [`@bluvo/react`](https://www.npmjs.com/package/@bluvo/react). No Bluvo iFrame.

<Tip>
  Whitelabel wins on UI control, instrumentation, latency, and agent compatibility. With a state-machine SDK, the implementation gap against an iFrame is small.
</Tip>

***

## Comparison

|                    | iFrame Widget                                      | Whitelabel API                    |
| ------------------ | -------------------------------------------------- | --------------------------------- |
| UI ownership       | Vendor DOM, cross-origin                           | Integrator DOM, same-origin       |
| Flow control       | Vendor-defined, `postMessage` events               | Enumerable states, direct `fetch` |
| Bundle             | Vendor runtime on the critical path                | Zero, or SDK (\~few KB)           |
| Latency            | Extra document load, `frame-ancestors` negotiation | Single request round-trip         |
| Analytics          | Only vendor-exposed events                         | Full `x-bluvo-*` request tracing  |
| A/B testing        | Constrained to vendor surfaces                     | Any screen, any variant           |
| Accessibility      | Vendor markup, limited override                    | Integrator markup, full control   |
| Agent / MCP        | Opaque cross-origin DOM                            | Deterministic function calls      |
| Compliance surface | Shared with the vendor                             | Integrator-owned                  |
| Time-to-first-flow | Hours, if widget config fits                       | Hours with SDK, days without      |

***

## Trade-offs

**iFrame constraints.** Cross-frame `postMessage` for state sync, `frame-ancestors` and CSP negotiation, vendor bundle on the critical path, mobile scroll and focus quirks, third-party branding on the 2FA screen. No way to gate entry on KYC, branch by user segment, or inject product-specific confirmation steps.

**Whitelabel responsibilities.** You own forms, error states, and KYC / 2FA branching. A mature SDK collapses the protocol (OAuth popup, 2FA, SMS, MFA, quote refresh, execute) into enumerable states; without one, you wire the states yourself against REST with `x-bluvo-*` headers.

***

## Code

<CodeGroup>
  ```tsx React SDK (@bluvo/react) theme={null}
  "use client";

  import { useBluvoFlow } from "@bluvo/react";

  export function Withdraw({ walletId }: { walletId: string }) {
    const flow = useBluvoFlow({ walletId });

    if (flow.needs2FA)   return <TwoFAInput onSubmit={flow.submit2FA} />;
    if (flow.needsQuote) return <QuoteForm  onSubmit={flow.requestQuote} />;
    if (flow.canExecute) return <Confirm    onClick={flow.execute} />;

    return <Status state={flow.state} />;
  }
  ```

  ```ts Raw REST (fetch) theme={null}
  // Server-side only. Never expose x-bluvo-api-key to the browser.
  const res = await fetch(
    "https://api-bluvo.com/api/v0/wallet/withdraw/quote",
    {
      method: "POST",
      headers: {
        "content-type": "application/json",
        "x-bluvo-org-id":     process.env.BLUVO_ORG_ID!,
        "x-bluvo-project-id": process.env.BLUVO_PROJECT_ID!,
        "x-bluvo-api-key":    process.env.BLUVO_API_KEY!,
        "x-bluvo-wallet-id":  walletId,
      },
      body: JSON.stringify({ asset: "USDT", network: "TRON", amount: "50" }),
    },
  );
  const quote = await res.json();
  ```
</CodeGroup>

The SDK is opt-in. REST is always available.

***

## By audience

* **Product and business.** Brand, analytics, funnel, compliance surface, and A/B testing on the highest-trust screen in the app.
* **Engineering.** Same headers, same `walletId`, same auth. The SDK reduces 30+ withdrawal states (OAuth, 2FA, SMS, KYC, MFA, quote, execute) to booleans, or call REST directly for zero runtime cost. See [`/learn/sdk/state-machine`](/learn/sdk/state-machine).
* **End users.** Faster first paint, native UI, consistent copy, no embedded-document scroll or focus quirks on mobile.

***

## Automation and MCP

<Tip>
  Whitelabel exposes deterministic, enumerable states. Through MCP and Bluvo's [`skill.md`](/learn/skill), an agent reads state, submits 2FA, polls, and confirms, all by calling functions. An iFrame is an opaque cross-origin DOM; agents cannot interact with it programmatically.
</Tip>

***

## Why Bluvo ships whitelabel only

<Note>
  iFrames are a legitimate choice for prototypes, internal tools, and demos. Bluvo's customers, PSPs, dApps, and agent platforms, care about brand, conversion, compliance, and agent compatibility more than "shippable in an afternoon." With the state-machine SDK, the time an iFrame saves is not worth the trade-offs.
</Note>

***

## Next Steps

<CardGroup cols={3}>
  <Card title="OAuth2 Integration" icon="lock" href="/learn/oauth2-integration">
    Implement the full OAuth2 popup flow
  </Card>

  <Card title="State Machine SDK" icon="diagram-project" href="/learn/sdk/state-machine">
    30+ withdrawal states reduced to booleans
  </Card>

  <Card title="Agent Skills" icon="robot" href="/learn/skill">
    Make AI agents build accurate Bluvo integrations
  </Card>
</CardGroup>
