Primary navigation

Reference

API and SDK reference for Apps SDK.

window.openai component bridge

Components rendered by ChatGPT run in a sandboxed iframe. The host injects a window.openai global so your bundle can exchange data with the conversation.

APIPurpose
window.openai.toolInputArguments ChatGPT provided to the tool call.
window.openai.toolOutputThe JSON your tool returned. Use as initial render data.
window.openai.widgetStatePersisted component state from prior renders. Read first and fall back to toolOutput.
window.openai.setWidgetState(state)Persist state back to the host. Returns a promise when stored.
window.openai.callTool(name, args)Invoke another tool exposed by your MCP server. Useful for in-component actions such as moving a task or refreshing data.
window.openai.sendFollowupTurn({ prompt })Insert a message into the conversation, often after a user clicks a button inside the component.
window.openai.requestDisplayMode({ mode })Request a layout change (inline, pip, fullscreen). The host decides whether to honour the request.
window.openai.maxHeight / displayModeRead-only globals describing the current layout constraints.
window.openai.localeLocale string for the active user (BCP 47). Use it to load translations, format numbers, and surface localized copy.
window.openai.themeCurrent theme (light/dark).

Listen for window events to react to host updates:

  • openai:set_globals – dispatched when globals change (e.g., displayMode, maxHeight, toolOutput, widgetState).
  • openai:tool_response – dispatched after callTool completes with details of the tool invocation.

Compatibility: window.oai or window.webplus may be present for legacy components, but new components should use window.openai.

Tool descriptor parameters

By default, a tool description should include the fields listed here.

_meta fields on tool descriptor

We have also require the following _meta fields on the tool descriptor:

KeyPlacementTypeLimitsPurpose
_meta["securitySchemes"]Tool descriptorarrayBack-compat mirror for clients that only read _meta.
_meta["openai/outputTemplate"]Tool descriptorstring (URI)Resource URI for component HTML template (text/html+skybridge).
_meta["openai/widgetAccessible"]Tool descriptorbooleandefault falseAllow component→tool calls through the client bridge.
_meta["openai/toolInvocation/invoking"]Tool descriptorstring≤ 64 charsShort status text while the tool runs.
_meta["openai/toolInvocation/invoked"]Tool descriptorstring≤ 64 charsShort status text after the tool completes.

Example:

server.registerTool(
  "search",
  {
    title: "Public Search",
    description: "Search public documents.",
    inputSchema: {
      type: "object",
      properties: { q: { type: "string" } },
      required: ["q"]
    },
    securitySchemes: [
      { type: "noauth" },
      { type: "oauth2", scopes: ["search.read"] }
    ],
    _meta: {
      securitySchemes: [
        { type: "noauth" },
        { type: "oauth2", scopes: ["search.read"] }
      ],
      "openai/outputTemplate": "ui://widget/story.html",
      "openai/toolInvocation/invoking": "Searching…",
      "openai/toolInvocation/invoked": "Results ready"
    }
  },
  async ({ q }) => performSearch(q)
);

Annotations

To label a tool as “read-only”, please use the following annotation on the tool descriptor:

KeyTypeRequiredNotes
readOnlyHintbooleanOptionalSignal that the tool is read-only (helps model planning).

Example:

server.registerTool(
  "list_saved_recipes",
  {
    title: "List saved recipes",
    description: "Returns the user’s saved recipes without modifying them.",
    inputSchema: { type: "object", properties: {}, additionalProperties: false },
    annotations: { readOnlyHint: true }
  },
  async () => fetchSavedRecipes()
);

Component resource _meta fields

Set these keys on the resource template that serves your component (registerResource). They help ChatGPT describe and frame the rendered iframe without leaking metadata to other clients.

KeyPlacementTypePurpose
_meta["openai/widgetDescription"]Resource contentsstringHuman-readable summary surfaced to the model when the component loads, reducing redundant assistant narration.
_meta["openai/widgetPrefersBorder"]Resource contentsbooleanHint that the component should render inside a bordered card when supported.
_meta["openai/widgetCSP"]Resource contentsobjectDefine connect_domains and resource_domains arrays for the component’s CSP snapshot.
_meta["openai/widgetDomain"]Resource contentsstring (origin)Optional dedicated subdomain for hosted components (defaults to https://web-sandbox.oaiusercontent.com).

Example:

server.registerResource("html", "ui://widget/widget.html", {}, async () => ({
  contents: [
    {
      uri: "ui://widget/widget.html",
      mimeType: "text/html",
      text: componentHtml,
      _meta: {
        "openai/widgetDescription": "Renders an interactive UI showcasing the zoo animals returned by get_zoo_animals.",
        "openai/widgetPrefersBorder": true,
        "openai/widgetCSP": {
          connect_domains: [],
          resource_domains: ["https://persistent.oaistatic.com"],
        },
        "openai/widgetDomain": "https://chatgpt.com",
      },
    },
  ],
}));

Tool results

Tool results can contain the following fields. Notably:

KeyTypeRequiredNotes
structuredContentobjectOptionalSurfaced to the model and the component. Must match the declared outputSchema, when provided.
contentstring or Content[]OptionalSurfaced to the model and the component.
_metaobjectOptionalDelivered only to the component. Hidden from the model.

Only structuredContent and content appear in the conversation transcript. _meta is forwarded to the component so you can hydrate UI without exposing the data to the model.

Example:

server.registerTool(
  "get_zoo_animals",
  {
    title: "get_zoo_animals",
    inputSchema: { count: z.number().int().min(1).max(20).optional() },
    _meta: { "openai/outputTemplate": "ui://widget/widget.html" }
  },
  async ({ count = 10 }) => {
    const animals = generateZooAnimals(count);

    return {
      structuredContent: { animals },
      content: [{ type: "text", text: `Here are ${animals.length} animals.` }],
      _meta: {
        allAnimalsById: Object.fromEntries(animals.map((animal) => [animal.id, animal]))
      }
    };
  }
);

Error tool result

To return an error on the tool result, use the following _meta key:

KeyPurposeTypeNotes
_meta["mcp/www_authenticate"]Error resultstring or string[]RFC 7235 WWW-Authenticate challenges to trigger OAuth.

_meta fields the client provides

KeyWhen providedTypePurpose
_meta["openai/locale"]Initialize + tool callsstring (BCP 47)Requested locale (older clients may send _meta["webplus/i18n"]).
_meta["openai/userAgent"]Tool callsstringUser agent hint for analytics or formatting.
_meta["openai/userLocation"]Tool callsobjectCoarse location hint (city, region, country, timezone, longitude, latitude).

Operation-phase _meta["openai/userAgent"] and _meta["openai/userLocation"] are hints only; servers should never rely on them for authorization decisions and must tolerate their absence.

Example:

server.registerTool(
  "recommend_cafe",
  {
    title: "Recommend a cafe",
    inputSchema: { type: "object" }
  },
  async (_args, { _meta }) => {
    const locale = _meta?.["openai/locale"] ?? "en";
    const location = _meta?.["openai/userLocation"]?.city;

    return {
      content: [{ type: "text", text: formatIntro(locale, location) }],
      structuredContent: await findNearbyCafes(location)
    };
  }
);