Nitrocloud LogoNitroStack
/sdk
/typescript
/ui
/widget sdk

Widget SDK API Reference

Overview

The NitroStack Widget SDK provides a modern, type-safe API for building interactive widgets that integrate with MCP servers and ChatGPT. The SDK offers React hooks, a singleton SDK class, and utility functions for common widget operations.

Quick Start

Typescript
'use client';

import { useWidgetSDK, useTheme } from '@nitrostack/widgets';

export default function MyWidget() {
  const { isReady, callTool, getToolOutput } = useWidgetSDK();
  const theme = useTheme();
  
  if (!isReady) return <div>Loading...</div>;
  
  const data = getToolOutput();
  
  return (
    <div style={{ 
      background: theme === 'dark' ? '#000' : '#fff',
      color: theme === 'dark' ? '#fff' : '#000'
    }}>
      <h1>{data.title}</h1>
    </div>
  );
}

Core Hooks

useWidgetSDK()

Primary hook for accessing all Widget SDK functionality.

Returns:

Typescript
{
  sdk: WidgetSDK;
  isReady: boolean;
  
  // State Management
  setState: (state: any) => Promise<void>;
  getState: () => any;
  
  // Tool Calling
  callTool: (name: string, args?: Record<string, unknown>) => Promise<CallToolResponse>;
  
  // Display Controls
  requestFullscreen: () => Promise<void>;
  requestInline: () => Promise<void>;
  requestPip: () => Promise<void>;
  requestDisplayMode: (mode: DisplayMode) => Promise<{ mode: DisplayMode }>;
  requestClose: () => void;
  
  // Navigation
  openExternal: (url: string) => void;
  sendFollowUpMessage: (prompt: string) => Promise<void>;
  
  // Data Access
  getToolInput: <T>() => T | null;
  getToolOutput: <T>() => T | null;
  getToolResponseMetadata: <T>() => T | null;
  getTheme: () => 'light' | 'dark';
  getMaxHeight: () => number;
  getDisplayMode: () => DisplayMode;
  getUserAgent: () => UserAgent | null;
  getLocale: () => string;
  getSafeArea: () => SafeArea | null;
}

Example:

Typescript
function InteractiveWidget() {
  const { isReady, callTool, getToolOutput, requestFullscreen } = useWidgetSDK();
  
  const handleAction = async () => {
    const result = await callTool('process_data', { id: '123' });
    console.log('Tool result:', result);
  };
  
  return (
    <div>
      <button onClick={handleAction}>Process</button>
      <button onClick={requestFullscreen}>Fullscreen</button>
    </div>
  );
}

useTheme()

Get the current theme (light or dark mode).

Returns: 'light' | 'dark' | null

Example:

Typescript
function ThemedWidget() {
  const theme = useTheme();
  
  const styles = {
    background: theme === 'dark' ? '#1a1a1a' : '#ffffff',
    color: theme === 'dark' ? '#ffffff' : '#000000',
    border: `1px solid ${theme === 'dark' ? '#333' : '#ddd'}`
  };
  
  return <div style={styles}>Theme-aware content</div>;
}

useDisplayMode()

Get the current display mode.

Returns: 'inline' | 'fullscreen' | 'pip' | null

Example:

Typescript
function ResponsiveWidget() {
  const displayMode = useDisplayMode();
  
  const padding = displayMode === 'fullscreen' ? '48px' : '16px';
  const fontSize = displayMode === 'fullscreen' ? '24px' : '16px';
  
  return (
    <div style={{ padding, fontSize }}>
      {displayMode === 'fullscreen' ? 'Fullscreen View' : 'Compact View'}
    </div>
  );
}

useMaxHeight()

Get the maximum height constraint for the widget.

Returns: number | null

Example:

Typescript
function ScrollableWidget() {
  const maxHeight = useMaxHeight();
  
  return (
    <div style={{ 
      maxHeight: maxHeight ? `${maxHeight}px` : 'none',
      overflow: 'auto'
    }}>
      <LongContent />
    </div>
  );
}

useWidgetState()

Manage persistent widget state with automatic synchronization.

Returns:

Typescript
{
  state: T | null;
  setState: (value: T | ((prev: T) => T)) => Promise<void>;
  isLoading: boolean;
}

Example:

Typescript
interface FormState {
  name: string;
  email: string;
}

function StatefulWidget() {
  const { state, setState, isLoading } = useWidgetState<FormState>();
  
  const updateName = (name: string) => {
    setState(prev => ({ ...prev, name }));
  };
  
  return (
    <div>
      <input 
        value={state?.name || ''} 
        onChange={(e) => updateName(e.target.value)}
      />
    </div>
  );
}

useOpenAiGlobal()

Subscribe to specific window.openai properties with automatic re-rendering on changes.

Parameters:

  • key: keyof OpenAiGlobals - Property to subscribe to

Returns: Property value or null

Example:

Typescript
function LocaleWidget() {
  const locale = useOpenAiGlobal('locale');
  const userAgent = useOpenAiGlobal('userAgent');
  
  return (
    <div>
      <p>Locale: {locale}</p>
      <p>Device: {userAgent?.deviceType}</p>
    </div>
  );
}

WidgetSDK Class

Singleton class providing direct access to all widget functionality.

getInstance()

Get the global SDK instance.

Returns: WidgetSDK

Example:

Typescript
import { getWidgetSDK } from '@nitrostack/widgets';

const sdk = getWidgetSDK();

isReady()

Check if the SDK is initialized and ready to use.

Returns: boolean

Example:

Typescript
const sdk = getWidgetSDK();
if (sdk.isReady()) {
  const theme = sdk.getTheme();
}

waitForReady()

Wait for the SDK to be ready with optional timeout.

Parameters:

  • timeout?: number - Timeout in milliseconds (default: 5000)

Returns: Promise<void>

Example:

Typescript
const sdk = getWidgetSDK();
try {
  await sdk.waitForReady(3000);
  console.log('SDK ready');
} catch (error) {
  console.error('SDK initialization timeout');
}

State Management

setState()

Set widget state with persistence.

Parameters:

  • state: any - State object to persist

Returns: Promise<void>

Example:

Typescript
const { setState } = useWidgetSDK();

await setState({ 
  selectedItems: [1, 2, 3],
  filters: { category: 'electronics' }
});

getState()

Get current widget state.

Returns: any | null

Example:

Typescript
const { getState } = useWidgetSDK();
const currentState = getState();

Tool Calling

callTool()

Call an MCP tool from within the widget.

Parameters:

  • name: string - Tool name
  • args?: Record<string, unknown> - Tool arguments

Returns: Promise<CallToolResponse>

Example:

Typescript
const { callTool } = useWidgetSDK();

const result = await callTool('search_products', {
  query: 'laptop',
  limit: 10
});

console.log('Products:', result.content);

Display Controls

requestFullscreen()

Request fullscreen display mode.

Returns: Promise<void>

Example:

Typescript
const { requestFullscreen } = useWidgetSDK();

<button onClick={requestFullscreen}>
  Expand to Fullscreen
</button>

requestInline()

Request inline display mode.

Returns: Promise<void>

requestPip()

Request picture-in-picture display mode.

Returns: Promise<void>

requestDisplayMode()

Request specific display mode.

Parameters:

  • mode: DisplayMode - 'inline' | 'fullscreen' | 'pip'

Returns: Promise<{ mode: DisplayMode }>

Example:

Typescript
const { requestDisplayMode } = useWidgetSDK();

await requestDisplayMode('fullscreen');

requestClose()

Close the widget.

Returns: void

Example:

Typescript
const { requestClose } = useWidgetSDK();

<button onClick={requestClose}>Close</button>

openExternal()

Open a URL in an external browser.

Parameters:

  • url: string - URL to open

Returns: void

Example:

Typescript
const { openExternal } = useWidgetSDK();

<a onClick={() => openExternal('https://example.com')}>
  Visit Website
</a>

sendFollowUpMessage()

Send a follow-up message to the chat.

Parameters:

  • prompt: string - Message to send

Returns: Promise<void>

Example:

Typescript
const { sendFollowUpMessage } = useWidgetSDK();

const askForMore = async () => {
  await sendFollowUpMessage('Show me more products like this');
};

Data Access

getToolInput()

Get the input parameters passed to the tool.

Type Parameter: T - Type of input data

Returns: T | null

Example:

Typescript
interface SearchInput {
  query: string;
  filters: string[];
}

const { getToolInput } = useWidgetSDK();
const input = getToolInput<SearchInput>();

console.log('Search query:', input?.query);

getToolOutput()

Get the output data from the tool.

Type Parameter: T - Type of output data

Returns: T | null

Example:

Typescript
interface ProductData {
  id: string;
  name: string;
  price: number;
}

const { getToolOutput } = useWidgetSDK();
const product = getToolOutput<ProductData>();

getToolResponseMetadata()

Get metadata about the tool response.

Type Parameter: T - Type of metadata

Returns: T | null

getTheme()

Get current theme.

Returns: 'light' | 'dark'

getMaxHeight()

Get maximum height constraint.

Returns: number

getDisplayMode()

Get current display mode.

Returns: DisplayMode

getUserAgent()

Get user agent information.

Returns: UserAgent | null

Example:

Typescript
const { getUserAgent } = useWidgetSDK();
const ua = getUserAgent();

if (ua?.deviceType === 'mobile') {
  // Show mobile-optimized UI
}

getLocale()

Get user's locale.

Returns: string

Example:

Typescript
const { getLocale } = useWidgetSDK();
const locale = getLocale(); // e.g., 'en-US'

getSafeArea()

Get safe area insets for the widget.

Returns: SafeArea | null

Utility Functions

prefersReducedMotion()

Check if user prefers reduced motion.

Returns: boolean

Example:

Typescript
import { prefersReducedMotion } from '@nitrostack/widgets';

const shouldAnimate = !prefersReducedMotion();

isPrimarilyTouchDevice()

Check if device is primarily touch-based.

Returns: boolean

Example:

Typescript
import { isPrimarilyTouchDevice } from '@nitrostack/widgets';

const buttonSize = isPrimarilyTouchDevice() ? '48px' : '32px';

isHoverAvailable()

Check if hover interactions are available.

Returns: boolean

Example:

Typescript
import { isHoverAvailable } from '@nitrostack/widgets';

const showTooltipOnHover = isHoverAvailable();

prefersDarkColorScheme()

Check if user prefers dark color scheme.

Returns: boolean

Example:

Typescript
import { prefersDarkColorScheme } from '@nitrostack/widgets';

const defaultTheme = prefersDarkColorScheme() ? 'dark' : 'light';

Type Definitions

DisplayMode

Typescript
type DisplayMode = 'inline' | 'fullscreen' | 'pip';

Theme

Typescript
type Theme = 'light' | 'dark';

CallToolResponse

Typescript
interface CallToolResponse {
  content: any;
  isError?: boolean;
}

UserAgent

Typescript
interface UserAgent {
  deviceType: DeviceType;
  browser: string;
  os: string;
}

type DeviceType = 'mobile' | 'tablet' | 'desktop';

SafeArea

Typescript
interface SafeArea {
  top: number;
  right: number;
  bottom: number;
  left: number;
}

Components

WidgetLayout

Wrapper component that provides consistent layout and theme integration.

Props:

Typescript
interface WidgetLayoutProps {
  children: React.ReactNode;
  className?: string;
  style?: React.CSSProperties;
}

Example:

Typescript
import { WidgetLayout } from '@nitrostack/widgets';

export default function MyWidget() {
  return (
    <WidgetLayout>
      <h1>My Widget</h1>
      <p>Content automatically adapts to theme</p>
    </WidgetLayout>
  );
}

Legacy API

withToolData()

Higher-Order Component for automatic data fetching (legacy pattern).

Note: This is maintained for backward compatibility. New widgets should use useWidgetSDK() instead.

Example:

Typescript
import { withToolData } from '@nitrostack/widgets';

function MyWidget({ data }) {
  return <div>{data.title}</div>;
}

export default withToolData(MyWidget);

Best Practices

1. Always Check isReady

Typescript
const { isReady, getToolOutput } = useWidgetSDK();

if (!isReady) {
  return <div>Loading...</div>;
}

const data = getToolOutput();

2. Use Type Parameters

Typescript
interface ProductData {
  id: string;
  name: string;
  price: number;
}

const product = getToolOutput<ProductData>();
// TypeScript knows the shape of product

3. Handle Null Values

Typescript
const theme = useTheme();
const bgColor = theme === 'dark' ? '#000' : '#fff';
// Default to light theme if null

4. Combine Hooks for Responsive Design

Typescript
function AdaptiveWidget() {
  const theme = useTheme();
  const displayMode = useDisplayMode();
  const maxHeight = useMaxHeight();
  
  const styles = {
    background: theme === 'dark' ? '#000' : '#fff',
    padding: displayMode === 'fullscreen' ? '48px' : '16px',
    maxHeight: maxHeight ? `${maxHeight}px` : 'none'
  };
  
  return <div style={styles}>Adaptive content</div>;
}

Migration from withToolData

See Widget SDK Migration Guide for detailed migration instructions.

See Also