Skip to content

[Bug]: local-cloak navigate hard-codes waitUntil 'load'; Page.goto never forwards waitUntil, so never-idle sites (zillow.com) always time out #106

Description

@ngaurav

Summary

Adapters cannot opt out of waiting for the browser load event during navigation. The local-cloak runtime hard-codes waitUntil: 'load' in its navigate action, and Page.goto() never forwards its waitUntil option to the daemon — it only uses it to skip the client-side settle/stealth exec. On sites that stream analytics requests indefinitely (e.g. zillow.com), the load event never fires and every page.goto() in the adapter times out after 30s, even though the document rendered long before.

Reproduction

webcmd zillow rentals "San Francisco, CA" --max-rent 5000 --min-beds 2 --pets --parking

Fails with:

ok: false
error:
  code: UNKNOWN
  message: "page.goto: Timeout 30000ms exceeded.
    - navigating to \"https://www.zillow.com/homes/for_rent/San-Francisco,-CA_rb/\", waiting until \"load\""

The retained trace (traceId 20260716091350-631878c5) shows ~200 network events completed and the final screenshot contains fully rendered search results — the page was usable; only the load event stalled (a TikTok analytics pixel and similar requests keep the network busy indefinitely).

Passing { waitUntil: 'none' } from the adapter has no effect on the navigation itself, confirming the option is not forwarded.

Root cause

  1. src/browser/runtime/local-cloak/actions.ts:84 — the navigate action hard-codes the Playwright wait condition:
    await lease.page.goto(command.url, { waitUntil: 'load' });
  2. src/browser/page.ts:106Page.goto() sends only url (plus command opts) in the navigate command; options.waitUntil is consulted afterwards only to decide whether to run the settle/stealth exec, so the daemon-side wait condition is unreachable from adapters.

Expected behavior

page.goto(url, { waitUntil: 'none' }) (or a domcontentloaded-style option) should propagate through the navigate command so the runtime uses a matching Playwright wait condition. Adapters that gate readiness on their own selector waits should not be held hostage by third-party analytics stalling load.

Actual behavior

Navigation always waits for load with a 30s timeout regardless of adapter options; sites with never-idle network fail even though the DOM is ready.

Workaround (verified)

In the adapter, wrap page.goto() in a try/catch that swallows only the navigation-timeout error and rely on a subsequent selector wait (e.g. script#__NEXT_DATA__) as the real readiness gate. This restored zillow/rentals end-to-end, but it burns the full 30s timeout per navigation (two navigations exceed the default 60s command budget, requiring WEBCMD_BROWSER_COMMAND_TIMEOUT to be raised).

Environment

  • webcmd: 0.3.2 (npm global install)
  • Node: v22.23.1
  • OS: macOS 15.7.7 (Darwin 24.6.0)
  • Runtime: local-cloak

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions