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.
@gadgetinc/react-chatgpt-apps is a React library for connecting ChatGPT apps to Gadget backend applications. It provides:
A <Provider> component that automatically authenticates your ChatGPT app with your Gadget backend
Easy integration with @gadgetinc/react hooks for reading and writing data
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:
Automatically fetch the authentication token from OpenAI when your app loads
Configure your Gadget API client to use this token for all requests
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.
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.
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.
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().