Read your Jobber Client Hub — the customer portal a service business (pest control, lawn care, HVAC, cleaning) uses to send you appointments, quotes and invoices — from a shell with the fpx CLI (@fetchproxy/cli), instead of running the jobber-mcp server. Use when you want your Jobber data without the MCP, in a script, or on a machine where the MCP isn't installed.
Data & analysis
angi-mcp
Try itRead angi.com (US home-services directory) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the angi-mcp server — find pros by trade and city, read a pro's profile, ratings breakdown and reviews, and list the trade/city taxonomy. Use when you want Angi data without the MCP, in a script, or on a machine where the MCP isn't installed.
What it does
Read angi.com (US home-services directory) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the angi-mcp server — find pros by trade and city, read a pro's profile, ratings breakdown and reviews, and list the trade/city taxonomy. Use when you want Angi data without the MCP, in a script, or on a machine where the MCP isn't installed.
The skill document
Angi via fpx (no MCP)
Angi fronts www.angi.com with Cloudflare. Every content page returns 403
to plain curl/Node — only robots.txt, the sitemaps and /auth/login get
through. fpx runs the fetch inside the user's own browser tab (the
Transporter extension), which has already cleared the challenge, so the same
URL succeeds. No Angi login is needed for the public data below — a normal open
tab is enough; only the optional Signed-in account data section needs a
signed-in tab.
Two surfaces, two tools — don't route everything through the bridge:
- Taxonomy (which trades and cities exist) → the XML sitemaps, reachable by
plain
curl. No bridge, no extension. - Data (pros, ratings, reviews) →
fpx getthrough the tab.
One-time setup
npm install -g @fetchproxy/cli # provides `fpx`
fpx profile add angi --domain angi.com # fetch capability only
fpx pair -p angi --subdomain www # approve the 6-digit code in Transporter
Requires the Transporter extension with an open www.angi.com tab and its
Chrome Site access allowing angi.com. Pairing persists across invocations.
Pair per host you intend to fetch, and keep a tab open on it. The bridge
relays through a tab on the request's own host, so a bare fpx pair -p angi
fails with no tab matching https://angi.com/ — the apex serves no page. Pass
--subdomain www, and if you also want the signed-in account data below, open
a my.angi.com tab and run fpx pair -p angi --subdomain my as well.
(Alternatively --via-tab names the relaying tab explicitly.)
No cookie, storage or header scope is declared — Angi's data is server-rendered and rides the tab's own session, so nothing needs to be read out of the browser. Keep it that way: widening scope later forces a fresh pairing.
The one rule: resolve the trade slug first
Angi URLs are /companylist/us///.htm. The trade is a
fixed slug (plumbing, roofing, air-duct-cleaning, …), not free text, and
a wrong slug 404s. Resolve from the sitemaps before fetching — plain curl:
# All ~312 trade slugs
curl -s https://www.angi.com/sitemap/statecat-sitemap.xml \
| grep -o '[^<]*' | sed 's/<[^>]*>//g' \
| sed -n 's#.*/companylist/us/[a-z][a-z]/\([^/]*\)\.htm#\1#p' | sort -u
# Every city that has pages for one trade (confirms a city/trade combo exists)
curl -s https://www.angi.com/sitemap/angi-geocat-plumbing.xml \
| grep -o '[^<]*' | sed 's/<[^>]*>//g' | grep '/us/nc/'
Core call
Fetch the page through the tab, pipe the HTML into the extractor:
fpx get 'https://www.angi.com/companylist/us/nc/charlotte/plumbing.htm' -p angi \
| node references/rsc.mjs legacyId --dedupe id \
| jq -r '.[] | "\(.businessInfo.businessName)\t\(.rating.averageOverallRating)★ (\(.rating.reviewCount))\t\(.profileUrl)"'
rsc.mjs exists because the data is not in the HTML and not jq-able.
Angi is Next.js App Router: records arrive as React Server Component flight
rows inside self.__next_f.push([1,"…"]) string literals, and nested values are
deduplicated behind "$" references. The extractor concatenates the
chunks, unescapes them, brace-matches the objects owning a key, and resolves
the references. See references/angi-pages.md for record shapes and recipes.
Always pass --dedupe id on search pages. Each provider is emitted twice
(sponsored slot + list row); raw counts are exactly double.
Signed-in account data (optional)
If the tab is signed in to Angi, the account app on my.angi.com is readable
through the same profile (angi.com covers the subdomain). It is a different
Next.js app — Pages Router, so its data is a plain __NEXT_DATA__ blob, and
rsc.mjs does not apply. Use jq directly:
# Identity + project counts
fpx get 'https://my.angi.com/myprojects' -p angi \
| sed -n 's/.*]*>\(.*\)<\/script.*/\1/p' \
| jq '.props.pageProps.initialState
| {user: .projectHomeUser.firstName,
open: (.openProjectList.projects | length),
closed: (.closedProjectList.projects | length)}'
# Reviews you've written (plain JSON, session-cookie auth)
fpx get 'https://my.angi.com/account/rating-review/reviews' -p angi | jq
Two limits, both verified:
- Record fields are unknown. The account these were captured from held zero projects and zero reviews, so only the empty envelopes were observed. Read field names off the data; don't assume them.
- The inbox is not readable.
my.angi.com/inboxruns on the Twilio Conversations SDK; its proxy endpoints reject the session cookie alone (401, XML bodyusername or accesskey could not be verified).fpxcannot speak that protocol — messages need the Twilio client, not a GET.
Signed-out requests are redirected to /auth/login rather than 401'd, so a
200 that contains a login page means the tab is signed out.
Gotchas
?page=Npaginates (10 unique pros per page, no overlap between pages).?zip=is inert — verified:?zip=90210on a Charlotte page returns the identical Charlotte pros. Location comes from the URL path only. Don't offer it as a filter.- JSON-LD (
SearchResultsPage,LocalBusiness) is present and is real JSON, but carries only names/addresses/one sample review — no ratings, no ids. Use it as a cross-check, not the source. - A non-HTML or challenge-page 2xx means the tab lost its Cloudflare clearance;
refresh a
www.angi.comtab rather than parsing the interstitial.
Exit codes (fetch verbs)
0success ·2bridge unavailable (extension disconnected, or pairing pending → re-runfpx pair -p angi --subdomain www, and confirm a tab is open on the host you are fetching) ·3bot wall (tab hasn't cleared Cloudflare → refresh it) ·4upstream non-2xx (usually a bad trade/city slug — re-resolve from the sitemap).
Notes
- Reads only — nothing here writes to Angi. Everything is public except the optional account section, which reads only the signed-in user's own data. Stay within angi.com's terms.
fpx health -p angishows bridge state when a call fails.- This project is developed and maintained by AI (Claude).
Related skills
Query thumbtack.com from a shell — search local service pros by trade and zip, and read pro profiles with ratings, reviews, credentials, business hours and pricing. Uses plain curl against Thumbtack's SSR pages and its anonymous GraphQL endpoint; no API key, no login, no browser extension. Use when you want Thumbtack data without an MCP server, in a script, or one-shot.
Read a Housecall Pro estimate or invoice your contractor sent you — line items, totals, tax, what is still owed, the company behind it — from a shell with plain curl, instead of running the housecallpro-mcp server. Use when you want the data without the MCP, in a script, or on a machine where the MCP isn't installed. Covers declining an option, and why approving cannot be scripted.
Connect to Ben McAdams's personal MCP server for his resume, portfolio, and blog notes.
Read MyAtriumHealth (Atrium Health's Epic MyChart patient portal) — test results, medications, allergies, immunizations, health issues, visits, goals — from a shell with the fpx CLI (@fetchproxy/cli), by relaying requests through your signed-in Chrome tab. Use when you want your MyChart data in a script or one-shot without running the myatriumhealth-mcp server.
Generate more revenue with high-quality leads. Give your AI agent direct access to Prospairrow — extract prospects, enrich with deep company insights, discov...