Industry Applications
real estate
How to Create an Automated Open House Follow-Up System
Follow up with open house visitors automatically after the event.
Jay Banlasan
The AI Systems Guy
Automating open house follow-up in real estate turns a stack of sign-in sheets into a pipeline. Most agents collect names at the door and never follow up, or they send one generic email three days later. This system sends personalized follow-ups within hours and keeps the conversation going automatically.
What You Need Before Starting
- Python 3.8+
- Anthropic API key
- A digital sign-in method (Google Form, tablet app, or CSV import)
- Email sending capability (SMTP)
Step 1: Set Up the Visitor Database
import sqlite3
from datetime import datetime
def init_open_house_db(db_path="open_house.db"):
conn = sqlite3.connect(db_path)
conn.execute("""
CREATE TABLE IF NOT EXISTS visitors (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
email TEXT,
phone TEXT,
property_address TEXT,
open_house_date TEXT,
buyer_type TEXT,
price_range TEXT,
working_with_agent TEXT DEFAULT 'unknown',
follow_up_stage INTEGER DEFAULT 0,
created_at TEXT
)
""")
conn.commit()
conn.close()
def import_sign_in_sheet(csv_file, property_address, open_house_date, db_path="open_house.db"):
import csv
conn = sqlite3.connect(db_path)
with open(csv_file) as f:
reader = csv.DictReader(f)
for row in reader:
conn.execute("""
INSERT INTO visitors (name, email, phone, property_address, open_house_date,
buyer_type, price_range, working_with_agent, created_at)
VALUES (?,?,?,?,?,?,?,?,?)
""", (row["name"], row["email"], row.get("phone", ""),
property_address, open_house_date, row.get("buyer_type", "unknown"),
row.get("price_range", ""), row.get("has_agent", "unknown"),
datetime.utcnow().isoformat()))
conn.commit()
conn.close()
Step 2: Define Follow-Up Sequences
FOLLOW_UP_STEPS = [
{"delay_hours": 2, "template": "same_day_thank_you"},
{"delay_hours": 48, "template": "property_feedback_request"},
{"delay_hours": 120, "template": "similar_properties"},
{"delay_hours": 240, "template": "market_update"},
]
Step 3: Generate Personalized Messages
import anthropic
from dotenv import load_dotenv
load_dotenv()
def generate_open_house_email(visitor, template_type):
client = anthropic.Anthropic()
templates = {
"same_day_thank_you": f"Write a same-day thank you email to {visitor['name']} who visited the open house at {visitor['property_address']}. Ask what they thought of the property and if they have questions. Keep it warm and brief, under 80 words.",
"property_feedback_request": f"Write a follow-up to {visitor['name']} asking for their honest feedback on {visitor['property_address']}. Ask if the price range of {visitor.get('price_range', 'their budget')} aligns with what they saw. Under 80 words.",
"similar_properties": f"Write an email to {visitor['name']} mentioning you have similar properties to {visitor['property_address']} that might interest them. Ask if they want to schedule private showings. Under 80 words.",
"market_update": f"Write a casual market update email to {visitor['name']} about the area around {visitor['property_address']}. Include a soft offer to help with their search. Under 80 words."
}
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=512,
system="You are a real estate agent writing personal follow-up emails. Sound human. No exclamation mark overuse. No ALL CAPS. Short and conversational.",
messages=[{"role": "user", "content": templates.get(template_type, templates["same_day_thank_you"])}]
)
return response.content[0].text
Step 4: Build the Processing Engine
from datetime import timedelta
import smtplib
from email.mime.text import MIMEText
def process_open_house_followups(db_path="open_house.db"):
conn = sqlite3.connect(db_path)
visitors = conn.execute("""
SELECT id, name, email, property_address, open_house_date, follow_up_stage, buyer_type, price_range
FROM visitors WHERE follow_up_stage < ?
""", (len(FOLLOW_UP_STEPS),)).fetchall()
for v in visitors:
vid, name, email, property_addr, oh_date, stage, buyer_type, price_range = v
step = FOLLOW_UP_STEPS[stage]
oh_dt = datetime.fromisoformat(oh_date)
send_after = oh_dt + timedelta(hours=step["delay_hours"])
if datetime.utcnow() >= send_after:
visitor_data = {
"name": name, "property_address": property_addr,
"buyer_type": buyer_type, "price_range": price_range
}
body = generate_open_house_email(visitor_data, step["template"])
msg = MIMEText(body)
msg["Subject"] = f"Following up from {property_addr}"
msg["From"] = "[email protected]"
msg["To"] = email
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login("[email protected]", "APP_PASSWORD")
server.send_message(msg)
conn.execute("UPDATE visitors SET follow_up_stage = ? WHERE id = ?", (stage + 1, vid))
print(f"Sent {step['template']} to {name}")
conn.commit()
conn.close()
Step 5: Schedule and Run
0 * * * * python3 /path/to/open_house_followup.py
if __name__ == "__main__":
init_open_house_db()
process_open_house_followups()
What to Build Next
Add a digital sign-in page that visitors fill out on a tablet at the open house. That eliminates the CSV import step and starts the follow-up sequence immediately.
Related Reading
- Automating Follow-Ups Without Being Annoying - follow-up timing and tone
- AI in Real Estate Operations - AI across real estate workflows
- AI for Email Marketing Automation - email automation patterns
Want this system built for your business?
Get a free assessment. We will map every system your business needs and show you the ROI.
Get Your Free Assessment