Developer Docs

Widget SDK

Early access · v1

What is the Widget SDK?

The WidgetFlow Widget SDK lets you build custom widgets that run directly on the canvas alongside the built-in ones. Each widget is a React component — or any JavaScript — hosted inside a sandboxed iframe. Your code never touches the WidgetFlow codebase; it communicates with the host through a secure postMessage contract.

The SDK handles initialization, state persistence, theme syncing, and AI access. You write a component. WidgetFlow handles everything else.

Entry point

Import one hook. It returns everything your widget needs.

import { useWidgetFlow } from "@widgetflow/sdk";

export default function MyWidget() {
  const { state, saveState, theme, user, sdk } = useWidgetFlow();
  // ...
}

Props contract

state / saveState

stateis your widget's persisted JSON blob — any shape you want. null on first load. Call saveState(newState) to persist changes. Rate-limited to one call per second. State must be JSON-serializable.

theme: ThemeVars

interface ThemeVars {
  background: string;     // e.g. "#0a0a0a"
  surface: string;        // e.g. "#171717"
  border: string;         // e.g. "rgba(255,255,255,0.05)"
  text: string;           // e.g. "#ffffff"
  textMuted: string;      // e.g. "#a3a3a3"
  accent: string;         // e.g. "#8b5cf6"
  accentGradient: string; // e.g. "linear-gradient(to right, #8b5cf6, #7c3aed)"
}

Apply as inline style attributes — these are raw CSS strings, not Tailwind classes.

user: UserContext

username, displayName, and avatarUrl for the WidgetFlow user currently viewing this widget.

SDK methods

Available via the sdk object returned by the hook. All methods return Promises.

// Persistent key-value storage (scoped to widget + user)
sdk.storage.get(key: string): Promise<any>
sdk.storage.set(key: string, value: any): Promise<void>
sdk.storage.delete(key: string): Promise<void>

// AI
sdk.ai.prompt(text: string, options?: { persona?: string }): Promise<string>

Database, file storage, and external connections are planned for future SDK versions.

Example: Counter widget

A counter that persists across sessions and matches the host theme. This is the smallest complete example that exercises state, saveState, theme, and userContext.

"use client";
import { useWidgetFlow } from "@widgetflow/sdk";

interface CounterState { count: number; }

export default function CounterWidget() {
  const { state, saveState, theme, user } = useWidgetFlow();

  const count = (state as CounterState | null)?.count ?? 0;

  return (
    <div style={{ background: theme.background, color: theme.text,
                  display: "flex", flexDirection: "column",
                  alignItems: "center", justifyContent: "center",
                  height: "100%", padding: "24px" }}>

      {user.username && (
        <span style={{ color: theme.textMuted, fontSize: "11px",
                       position: "absolute", top: 12, right: 14 }}>
          @{user.username}
        </span>
      )}

      <div style={{ fontSize: "72px", fontWeight: 800,
                    background: theme.accentGradient,
                    WebkitBackgroundClip: "text",
                    WebkitTextFillColor: "transparent" }}>
        {count}
      </div>

      <div style={{ display: "flex", gap: "12px" }}>
        <button onClick={() => saveState({ count: count - 1 })}>−</button>
        <button onClick={() => saveState({ count: count + 1 })}>+</button>
      </div>
    </div>
  );
}

Constraints

  • One file, one component. Your widget is a single file with a default-exported React component.
  • No external network requests. The iframe Content Security Policy blocks outbound requests. Use sdk.ai.prompt for AI and sdk.storage for data.
  • No localStorage or sessionStorage. The sandbox blocks direct storage access. All persistence goes through saveState and sdk.storage.
  • State must be JSON-serializable. No functions, class instances, or circular references.
  • Inline styles for theming. Tailwind CSS is not available inside the iframe. Use the theme values as inline style props.

Apply for early access

The Widget SDK is in private early access. Reach out with what you want to build and we'll get you set up.

Request access →