Install
openclaw skills install @chrischall/homes-fpxQuery homes.com (US real-estate portal) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the homes-mcp server — search listings, resolve street addresses, fetch property detail/photos/ history, and read the signed-in user's saved homes, all through a one-shot call over their own signed-in browser tab. Use when you want homes.com data without the MCP, in a script, or on a machine where the MCP isn't installed.
openclaw skills install @chrischall/homes-fpxhomes.com is a fully server-rendered site with no public JSON API
and gates traffic through AWS WAF at the session level — every
request, not just login, needs to ride a real browser session. fpx
routes each call through the user's own signed-in www.homes.com tab
(the Transporter extension), which has already cleared the WAF
challenge, so the same fetch a Node process gets 403'd on succeeds.
This is "Pattern A" (every call rides the bridge) — there's no bootstrap-once/direct-fetch shortcut like some sibling portals get.
Almost every page is HTML with one embedded Schema.org
<script type="application/ld+json"> block carrying the structured
data (search results, property detail). One endpoint — the address
typeahead — is a real JSON API. Everything else this skill covers is
DOM scraping over specific, verified sections of the same pages the
homes_* MCP tools parse.
npm install -g @fetchproxy/cli # provides `fpx`
fpx profile add homes --domain homes.com
fpx pair -p homes # prints a pair code → approve in Transporter
Requirements: the Transporter browser extension installed, with an
open www.homes.com tab (signed in — required for the saved-homes/
saved-searches tools below, and helps every other page render the way
the extractors expect), and its Chrome Site access allowing
homes.com. Pairing persists after the first approval.
Always pass the full URL (fpx has no base-URL concept of its own):
fpx get 'https://www.homes.com/<path>' -p homes
Most responses are HTML — pull the JSON-LD block out with node, then
project with jq. homes.com HTML-entity-encodes the script tag's
type attribute (application/ld+json), so match loosely:
fpx get 'https://www.homes.com/atlanta-ga/' -p homes > /tmp/page.html
node -e '
const html = require("fs").readFileSync("/tmp/page.html", "utf8");
const m = html.match(/<script type="application\/ld(?:\+|+)json">([\s\S]*?)<\/script>/);
if (!m) { console.error("no JSON-LD found"); process.exit(1); }
process.stdout.write(m[1]);
' > /tmp/jsonld.json
jq '.["@graph"][] | select(.["@type"] == "CollectionPage")' /tmp/jsonld.json
The one non-HTML endpoint (address typeahead) is a real JSON POST — no
extraction step, pipe straight to jq:
fpx post-json 'https://www.homes.com/routes/res/consumer/smartsearch/autocomplete/' \
@/tmp/body.json -p homes | jq '.suggestions.places'
Ready-to-run request/extraction recipes for every endpoint — search,
property detail, photos, history/tax, nearby, market report, saved
homes/searches, and the typeahead — are in
references/homes-requests.md.
If you only have a free-text address (not a /property/<slug>/<hash>/
URL), resolve it first — same three-rung order homes_get_by_address
uses:
POST /routes/res/consumer/smartsearch/autocomplete/)
— the primary rung; returns the real detail URL directly.GET /<address-city-state-zip-slug>/) — homes.com often
routes an unambiguous address straight to the detail page.GET /<city-slug>/, fuzzy-match the street) —
only when 1 and 2 miss.See references/homes-requests.md for the exact body/path shapes and a
jq street-match recipe. Verify whatever candidate you pick against the
address you asked for — homes.com will happily return the "closest"
result, not a confirmed match.
homes_get_saved_homes / homes_get_saved_searches need a signed-in
tab. A missing session shows up as either:
/sign-in, orawswaf.com
and challenge.js, and is under ~80 KB).If you see either, open www.homes.com in the browser tab fpx is
paired to, sign in / clear the challenge, and retry.
0 — success (still check the body — an empty JSON-LD match or a
sign-in redirect can ride a 200).2 — bridge unavailable: extension not connected or pairing pending
→ fpx pair -p homes, confirm a www.homes.com tab is open.3 — bot wall: the tab hasn't cleared the AWS WAF challenge → open/
refresh a www.homes.com tab and retry.4 — upstream non-2xx from homes.com.fpx health -p homes shows bridge connection state when a call fails.