# `@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 [ChatGPT connection guide](https://docs.gadget-canary.xyz/guides/plugins/chatgpt). The package source code is available on [GitHub](https://github.com/gadget-inc/js-clients/tree/main/packages/react-chatgpt-apps). ## Features  `@gadgetinc/react-chatgpt-apps` is a React library for connecting ChatGPT apps to Gadget backend applications. It provides: 1. A `` 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`: ```bash yarn add @gadgetinc/react-chatgpt-apps ``` 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. ```tsx // 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 {props.children}; } 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: ```typescript // 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: ```typescript import { Provider } from "@gadgetinc/react-chatgpt-apps"; import { api } from "../api"; function Root(props: { children: React.ReactNode }) { return ( {props.children} ); } 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](https://developers.openai.com/apps-sdk/build/custom-ux). ### `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. ```tsx import { useMaxHeight } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const maxHeight = useMaxHeight(); return
Content that respects viewport limits
; } ``` ### `useDisplayMode()`  Provides the value of `openai.window.displayMode`. Access the current display mode of your ChatGPT app. ```tsx import { useDisplayMode } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const displayMode = useDisplayMode(); return
{displayMode === "fullscreen" ? : }
; } ``` ##### 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. ```tsx 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 ; } ``` 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. ```tsx import { useWidgetState } from "@gadgetinc/react-chatgpt-apps"; function Counter() { const [state, setState] = useWidgetState({ count: 0 }); return ; } ``` ##### 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. ```tsx import { useWidgetProps } from "@gadgetinc/react-chatgpt-apps"; function MyWidget() { const props = useWidgetProps({ userId: "unknown", theme: "light" }); return
User ID: {props.userId}
; } ``` ##### 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()`. ```tsx import { useSendMessage } from "@gadgetinc/react-chatgpt-apps"; function QuickActions() { const sendMessage = useSendMessage(); return ; } ``` ##### 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()` ```tsx import { useOpenExternal } from "@gadgetinc/react-chatgpt-apps"; function LinkButton() { const openExternal = useOpenExternal(); return ; } ``` ##### 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()`. ```tsx 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 ; } ``` ##### 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. ```tsx import { useOpenAiGlobal } from "@gadgetinc/react-chatgpt-apps"; function ThemeAwareComponent() { const theme = useOpenAiGlobal("theme"); const locale = useOpenAiGlobal("locale"); return
Content in {locale}
; } ``` ##### 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. Most apps should use the more specific hooks like `useDisplayMode` or `useMaxHeight` instead of using this hook directly.