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

# Apps SDK (ChatGPT)

> Deep dive into ChatGPT's runtime: MCP Apps compatibility, the window.openai API, and ChatGPT-only features.

The [OpenAI Apps SDK](https://developers.openai.com/apps-sdk/) is the ChatGPT runtime layer for ChatGPT Apps, [announced in October 2025](https://alpic.ai/blog/inside-openai-s-apps-sdk-how-to-build-interactive-chatgpt-apps-with-mcp). ChatGPT supports the MCP Apps UI model, and also provides `window.openai` for compatibility and ChatGPT-specific extensions.

## View Rendering Flow

Here's what happens when ChatGPT renders a view:

1. User asks ChatGPT to perform an action (e.g., "Show me flight options to Paris")
2. ChatGPT calls your MCP tool (e.g., `search_flights`)
3. Your tool returns a result with data and a reference to a UI resource
4. ChatGPT fetches the resource (your compiled React component) and renders it in an iframe
5. The view is hydrated with your tool's `structuredContent` and `_meta` properties

<img src="https://mintcdn.com/skybridge-alpic/qsKsAKKpselsIl6n/images/fundamentals-chatgpt-apps.png?fit=max&auto=format&n=qsKsAKKpselsIl6n&q=85&s=ebf1260502b40e10fef7030a486e2f5a" alt="ChatGPT Apps Rendering Flow" style={{ width: "100%", maxWidth: "800px", display: "block", margin: "0 auto" }} width="1980" height="1114" data-path="images/fundamentals-chatgpt-apps.png" />

## The `window.openai` API

Views run inside an iframe and have access to a special [`window.openai`](https://developers.openai.com/apps-sdk/build/chatgpt-ui#understand-the-windowopenai-api) global. In ChatGPT, this acts as a compatibility layer plus an extension surface for host-specific features:

| API                            | Description                                                   |
| ------------------------------ | ------------------------------------------------------------- |
| `toolInput`                    | Arguments supplied when the tool was invoked                  |
| `toolOutput`                   | Your `structuredContent` — initial data passed from your tool |
| `toolResponseMetadata`         | The `_meta` payload; only the view sees it, never the model   |
| `viewState` / `setViewState()` | Persist UI state across interactions                          |
| `callTool()`                   | Trigger additional tool calls from the UI                     |
| `sendFollowUpMessage()`        | Send messages back into the chat                              |
| `requestDisplayMode()`         | Request inline, PiP, or fullscreen display                    |
| `requestModal()`               | Open a modal window outside the iframe                        |
| `uploadFile()`                 | Upload files to host-managed storage                          |
| `getFileDownloadUrl()`         | Get download URLs for uploaded files                          |
| `openExternal()`               | Open external URLs safely                                     |
| `setOpenInAppUrl()`            | Set URL for the "Open in \<App>" button in fullscreen mode    |

This API is powerful but low-level and imperative—which is where Skybridge comes in.

## Skybridge Hook Mapping

Skybridge wraps the raw `window.openai` API with React hooks:

| Raw API                                                            | Skybridge Hook                                                          | Purpose                                |
| ------------------------------------------------------------------ | ----------------------------------------------------------------------- | -------------------------------------- |
| `window.openai.toolInput`, `toolOutput`, `toolResponseMetadata`    | [`useToolInfo()`](/api-reference/use-tool-info)                         | Access tool input, output, and `_meta` |
| `window.openai.widgetState` and `window.openai.setWidgetState`     | [`useViewState()`](/api-reference/use-view-state)                       | Persistent view state                  |
| `window.openai.callTool()`                                         | [`useCallTool()`](/api-reference/use-call-tool)                         | Make additional tool calls             |
| `window.openai.sendFollowUpMessage()`                              | [`useSendFollowUpMessage()`](/api-reference/use-send-follow-up-message) | Send follow-up messages                |
| `window.openai.openExternal()`                                     | [`useOpenExternal()`](/api-reference/use-open-external)                 | Open external URLs                     |
| `window.openai.view` and `window.openai.requestModal()`            | [`useRequestModal()`](/api-reference/use-request-modal)                 | Request modal display                  |
| `window.openai.theme`, `maxHeight`, `safeArea`                     | [`useLayout()`](/api-reference/use-layout)                              | Theme, max height, safe area insets    |
| `window.openai.locale`, `userAgent`                                | [`useUser()`](/api-reference/use-user)                                  | Locale and device/capabilities         |
| `window.openai.displayMode` and `window.openai.requestDisplayMode` | [`useDisplayMode()`](/api-reference/use-display-mode)                   | Access/change display mode             |
| `window.openai.uploadFile()`, `getFileDownloadUrl()`               | [`useFiles()`](/api-reference/use-files)                                | Upload and download files              |
| `window.openai.setOpenInAppUrl()`                                  | [`useSetOpenInAppUrl()`](/api-reference/use-set-open-in-app-url)        | "Open in App" button URL in fullscreen |

## Apps SDK APIs not yet supported in Skybridge

The following [Apps SDK view APIs](https://developers.openai.com/apps-sdk/reference) are not yet wrapped by Skybridge hooks:

| Raw API                                    | Purpose                                                          |
| ------------------------------------------ | ---------------------------------------------------------------- |
| `window.openai.notifyIntrinsicHeight(...)` | Report dynamic view heights to the host to avoid scroll clipping |
| `window.openai.requestClose()`             | Close the view from the UI (e.g. user dismisses)                 |
| `window.openai.requestCheckout(...)`       | Open ChatGPT Instant Checkout UI (monetization)                  |

You can call these directly on `window.openai` when running in ChatGPT, if needed. Support may be added in a future release.

## Skybridge Apps SDK Exclusive Features

These features are **only available in ChatGPT** and not supported in MCP Apps:

### File Operations

Upload and download files with host-managed storage:

```tsx theme={null}
import { useFiles } from "skybridge/web";

function View() {
  const { upload, getDownloadUrl } = useFiles();

  const handleUpload = async (file: File) => {
    const { fileId } = await upload(file);
    const { downloadUrl } = await getDownloadUrl({ fileId });
    // Use downloadUrl...
  };

  return <input type="file" onChange={handleUpload} />;
}
```

### Open in App URL

Set a URL for the "Open in App" button that appears in fullscreen mode:

```tsx theme={null}
import { useSetOpenInAppUrl } from "skybridge/web";

function View() {
  const { setOpenInAppUrl } = useSetOpenInAppUrl();

  useEffect(() => {
    setOpenInAppUrl("https://myapp.com/view/123");
  }, []);

  return <div>View content</div>;
}
```

## Testing in ChatGPT

Please see the [Test Your App](/quickstart/test-your-app#testing-in-chatgpt) guide for more information.

<Warning>
  ChatGPT has aggressive caching. Use [DevTools](/devtools) for fast iteration, then test in ChatGPT for final validation. See [Fast Iteration](/concepts/fast-iteration).
</Warning>

## Related

* [MCP Apps](/fundamentals/mcp-apps) - The open alternative runtime
* [Write Once, Run Everywhere](/concepts/write-once-run-everywhere) - How Skybridge handles both runtimes
* [useSetOpenInAppUrl](/api-reference/use-set-open-in-app-url) - Open in App URL API reference
* [useFiles](/api-reference/use-files) - File operations API reference
