Skip to main content
Widgets are the user-facing layer of your ChatGPT app—self-contained HTML files served as MCP resources and embedded by ChatGPT as iframes. Any approach that produces a single self-contained HTML file works:
  • React + Vite + vite-plugin-singlefile — Build widgets as React SPAs bundled into one HTML file (TypeScript reference).
  • Self-contained HTML — Write standalone HTML files with inline CSS and JS. No build step needed (Python reference).
The bridge API and lifecycle pattern below apply to both approaches.
1

Build the ChatGPT widget bridge

The widget bridge wraps the window.openai API that ChatGPT provides inside widget iframes. The TypeScript example creates a shared module; the Python example calls window.openai directly inline.
2

Build the widgets

This section applies to the TypeScript/React implementation only. If you are writing self-contained HTML files directly, as the Python reference implementation does, skip to Integrate Gr4vy Embed.
Each widget is a React SPA bundled into a single HTML file. The UI is app-specific—see the reference implementation for a complete example. This guide covers the communication pattern every widget shares.Every widget follows the same file layout:
Every widget follows the same communication lifecycle:
src/widgets/<widget-name>/App.tsx
The checkout widget follows this same pattern with the addition of Gr4vy Embed. See Integrate Gr4vy Embed.
3

Configure the widget build process

Compile widgets into self-contained HTML files using Vite and vite-plugin-singlefile. The config accepts a WIDGET environment variable so the same file builds every widget:
vite.config.ts
Create scripts/build-widgets.ts to build each widget and rename the output:
scripts/build-widgets.ts
Run the build:
This produces product-catalog.html, shopping-cart.html, and checkout.html in dist/widgets/, each fully self-contained.Continue to Integrate Gr4vy Embed.