If your evenings look like twelve Zillow tabs, a Slack channel with links you swear you’ll revisit, and a spreadsheet called maybe-next-home.xlsx, this article is for you. I’m walking through exactly how I wired OpenClaw (v3.7.2 on Node 22.4) to monitor listings on Rightmove and Zillow, ping me on Telegram the minute something new matches my filters, run monthly-payment maths against live rates, pull neighbourhood crime stats, and shove viewing slots straight into Google Calendar. No sponsored plugins, no mystical AI — just the open-source bits shipping on GitHub right now.
Why automate house hunting with OpenClaw?
Before the recipes, a quick list of pain points automation actually fixes:
- Latency: Listing sites keep the good stuff at the top for 5–30 minutes. If you’re not first, you’re tenth.
- Repetition: Most buyers search identical filters multiple times a day. Agents do not discount your stress tax.
- Context switching: Mortgage calculators, school ratings, commute times live in different tabs. Copy-pasting guarantees errors.
- Scheduling: Calling agents while you’re at work is awkward. Automatically proposing viewings based on your calendar saves the back-and-forth.
OpenClaw ships with browser control, persistent memory, scheduled tasks and 800+ tool integrations through Composio. That’s enough to stitch the entire workflow together without writing a private SaaS from scratch.
Prerequisites and one-time setup
I’m assuming you already have Node 22+ and Git installed. Everything else is just npm.
# fresh directory for the agent
mkdir claw-estate && cd claw-estate
npm init -y
npm install openclaw@3.7.2 playwright@1.44.0 # Chromium driver
# optional: dotenv for local secrets
npm install dotenv
Run the OpenClaw gateway locally:
npx openclaw gateway --port 3000
You’ll see the browser UI at http://localhost:3000. That’s where we’ll paste YAML workflows in a minute. For production I push the same agent to ClawCloud so it runs even when my laptop sleeps:
# from the same directory
npx openclaw cloud deploy --name "home-hunt" --plan hobby
The --plan hobby tier is free and gives one agent, 256 MB memory, and scheduled tasks every five minutes — plenty for listing checks.
Scraping listings with Playwright actions
OpenClaw’s built-in browser control is a thin wrapper around Playwright. That means every selector and wait condition you see in Playwright docs works unchanged. Below is the action I use for Rightmove. Zillow is near-identical; just swap URLs and selectors.
# .claw/actions/rightmove-scrape.mjs
import { chromium } from 'playwright';
export default async function (ctx) {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
const url = `https://www.rightmove.co.uk/property-for-sale/find.html?locationIdentifier=REGION%5E93966&minBedrooms=3&maxPrice=600000`; // edit to taste
await page.goto(url, { waitUntil: 'domcontentloaded' });
const cards = await page.$$('[data-test="property-card"]');
const listings = [];
for (const card of cards) {
const title = await card.$eval('address', el => el.textContent.trim());
const price = await card.$eval('[data-test="property-card-price" ]', el => el.textContent.trim());
const href = await card.$eval('a.propertyCard-link', el => el.href);
listings.push({ title, price, href });
}
await browser.close();
return listings;
}
Save that file, then declare it in openclaw.yaml so the agent can call it:
actions:
rightmoveList: ./actions/rightmove-scrape.mjs
Repeat for Zillow. Community PR #482 shows a full selector map if you’re curious.
De-duplicating and alerting in real time
Scraping every five minutes will spam you unless you remember what you’ve already seen. OpenClaw’s memory store is a simple key–value blob that survives restarts. Perfect for checksum lists.
# .claw/flows/listing-alert.yaml
name: listingAlert
schedule: "*/5 * * * *" # every 5 minutes
steps:
- id: pull
uses: rightmoveList
- id: filterNew
run: |
const seen = memory.get('seenLinks') || [];
const fresh = pull.output.filter(l => !seen.includes(l.href));
memory.set('seenLinks', [...seen, ...fresh.map(f => f.href)].slice(-5000));
return fresh;
- id: notify
if: filterNew.output.length > 0
uses: composio/gmail.send
with:
to: "me@gmail.com"
subject: "🏠 New Rightmove matches ({filterNew.output.length})"
body: |
${filterNew.output.map(l => `${l.price} - ${l.title}\n${l.href}`).join('\n\n')}
Yes, the Unicode house in the subject survives most mail clients; feel free to drop it. Swap composio/gmail.send for telegram.sendMessage or slack.postMessage if that’s your channel. The key point: only unseen links trigger notifications.
Tossing the same logic at Zillow
My convention is seenLinks:zillow vs seenLinks:rightmove in memory to keep the keys separate. Otherwise the flow is identical.
Mortgage and affordability calculations
Numbers turn listings into decisions. The snippet below relies on npm install mortgage-js@2.1.0, a tiny library that handles compound interest correctly. I wired it as a custom action so I can reuse it across flows.
// .claw/actions/mortgage.mjs
import { monthlyPayment } from 'mortgage-js';
export default async function (ctx, { price, deposit = 0.1, years = 25, rate = 0.05 }) {
const principal = price * (1 - deposit);
const payment = monthlyPayment(principal, rate, years);
return { principal, payment: payment.toFixed(2) };
}
Now chain it after the scrape:
- id: enrich
uses: mortgage
with:
price: "{{ pull.output[0].price.replace(/[^0-9]/g, '') }}"
The RegEx strips commas and the pound sign. Feel free to over-engineer with Intl.NumberFormat.
Area research: schools, crime, commute
Listings don’t mention that the nearest primary school is “Requires Improvement”. For UK readers, Ofsted publishes JSON feeds; in the US, GreatSchools has an open API with rate limiting. Crime data is public for both regions. I bundled three quick actions:
schoolScore: fetches rating by postcode or ZIPcrimeStats: counts incidents within 1 mile radius last 12 monthscommuteTime: hits Google Maps Distance Matrix (yes, API key required)
The idea isn’t to replace your own judgement — it’s to decide in 30 seconds whether a listing is worth booking.
Auto-proposing viewing slots
Everyone hates calendar ping-pong. Since Composio wraps Google Calendar, the flow is one additional step once you’ve short-listed a property:
- id: nextFreeSlot
uses: composio/gcal.findNextFree
with:
durationMinutes: 30
windowStart: "2024-09-01T09:00:00"
windowEnd: "2024-09-07T19:00:00"
- id: hold
uses: composio/gcal.createEvent
with:
summary: "Viewing: {{ property.title }}"
start: "{{ nextFreeSlot.output.start }}"
end: "{{ nextFreeSlot.output.end }}"
You’ll end up with a tentative hold on your calendar that you can quote when you phone the agent. If they confirm, keep it; if not, delete — but you’ve saved two emails already.
Putting it all together: sample full workflow
Below is my current openclaw.yaml. Eight steps, runs every five minutes, and touches only free APIs.
# openclaw.yaml
version: "1"
actions:
rightmoveList: ./actions/rightmove-scrape.mjs
mortgage: ./actions/mortgage.mjs
schoolScore: ./actions/schools.mjs
crimeStats: ./actions/crime.mjs
commuteTime: ./actions/commute.mjs
flows:
- name: hunt
schedule: "*/5 * * * *"
steps:
- id: listings
uses: rightmoveList
- id: fresh
run: |
const seen = memory.get('links') || [];
const news = listings.output.filter(l => !seen.includes(l.href));
memory.set('links', [...seen, ...news.map(n => n.href)].slice(-10000));
return news;
- id: each
foreach: fresh.output
steps:
- id: loan
uses: mortgage
with:
price: "{{ item.price.replace(/[^0-9]/g, '') }}"
- id: school
uses: schoolScore
with:
postcode: "{{ item.title.split(',').pop().trim() }}"
- id: crime
uses: crimeStats
with:
postcode: "{{ item.title.split(',').pop().trim() }}"
- id: commute
uses: commuteTime
with:
origin: "SW1A 1AA" # office postcode
destination: "{{ postcode }}"
- id: grade
run: |
const ok = school.output.rating > 3 && crime.output.incidents < 50 && commute.output.minutes < 45;
return { ok };
- id: notify
if: grade.output.ok
uses: composio/telegram.sendMessage
with:
chat_id: "123456"
text: |
🏠 {{ item.price }} {{ item.title }}\n\n💰 £{{ loan.output.payment }} / month\n🎓 School: {{ school.output.rating }}/5\n🚨 Crime: {{ crime.output.incidents }} last year\n🚇 Commute: {{ commute.output.minutes }} min\n\n{{ item.href }}
Total runtime per cycle on ClawCloud hobby tier: ~4 seconds, 30 MB RSS. Plenty of headroom.
Operational considerations and caveats
- Rate limits: Zillow throws a 403 if you hit them more than ~100 times per hour per IP. Five-minute schedule is fine; one-minute will burn you.
- CAPTCHA: Both sites occasionally serve bot checks. Playwright’s stealth plugin works but violates TOS; use at your risk.
- Data freshness: Mortgage rates change daily. I pull the Bank of England CSV at 01:00 and update a
memoryvalue used by the mortgage action. - GDPR/PII: Crime and school APIs return aggregates, so no personal data is stored, but double-check local laws if you’re in a different region.
- Mobile push: Telegram is easy. If you’re on iMessage only, wrap
osa scriptunder a custom action; works, but fragile.
Next steps
The flow above got me from “I might have missed a house yesterday” to “I’m booking viewings before the listing has 100 views”. Clone the repo skeleton (github.com/psteiner/openclaw-realestate), tweak the selectors for your market, and deploy to ClawCloud so it keeps grinding while you sleep. Your future self — and possibly your estate agent — will thank you.