Skip to content

ChatGPT Apps submission: widget _meta.ui.domain not set on UI template ("Widget domain is not set for this template") #2

Description

@janbam

Summary

The ChatGPT Apps developer panel warns that DevSpace's UI template has no "widget domain" set:

Widget domain is not set for this template. A unique domain is required for app submission.

This is a real submission gate for the ChatGPT Apps Directory: OpenAI requires each app's UI template to declare a stable, unique sandbox origin via _meta.ui.domain. DevSpace currently omits this field, so the template is registered without it.

What "widget domain" is

When DevSpace registers its widget app as an MCP resource (ui://devspace/workspace-app.html), the MCP Apps schema allows _meta.ui with several fields. DevSpace sets only the CSP allowlists:

// src/server.ts — appCsp(config)
{
  csp: {
    resourceDomains: [publicBaseUrl],
    connectDomains: [publicBaseUrl],
  }
}

There is a sibling field, domain, that DevSpace never emits. Per the OpenAI Apps SDK reference:

Dedicated origin for hosted components (required for app submission; must be unique per app). Defaults to https://web-sandbox.oaiusercontent.com.

From the "Build your MCP server" guide:

ChatGPT renders the widget under <domain>.web-sandbox.oaiusercontent.com.

So domain is not the server's own public URL (e.g. the ngrok/tunnel origin). It is a stable, dedicated origin inside ChatGPT's host sandbox that ChatGPT assigns to the widget iframe. Without it, ChatGPT falls back to an ephemeral per-conversation sandbox origin.

Why OpenAI asks for it

A stable sandbox origin matters for (per SDK docs):

  1. OAuth callback redirect URIs (need a fixed origin on the allowlist)
  2. CORS policies on external APIs that check the Origin header
  3. API key restrictions by origin

For directory distribution, OpenAI wants every app pinned to a unique, stable origin so these things are predictable and reviewable. That is why the panel calls it "required for app submission" and "must be unique per app." In developer mode the widget still renders under the default ephemeral sandbox origin, so development use is unaffected — only submission is gated.

Relevant code

appCsp() in src/server.ts only returns CSP allowlists and never includes domain. The resource is registered at src/server.ts around the registerAppResource(server, "DevSpace Diff Card", WORKSPACE_APP_URI, ...) call, where _meta.ui.csp is set both at listing level and on the content item.

A fix would extend the _meta.ui block to include domain, e.g.:

_meta: {
  ui: {
    csp: appCsp(config),
    domain: "<unique-per-app-label>",
  },
}

The exact domain format is host-specific (OpenAI docs say the widget renders under <domain>.web-sandbox.oaiusercontent.com, with a default of web-sandbox.oaiusercontent.com). The value appears to be a short stable label that ChatGPT turns into a subdomain, but the precise accepted format needs verification against a working submitted app or the SDK's hosted-submission docs.

Scope and open questions (needs further investigation)

I do not fully understand this feature yet, so I am filing this for visibility rather than as a ready-to-merge fix. Things to clarify before changing anything:

  • What is this actually for in DevSpace's case? DevSpace's widget currently only loads its own bundled JS/CSS from the DevSpace server's public origin. Does it make any cross-origin calls or rely on OAuth/CORS that would benefit from a stable sandbox origin? If not, the field is purely a submission-compliance checkbox, not a runtime improvement.
  • Does DevSpace intend to support being an official registered ChatGPT App at all? I am running it in developer mode against chatgpt.com. I do not know whether the upstream maintainer registers/publishes DevSpace or keeps it developer-only. If it stays developer-only, this warning can be ignored; if it is meant to be submittable, the field is mandatory.
  • Resource/connect domains may also need to include the sandbox origin once domain is pinned, or the iframe app cannot load its own bundled assets. The OpenAI docs explicitly warn: declare all origins the app loads from, including the sandbox itself once pinned. This needs to be handled together with the domain addition.
  • Exact accepted format for _meta.ui.domain on ChatGPT specifically. The hosted-submission flow and any SDK examples should be checked; the docs mention web-sandbox.oaiusercontent.com as the default and <domain>.web-sandbox.oaiusercontent.com as the pattern, but whether a bare label or a full URL is expected is not fully spelled out.

Environment

  • DevSpace 1.0.3 (post-merge with upstream/main, includes feat/config: add codex tool mode)
  • Client: chatgpt.com (Developer Mode connector)
  • Public origin via ngrok tunnel (*.ngrok-free.app)
  • DEVSPACE_TOOL_MODE=codex, DEVSPACE_WIDGETS=full

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingquestionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions