@gadgetinc/react-chatgpt-apps 

The @gadgetinc/react-chatgpt-apps package provides wrapper components that allow you to communicate with your Gadget backend from a ChatGPT app's frontend widgets running inside ChatGPT.

Read more about ChatGPT apps in the Building ChatGPT apps guide.

The package source code is available on GitHub.

Features 

@gadgetinc/react-chatgpt-apps is a React library for connecting ChatGPT apps to Gadget backend applications. It provides:

  1. A <Provider> component that automatically authenticates your ChatGPT app with your Gadget backend
  2. Easy integration with @gadgetinc/react hooks for reading and writing data
  3. Automatic token management using OpenAI's and Gadget's authentication system

When building a ChatGPT app that needs to interact with a Gadget backend, this library handles all the authentication complexity for you, allowing your React components to focus on building great user experiences.

Installation 

For Gadget apps that have a ChatGPT app connection, the @gadgetinc/react-chatgpt-apps package is automatically installed.

If you need to install the package manually, you can do so with yarn:

terminal
yarn add @gadgetinc/react-chatgpt-apps
Package manager support

Gadget apps use yarn as the package manager.

If you are adding @gadgetinc/react-chatgpt-apps to a non-Gadget app, you can use the package manager of your choice.

Setup 

To use this library, wrap your ChatGPT app's React components in the Provider component from this package. The Provider automatically handles authentication with your Gadget backend using OpenAI's authentication system.

The best place to wrap your ChatGPT app's React components is in the web/chatgpt/root.tsx, which is a wrapper component that vite-plugin-chatgpt-widgets wraps all your ChatGPT widgets within.

web/chatgpt/root.jsx
React
// import the Provider component from this package import { Provider } from "@gadgetinc/react-chatgpt-apps"; // import an instance of the Gadget API client from your app, usually in web/api.ts import { api } from "../api"; function Root(props: { children: React.ReactNode }) { return <Provider api={api}>{props.children}</Provider>; } export default Root;
// import the Provider component from this package import { Provider } from "@gadgetinc/react-chatgpt-apps"; // import an instance of the Gadget API client from your app, usually in web/api.ts import { api } from "../api"; function Root(props: { children: React.ReactNode }) { return <Provider api={api}>{props.children}</Provider>; } export default Root;

Then, you must add an MCP tool call to your ChatGPT app's MCP server to allow fetching the auth token client side:

api/mcp.js
JavaScript
// gadget-specific tool for bootstrapping session auth within ChatGPT widgets // don't remove this if you are using the `api` object client side in your widget React code! mcpServer.registerTool( "__getGadgetAuthTokenV1", { title: "Get the gadget auth token", description: "Gets the gadget auth token. Should never be called by LLMs or ChatGPT -- only used for internal auth machinery.", _meta: { // ensure widgets can invoke this tool to get the token "openai/widgetAccessible": true, }, }, async () => { if (!request.headers["authorization"]) { return { structuredContent: { token: null, error: "no token found", }, content: [], }; } const [scheme, token] = request.headers["authorization"].split(" ", 2); if (scheme !== "Bearer") { return { structuredContent: { token: null, error: "incorrect token scheme", }, content: [], }; } return { structuredContent: { token, scheme, }, content: [], }; } );
// gadget-specific tool for bootstrapping session auth within ChatGPT widgets // don't remove this if you are using the `api` object client side in your widget React code! mcpServer.registerTool( "__getGadgetAuthTokenV1", { title: "Get the gadget auth token", description: "Gets the gadget auth token. Should never be called by LLMs or ChatGPT -- only used for internal auth machinery.", _meta: { // ensure widgets can invoke this tool to get the token "openai/widgetAccessible": true, }, }, async () => { if (!request.headers["authorization"]) { return { structuredContent: { token: null, error: "no token found", }, content: [], }; } const [scheme, token] = request.headers["authorization"].split(" ", 2); if (scheme !== "Bearer") { return { structuredContent: { token: null, error: "incorrect token scheme", }, content: [], }; } return { structuredContent: { token, scheme, }, content: [], }; } );

That's it! The Provider component will:

  1. Automatically fetch the authentication token from OpenAI when your app loads
  2. Configure your Gadget API client to use this token for all requests
  3. Ensure all API calls wait for authentication to be ready before proceeding

Using without authentication 

If you don't need authentication for your ChatGPT widgets such that they are safe to be world readable, you can disable authentication in the provider by setting the authenticate prop to false:

web/chatgpt/root.jsx
JavaScript
import { Provider } from "@gadgetinc/react-chatgpt-apps"; import { api } from "../api"; function Root(props: { children: React.ReactNode }) { return ( <Provider api={api} authenticate={false}> {props.children} </Provider> ); } export default Root;
import { Provider } from "@gadgetinc/react-chatgpt-apps"; import { api } from "../api"; function Root(props: { children: React.ReactNode }) { return ( <Provider api={api} authenticate={false}> {props.children} </Provider> ); } export default Root;

Reference 

Provider 

A Provider component that wraps your ChatGPT app's widgets to authenticate the API client and generate a session token.

Props 
  • api: Client - The Gadget API client to use for the extension.
  • authenticate: boolean - Whether to authenticate the API client. Defaults to true.

ChatGPT-specific hooks 

This package also provides hooks for interacting with the ChatGPT environment and the iframe environment's window.openai API. These hooks enable your app to respond to the ChatGPT context and provide a native experience.

More information on the window.openai API can be found in the Apps SDK docs.

useMaxHeight() 

Provides the value of openai.window.maxHeight. Get the maximum height available for your app in pixels. This value updates dynamically as the display mode or window size changes.

React
import { useMaxHeight } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const maxHeight = useMaxHeight(); return <div style={{ maxHeight }}>Content that respects viewport limits</div>; }
import { useMaxHeight } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const maxHeight = useMaxHeight(); return <div style={{ maxHeight }}>Content that respects viewport limits</div>; }

useDisplayMode() 

Provides the value of openai.window.displayMode. Access the current display mode of your ChatGPT app.

React
import { useDisplayMode } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const displayMode = useDisplayMode(); return <div>{displayMode === "fullscreen" ? <FullScreenView /> : <CompactView />}</div>; }
import { useDisplayMode } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const displayMode = useDisplayMode(); return <div>{displayMode === "fullscreen" ? <FullScreenView /> : <CompactView />}</div>; }
Returns 

Returns one of:

  • "pip" - Picture-in-picture mode (small floating window)
  • "inline" - Inline mode (embedded in the chat)
  • "fullscreen" - Fullscreen mode (takes up the entire screen)
  • null - If not available

useRequestDisplayMode() 

Request a change to the app's display mode.

React
import { useRequestDisplayMode } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const requestDisplayMode = useRequestDisplayMode(); const goFullscreen = async () => { const result = await requestDisplayMode("fullscreen"); console.log("Granted mode:", result.mode); }; return <button onClick={goFullscreen}>Go Fullscreen</button>; }
import { useRequestDisplayMode } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const requestDisplayMode = useRequestDisplayMode(); const goFullscreen = async () => { const result = await requestDisplayMode("fullscreen"); console.log("Granted mode:", result.mode); }; return <button onClick={goFullscreen}>Go Fullscreen</button>; }
Display mode requests

The host may reject or modify the request. For example, on mobile, "pip" is always coerced to fullscreen.

useWidgetState(defaultState) 

Manage persistent widget state that syncs with ChatGPT's storage system via window.openai.widgetState. State persists across re-renders and display mode changes.

React
import { useWidgetState } from "@gadgetinc/react-chatgpt-apps"; function Counter() { const [state, setState] = useWidgetState({ count: 0 }); return <button onClick={() => setState({ count: (state?.count ?? 0) + 1 })}>Count: {state?.count ?? 0}</button>; }
import { useWidgetState } from "@gadgetinc/react-chatgpt-apps"; function Counter() { const [state, setState] = useWidgetState({ count: 0 }); return <button onClick={() => setState({ count: (state?.count ?? 0) + 1 })}>Count: {state?.count ?? 0}</button>; }
Parameters 
  • defaultState: any - The default state value to use if no state is available.
Returns 

Returns a tuple similar to React's useState:

  • [0] - The current state value
  • [1] - A function to update the state

useWidgetProps(defaultProps) 

When ChatGPT makes a tool call for your widget, the MCP server may provide initial data through the window.openai.toolOutput property. This hook retrieves that data with optional defaults.

React
import { useWidgetProps } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const props = useWidgetProps({ userId: "unknown", theme: "light" }); return <div>User ID: {props.userId}</div>; }
import { useWidgetProps } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const props = useWidgetProps({ userId: "unknown", theme: "light" }); return <div>User ID: {props.userId}</div>; }
Parameters 
  • defaultProps: any - The default props to use if no props are available.
Returns 

Returns the props object passed to your widget from the ChatGPT window.openai.toolOutput, merged with the default props.

useSendMessage() 

Send follow-up messages to the ChatGPT conversation programmatically. Useful for creating interactive experiences that guide the conversation. Provides an interface for window.openai.sendFollowUpMessage().

React
import { useSendMessage } from "@gadgetinc/react-chatgpt-apps"; function QuickActions() { const sendMessage = useSendMessage(); return <button onClick={() => sendMessage("Tell me more about this")}>Ask for more details</button>; }
import { useSendMessage } from "@gadgetinc/react-chatgpt-apps"; function QuickActions() { const sendMessage = useSendMessage(); return <button onClick={() => sendMessage("Tell me more about this")}>Ask for more details</button>; }
Returns 

Returns a function that accepts a string message to send to the ChatGPT conversation.

useOpenExternal() 

Open external URLs in a way that respects the ChatGPT environment. Attempts to use ChatGPT's native link handler, falling back to window.open if unavailable. Provides an interface for window.openai.openExternal()

React
import { useOpenExternal } from "@gadgetinc/react-chatgpt-apps"; function LinkButton() { const openExternal = useOpenExternal(); return <button onClick={() => openExternal("https://example.com")}>Visit Example</button>; }
import { useOpenExternal } from "@gadgetinc/react-chatgpt-apps"; function LinkButton() { const openExternal = useOpenExternal(); return <button onClick={() => openExternal("https://example.com")}>Visit Example</button>; }
Returns 

Returns a function that accepts a URL string to open.

useCallTool() 

Call external tools/APIs that have been configured in your ChatGPT app. Provides an interface for window.openai.callTool().

React
import { useCallTool } from "@gadgetinc/react-chatgpt-apps"; function WeatherWidget() { const callTool = useCallTool(); const fetchWeather = async () => { const response = await callTool("weatherApi", { city: "San Francisco" }); console.log(response?.result); }; return <button onClick={fetchWeather}>Get Weather</button>; }
import { useCallTool } from "@gadgetinc/react-chatgpt-apps"; function WeatherWidget() { const callTool = useCallTool(); const fetchWeather = async () => { const response = await callTool("weatherApi", { city: "San Francisco" }); console.log(response?.result); }; return <button onClick={fetchWeather}>Get Weather</button>; }
Returns 

Returns a function that accepts:

  • toolName: string - The name of the tool to call
  • parameters: any - The parameters to pass to the tool

The function returns a promise that resolves to the tool's response.

useOpenAiGlobal(key) 

Low-level hook for accessing OpenAI global values from window.openai by key.

React
import { useOpenAiGlobal } from "@gadgetinc/react-chatgpt-apps"; function ThemeAwareComponent() { const theme = useOpenAiGlobal("theme"); const locale = useOpenAiGlobal("locale"); return <div className={theme}>Content in {locale}</div>; }
import { useOpenAiGlobal } from "@gadgetinc/react-chatgpt-apps"; function ThemeAwareComponent() { const theme = useOpenAiGlobal("theme"); const locale = useOpenAiGlobal("locale"); return <div className={theme}>Content in {locale}</div>; }
Parameters 
  • key: string - The key of the global value to access.
Returns 

Returns the value associated with the provided key from the OpenAI global context.

Using specific hooks

Most apps should use the more specific hooks like useDisplayMode or useMaxHeight instead of using this hook directly.

Was this page helpful?