[FEATURE] Browser pane: let users trust local-dev domains that resolve to 127.0.0.1 (e.g. *.lndo.site, *.ddev.site)

Status Open
Maintainer reply None cached
Activity 0 comments · opened Sep 30, 2026

Problem Statement

Many local dev stacks serve the app under a real public domain whose DNS points at 127.0.0.1: Lando's *.lndo.site, DDEV's *.ddev.site, *.lvh.me, or a company subdomain mapped in /etc/hosts. The app has to be reached on that name, because the server routes sites by hostname and the cookies, OAuth redirect URIs and TLS certificates are issued for it.

In the desktop app's Browser pane, such a page loads, but every request it makes to this machine is cancelled with net::ERR_BLOCKED_BY_CLIENT, including its own same-origin CSS and JS. ~/Library/Logs/Claude/main.log shows:

[PreviewContext] Blocked subresource to private-resolving host { resourceType: 'stylesheet' }
[PreviewContext] Blocked subresource to non-public host from non-preview initiator { resourceType: 'stylesheet' }

The second line is the page's request to a dev server on https://localhost:3000 (Vite).

The pane treats a page as local only when its hostname is localhost, *.localhost, 127.0.0.1, 0.0.0.0 or ::1. Since #86362, same-origin requests also work for names that can't exist in public DNS, such as *.test. A public name that resolves to loopback gets neither. Nothing the user can configure changes this: neither the Allowed sites list nor a .claude/launch.json attach entry has any effect (also reported in #91203). The page renders unstyled, so Claude can't inspect its DOM or styles in the pane.

Proposed Solution

An explicit, user-owned allowlist of domains to treat like localhost. For example, in ~/.claude/settings.json:

{
  "browser": {
    "trustedLocalDomains": ["*.lndo.site", "*.ddev.site"]
  }
}

A page on a listed domain would get what a page on localhost gets today. It could load subresources that resolve to this machine, including loopback dev servers it references, such as https://localhost:3000. Pages on unlisted domains keep today's protection, and the list is empty by default.

A repository's files shouldn't be able to widen this silently. A project-level form (for example, a field on a .claude/launch.json attach configuration) should take effect only after the user approves it once, the way project MCP servers are approved.

Alternative Solutions

  • Serving on localhost, *.localhost or *.test instead: not possible when the server routes by hostname, or when cookies, OAuth or TLS are tied to the real name.
  • A local proxy: doesn't help, because the pane resolves the hostname itself before it sends the request.
  • Using an external browser: loses the pane's inspection and annotation tools.

Priority

High - Significant impact on productivity

Feature Category

Configuration and settings

Use Case Example

  1. Lando serves the project at https://myproject.lndo.site, which resolves to 127.0.0.1 through public DNS, with Lando's CA trusted by macOS. A Vite dev server on https://localhost:3000 serves the dev CSS and JS.
  2. I ask Claude to check a component's styles in the Browser pane.
  3. Today, the page loads unstyled, and every stylesheet and script fails with net::ERR_BLOCKED_BY_CLIENT.
  4. With "*.lndo.site" in trustedLocalDomains, the page would render as it does in Chrome, and Claude could inspect it.

Environment: Claude desktop 2.16120.0, macOS 26.6 (arm64), Lando v3.26.7.

Related: #86362 (closed), #95139 (*.ddev.site, the same public-wildcard case), #96508, #91203. #90539 asked for a similar allowlist inside a bug report, which was automatically labeled duplicate; this is the standalone request.

View original on GitHub ↗