/library / template-vertical-real-estate
templateVertical (industry)

Real estate listings site (MLS feed + agent profiles + lead capture)

A real estate brokerage site. Listings synced from an MLS feed (RETS/RESO Web API), agent profiles, lead form per listing, saved searches via magic-link auth. Built for a small-team brokerage that wants to escape Zillow rent.

use whenIndependent brokerage or team that pays $1000+/mo to Zillow for leads and wants their own site that ranks for 'homes for sale in [city]' and routes leads to specific agents.

May 2, 20262,230 bytesreal-estatemlsbrokeragelistingsleads

[Brokerage Name] · Listings

A brokerage listings site. MLS feed in, individual listing pages out, agent contact form on every listing, saved searches via email.

Source of truth

The MLS is the source of truth for listings. A scheduled job pulls the RETS/RESO Web API feed every 15 minutes and writes to Postgres. Listing pages are statically regenerated from the DB. Agent profiles are CMS-managed (Sanity).

Tech stack

Next.js 15 (App Router) + React + Tailwind v4. Postgres (Vercel Postgres) for listings + saved-search subscribers. Sanity for agent profiles + brokerage content. Mapbox for the listing map. Cloudinary for listing photo optimization. Resend for the daily saved-search emails. Vercel cron for the MLS pull.

Deploy

  • Site: git push -> Vercel auto-deploys
  • MLS sync: Vercel cron hits /api/cron/mls-sync every 15 minutes
  • Saved search emails: daily cron hits /api/cron/saved-search-digest

File map

  • app/page.tsx home: featured listings, search bar, agent grid
  • app/listings/page.tsx search results with filters
  • app/listings/[mlsId]/page.tsx individual listing
  • app/agents/[slug]/page.tsx agent profile + their active listings
  • app/saved-search/page.tsx user manages their saved searches
  • app/api/cron/mls-sync/route.ts pull feed, upsert to Postgres
  • app/api/cron/saved-search-digest/route.ts daily email
  • app/api/lead/route.ts lead form: assigns to the listing's agent
  • lib/mls.ts RESO Web API client (auth, pagination, parsing)
  • lib/round-robin.ts lead routing when no agent attached

.env keys

  • DATABASE_URL
  • MLS_API_BASE_URL, MLS_API_USERNAME, MLS_API_PASSWORD (RESO Web API)
  • SANITY_PROJECT_ID, SANITY_DATASET, SANITY_TOKEN
  • CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY, CLOUDINARY_API_SECRET
  • RESEND_API_KEY, RESEND_FROM_EMAIL
  • MAPBOX_ACCESS_TOKEN
  • CRON_SECRET Vercel cron auth

Hard rules

  • MLS feed terms have rules. Listing photos can only be served from MLS-approved URLs (Cloudinary fetch + cache is usually fine; cold-stored copies are usually not). Read the feed agreement.
  • Hide "off market", "expired", "pending" or "sold" from the public site unless explicitly opted in.
  • Display the agent name AND brokerage name on every listing (MLS attribution rule).
  • Lead form notifies the listing agent within 30 seconds. Real estate leads decay FAST.
  • Saved searches send a daily digest, not realtime. Daily is the sweet spot for engagement.
  • Comply with IDX rules for your MLS. Each MLS has slightly different display requirements.

Recent significant changes

  • 2026-05-02: Scaffolded. Locked: RESO Web API over RETS (RESO is the modern path), Sanity for agent CMS (non-dev edits), saved searches over realtime alerts (better retention).

Next session: start here

  1. Get MLS credentials. Most MLSs require a brokerage license + signed agreement.
  2. Set up Postgres. Apply schema for listings, agents, saved_searches.
  3. Run the MLS sync once manually. Confirm 50-200 listings ingest cleanly.
  4. Build the listing detail page. Match an agent to it. Submit a real lead.
  5. Confirm the agent receives the lead email within 30 seconds.
  6. Set up Vercel cron, confirm it fires on schedule.

Get the next CLAUDE.md in your inbox.

One new template every week, plus occasional case studies.