If you searched for how to set up OpenClaw for real estate agents and brokers, you probably want a working playbook, not another fluffy product pitch. I just wired OpenClaw 0.38.4 into a five-person brokerage last month. Below is everything that worked (and what blew up) so you can copy the repo, avoid the face-plants, and get listings flowing into your client chats by lunch.

Why real-estate teams are wiring OpenClaw into their stack

Most brokerages already juggle half a dozen point tools—MLS web portals, Redfin, Realtor.com, Gmail, Calendly, Mailchimp, maybe Slack or WhatsApp. Nothing talks to each other. OpenClaw glues them together with:

  • 800+ integrations via Composio (Gmail, Google Calendar, Notion, HubSpot, etc.)
  • First-class chat connectors—WhatsApp, Telegram, Slack, iMessage—so buyers get updates where they actually read them
  • Browser automation for sites with no API (e.g., MLS systems that still think it’s 2005)
  • Scheduled tasks and persistent memory—perfect for drip campaigns and CMA snapshots

Drawbacks? You need Node 22+ on a machine that can keep Chromium running headless. And if your MLS terms of service prohibit scraping, get explicit permission first. I’m not your lawyer.

Prerequisites: Node 22+, secure MLS credentials, ClawCloud or local box

Versions and tooling

  • Node.js 22.3 or newer (LTS works, just stay on 22+).
  • npm 10+ (ships with Node 22).
  • OpenClaw 0.38.4 (current at 2024-06-14).
  • Chrome/Chromium 124+ (bundled by Puppeteer if you let it).
  • Git for pulling templates.

Accounts and keys

  • MLS / IDX credentials with two-factor app passwords—store them in process.env or your CI secret manager, not in the repo.
  • A Twilio WhatsApp sandbox or a Slack bot token for messaging.
  • A ClawCloud account if you want zero-ops hosting. Free tier handles a small brokerage fine.

Installing and bootstrapping OpenClaw for real estate agents

1. Spin up the agent locally first

You’ll burn time if you deploy before you know the workflows work.

# macOS/Linux brew install node@22 # or use asdf/volta npm create openclaw@latest real-estate-bot cd real-estate-bot npm install

The scaffold gives you gateway (web UI) and daemon (background jobs). Start both:

# two terminals or tmux panes npm run gateway npm run daemon

Hit http://localhost:14500. Name your agent “RE-Bot” or whatever. The gateway writes config to claw.config.json.

2. Wire messaging channels

For WhatsApp:

# .env WHATSAPP_ACCOUNT_SID=ACxxx WHATSAPP_AUTH_TOKEN=yyy WHATSAPP_FROM="whatsapp:+14155238886" WHATSAPP_TO="whatsapp:+15551234567"

Slack is similar—just export SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET.

3. Commit, then push to ClawCloud

git remote add claw https://git.clawcloud.com/your-team/real-estate-bot.git git push claw main

In the ClawCloud dashboard: New Agent → Import Git Repo → Environment = Node 22 → Deploy. First build takes ~90 seconds; after that, webhooks auto-redeploy.

Automating listing monitoring across MLS and property portals

This is where OpenClaw’s browser engine—Puppeteer 20 under the hood—pays off. Most MLS systems (Bright, CRMLS, Matrix) have zero public API. We mimic a real user session, cache cookies in persistent storage, and poll on a cron.

Headless login flow

// src/tasks/mls-login.ts import { browser } from "openclaw/browser"; export async function mlsLogin(page) { await page.goto("https://bright.mlsmatrix.com", { waitUntil: "domcontentloaded" }); await page.type("#UserID", process.env.MLS_USER); await page.type("#Password", process.env.MLS_PASS); await page.click("button[type=submit]"); await page.waitForNavigation(); // multi-factor prompt? brighten this accordingly return page.cookies(); }

Cron job to fetch new listings

// src/crons/fetch-new-listings.ts import { schedule } from "openclaw/cron"; import { sendMessage } from "openclaw/messages"; import { mlsLogin } from "../tasks/mls-login"; schedule("*/15 * * * *", async () => { const page = await browser.newPage(); await page.setCookie(...await mlsLogin(page)); await page.goto("https://bright.mlsmatrix.com/Matrix/Search/Residential"); // Assume saved search ID 123456 emits JSON const data = await page.evaluate(() => fetch("/Matrix/Export/ExportResults.aspx?SavedSearchID=123456&Format=JSON").then(r => r.json())); const newOnes = filterSinceLastRun(data); for (const listing of newOnes) { await sendMessage("whatsapp", formatListing(listing)); } await page.close(); });

Persist lastRunTimestamp in OpenClaw’s built-in KV store (openclaw/store) so restarts don’t flood clients.

Scraping Realtor.com as a backup

Realtor’s HTML is heavy but predictable. document.querySelectorAll("li.component_property-card") gets you the goods. Same cron pattern applies. I keep it at hourly cadence to avoid getting my IP throttled.

Streamlining client communication from WhatsApp to email

Unified message router

Create one handler so a client can ask, “Can we see 123 Maple tomorrow?” on any channel and get the same response.

// src/routes/messages.ts import { router } from "openclaw/router"; import { scheduleShowing } from "../tasks/showings"; router.on("message", async (ctx) => { const { text, from } = ctx; if (/^see\s+\d+\s+.+/i.test(text)) { const date = parseDate(text); // use chrono-node await scheduleShowing(from, date, text); return ctx.reply(`Got it. Tentatively penciled for ${date}. I’ll confirm with the seller.`); } });

The router fires for Slack, WhatsApp, Telegram, Signal—wherever you enabled connectors. No more copy-pasting between apps at 10 PM.

Managing showing schedules and calendar sync

Brokerages live in calendars. Double-booking a showing is death to credibility. OpenClaw plus Composio gives first-class calendar integration in eight lines.

// src/tasks/showings.ts import { googleCalendar } from "composio/google"; export async function scheduleShowing(client, when, note) { const event = await googleCalendar.events.insert({ summary: `Showing: ${note}`, start: { dateTime: when.toISOString() }, end: { dateTime: new Date(when.getTime() + 30*60*1000).toISOString() }, attendees: [{ email: `${client}@example.com` }] }); return event.htmlLink; }

Set a cron to reconcile MLS showing approvals and update events with lockbox codes once confirmed.

Market analysis and CMA preparation with OpenClaw toolchain

Data ingestion

Pull historical sold data via the MLS’s export (CSV) and ingest to a local DuckDB. Why DuckDB? It’s embedded, ACID, and OpenClaw’s TypeScript client is trivial.

// src/db/duck.ts import Duck from "duckdb"; export const db = new Duck.Database("cma.db");

Generating the report

// src/tasks/generate-cma.ts import { db } from "../db/duck"; import { writeFileSync } from "fs"; import { execSync } from "child_process"; export async function generateCMA(address) { const comps = db.prepare("SELECT * FROM sales WHERE geo_distance(addr, ?) < 0.5 AND sold_date > date('now', '-6 months')").all(address); const markdown = `# CMA for ${address}\n\n| Address | Beds | Baths | SqFt | Price | DOM |\n|---|---|---|---|---|---|\n` + comps.map(row => `|${row.address}|${row.beds}|${row.baths}|${row.sqft}|$${row.price}|${row.days_on_market}|`).join("\n"); writeFileSync("/tmp/cma.md", markdown); execSync("pandoc /tmp/cma.md -o /tmp/cma.pdf"); return "/tmp/cma.pdf"; }

Auto-emailing the PDF

import { sendEmail } from "openclaw/email"; await sendEmail({ to: clientEmail, subject: `Your CMA for ${address}`, attachments: [{ path: await generateCMA(address) }] });

This shaves ~45 minutes off every listing appointment prep.

Lead nurturing workflows: drip campaigns and reminders

New leads drop in from Zillow Premier Agent API? Pipe them straight into OpenClaw and let the agent decide if it’s a hot buyer.

Webhook intake

// src/routes/zillow.ts router.post("/zillow/lead", async (ctx) => { const lead = ctx.request.body; await store.set(`lead:${lead.id}`, lead); await sendMessage("whatsapp", `New Zillow lead: ${lead.name} asking about ${lead.property_address}`); });

24-hour follow-up sequence

// src/crons/leads.ts schedule("0 * * * *", async () => { // hourly sweep const stale = await store.keys("lead:*", (k, v) => hoursSince(v.created_at) > 24 && !v.touched); for (const lead of stale) { await sendEmail({ to: lead.email, subject: "Still interested in seeing homes?", html: renderTemplate("follow-up", lead) }); lead.touched = true; await store.set(`lead:${lead.id}`, lead); } });

If WhatsApp is more your style, swap sendEmail for sendMessage("whatsapp", ...). Either way, the team never misses the critical day-one touch.

Hard lessons, trade-offs, and next steps

  • MLS portals sometimes break XPaths when they push an update. Keep selectors in one file and add Sentry to alert when a scrape fails.
  • Chromium in headless mode still needs ~150 MB RAM per page. On ClawCloud’s free instance you get 512 MB; run one scrape at a time or pay for the 2 GB tier.
  • Composio’s Google Calendar connector throttles at 10 requests/second. Batch inserts to stay under quota when importing historical showings.
  • For brokerages with strict compliance, disable shell access in claw.config.json ({"allowShell": false}) so agents can’t rm -rf / by accident.
  • Always test automations with your own phone number/email first. Accidentally blasting 64 buyers at midnight is a quick path to angry sellers.

The playbook above covers 90 % of what a typical small-to-mid brokerage needs: real-time listing alerts, unified chat replies, calendar-solid showings, one-click CMA PDFs, and a drip that never sleeps. Fork the repo, swap in your MLS credentials, and push to ClawCloud. Your clients will think you hired an assistant—nobody has to know it’s 400 lines of TypeScript.