How We Run a Nationwide Real Estate Company Entirely Through Slack
No Salesforce. No Hubspot. No $150/seat CRM. Our entire operation — leads, deals, analytics, AI analysis — runs through Slack channels and Cloudflare Workers. Here's exactly how we built it.
Why Slack Instead of a CRM?
Everyone told me I needed Salesforce. Or Hubspot. Or Podio. Or some real estate-specific CRM that costs $97/month per user.
Here's what I actually needed:
- Get notified instantly when a lead comes in
- See all the context about that lead in one place
- Track the deal through stages
- Have my team collaborate on deals
- Not pay per-seat pricing that scales terribly
Slack does all of this. And with Cloudflare Workers handling the automation, it does it better than any CRM I've tried.
The realization: A CRM is just a database with a notification system. Slack IS a notification system. I just needed to add the database part.
The Channel Architecture
Every channel has a specific purpose. Nothing overlaps. Here's our exact structure:
What a Lead Notification Looks Like
When a lead comes in from any source — Google Ads, website form, Offer Check tool, door knocker verification — it hits our Cloudflare Worker, gets enriched with property data, and posts to Slack like this:
Name: Justin
Phone: (555) 777-1444
Email: info@proptechusa.ai
Timeline: 1-2 months
📍 Property: 8632 134th St W, Apple Valley, MN 55124
Their Offer: $200,000
FMV: $360,000
Percent: 56%
Grade: D (predatory)
🐝 Partnership Opportunity: +$138,400 extra
Source: door_knock | Condition: good | 1/24/2026, 3:43:01 PM
Everything I need to call this person is right there. Property address, what offer they're comparing, how much upside there is. No clicking into a CRM. No loading screens. Just information.
The Cloudflare Worker That Powers It
Every lead source posts to the same Worker endpoint. The Worker handles:
- Source identification — Which form/channel did this come from?
- Property enrichment — Pull Zillow/Redfin estimates via RentCast API
- Lead scoring — Timeline, motivation level, property condition
- Slack formatting — Build the rich message with all context
- D1 storage — Save to database for reporting
Here's the core routing logic:
export default {
async fetch(request, env) {
const data = await request.json();
// Enrich with property data
const propertyData = await fetchPropertyData(data.address, env);
// Calculate offer grade
const grade = calculateGrade(data.offer, propertyData.fmv);
// Build Slack message
const slackPayload = buildSlackMessage({
...data,
...propertyData,
grade,
upside: propertyData.fmv - data.offer
});
// Post to appropriate channel
const channel = data.source === 'offer_check'
? env.SLACK_OFFER_CHECKS
: env.SLACK_LEADS_NEW;
await postToSlack(channel, slackPayload, env);
// Store in D1
await env.DB.prepare(
`INSERT INTO leads (name, phone, address, offer, fmv, grade, source)
VALUES (?, ?, ?, ?, ?, ?, ?)`
).bind(data.name, data.phone, data.address, data.offer,
propertyData.fmv, grade, data.source).run();
return new Response(JSON.stringify({ success: true }));
}
};
Why Cloudflare Workers?
The Numbers:
- Response time: 8-15ms (vs 200-500ms for traditional servers)
- Cost: ~$5/month for 10M+ requests
- Uptime: 99.99% (Cloudflare's global network)
- Cold starts: 0ms (always warm)
A lead comes in, gets processed, and hits Slack before I finish reading the previous notification. That speed matters when you're competing for motivated sellers.
Lead Stages Without a CRM
Traditional CRMs make you click through menus to change a lead's status. We use Slack's emoji reactions:
- 👀 = Reviewing (someone's looking at it)
- 📞 = Called (attempted contact)
- ✅ = Qualified (moving to next stage)
- 📝 = Contract sent
- 💰 = Closed
- ❌ = Dead (add reason in thread)
A Worker watches for emoji changes and updates the database. Another Worker moves the message to the appropriate channel when status changes.
The key insight: Slack's threading keeps all communication about a deal in one place. Notes, objections, call recordings (via Slack audio), documents — everything lives in the thread.
Automated Market Intelligence
Every morning at 7am, a scheduled Worker pulls:
- Case-Shiller housing index changes
- Local MLS activity in our target ZIPs
- Interest rate movements
- Competitor activity (new "we buy houses" sites)
And posts a daily briefing to #market-intel:
Case-Shiller (Minneapolis): 328.44 (+0.3% MoM)
30yr Fixed: 6.89% (↓ 0.02%)
Active Listings (Target ZIPs): 847 (↑ 12 from yesterday)
🎯 Hot ZIP: 55124 — 8 new listings, avg DOM 12 days
⚠️ Watch: 55306 — Inventory up 15% this week
Data: FRED, Redfin, Zillow | Updated 7:00 AM CST
Reporting Without Dashboards
Every Monday, a Worker generates our weekly report and posts it:
Leads: 47 new (↑ 23% WoW)
Qualified: 12 (25.5% conversion)
Contracts: 3 sent
Closed: 1 ($23,400 profit)
By Source:
• Google Ads: 28 leads ($342 spend, $12.21 CPL)
• Offer Check: 11 leads ($0 spend)
• Direct: 8 leads
Pipeline Value: $127,000 potential profit
🎯 Best performing: Offer Check (38% qualification rate)
I don't log into a dashboard. I don't export CSVs. The information comes to me, formatted exactly how I want it, exactly when I need it.
The AI Layer
Here's where it gets interesting. Every lead that comes in also gets analyzed by Claude:
Motivation Score: 8/10
Reasoning: Seller is checking a competitor's offer = actively shopping. Timeline of 1-2 months suggests genuine intent, not just curiosity. Property condition "good" means likely not a distressed situation — seller has options and is being smart about them.
Recommended Approach:
Lead with transparency angle. They're already skeptical of the $200K offer (that's why they're checking it). Position partnership model as the "smart seller's choice." Emphasize the $138K additional value without pressuring timeline.
Objection Prep:
• "Why should I trust you?" → We gave you the Offer Check tool for free. We're not hiding anything.
• "I need to think about it" → Totally understand. Here's a comparison sheet to share with your family.
• "Can you match their timeline?" → We can close faster AND get you more money.
Analysis by Claude Sonnet 4 | Confidence: High
This posts in a thread under the original lead message. My team has talking points before they even pick up the phone.
What This Actually Cost to Build
Monthly Costs:
- Slack: $0 (free tier handles everything)
- Cloudflare Workers: $5/month
- D1 Database: $0 (included with Workers)
- RentCast API: $49/month
- Claude API: ~$30/month
- Total: ~$84/month
Compare that to Salesforce ($150/user/month) or even Podio ($24/user/month) and you see why we went this route.
The Downsides (Being Honest)
This setup isn't perfect:
- Search is limited — Slack's search isn't as powerful as a real CRM. We compensate with good channel organization and D1 queries.
- Onboarding takes longer — New team members need to learn the system. There's no "standard" way to do things.
- Mobile experience — Slack mobile is fine, but not as polished as dedicated CRM apps.
- Reporting requires code — Want a new report? Someone has to write a Worker.
For our size (small team, high volume, technical founder), the tradeoffs make sense. If we hit 50 employees, we'd probably need something more structured.
Should You Do This?
This approach works if:
- You're technical (or have access to technical help)
- Your team already lives in Slack
- You hate paying per-seat SaaS pricing
- You want complete control over your data and workflows
- Speed of information matters more than pretty dashboards
It doesn't work if:
- You need compliance/audit trails (though you could build this)
- Your team expects a traditional CRM interface
- You don't have anyone who can maintain the Workers
Want Us to Build This for You?
We build custom Slack-first operations systems. Your channels, your workflows, your automations.
Let's Talk →