Skip to main content

Documentation

No results found.
Features Members

Real Estate (MLS / IDX)

MLS-driven property listings for agent and broker websites: connect one or more MLS data feeds and the site keeps a live, searchable copy of the inventory — no manual listing entry. The feature targets parity with dedicated IDX platforms (m...

MLS-driven property listings for agent and broker websites: connect one or more MLS data feeds and the site keeps a live, searchable copy of the inventory — no manual listing entry. The feature targets parity with dedicated IDX platforms (map search, saved searches and alerts, lead capture, home-valuation funnels) while staying inside the CMS: leads land in the built-in CRM, alert emails ride the Marketing mail transport, and listing rows drop into any page from the design library.

Rollout status: all seven phases are complete — Phase 1 (feeds, sync engine, dashboard), Phase 2 (public search + detail pages, listing map, leads, compliance/SEO), Phase 3 (visitor accounts: saved homes, saved searches + email alerts, registration gate, buyer questionnaire), Phase 4 (design-library rows, areas, home-valuation + communities landing pages), Phase 5 (the Realty theme), Phase 6 (gated property packets + CRM/Marketing polish), and Phase 7 (open houses + instant home estimates).

Enabling

Dashboard → Settings → Features → Real Estate (membership feature). Toggling ON runs the module migrations, materializes the editable /home-valuation and /communities landing pages from the active theme's feature-pages/real-estate/ sources (never overwriting existing edits), and injects their routes. A Real Estate sidebar group appears with Listings, Agents, Areas, Leads, Buyer Activity, MLS Feeds, and Settings (admins).

MLS feeds

Dashboard → Real Estate → MLS Feeds. A site can connect any number of feeds; each syncs independently and every listing remembers which feed it came from (for attribution and compliance).

Supported platforms:

Platform Notes
RESO Web API The industry-standard OData interface — works with Trestle (Cotality), Bridge Interactive, Spark, and any Data-Dictionary-compliant platform. Needs the platform's OData endpoint URL + bearer token.
MLS Grid RESO variant with MLS Grid's replication contract: MlgCanView=false records are deleted locally, an Originating System name scopes multi-MLS accounts, and pulls respect their ~2 req/s rate limit.
SimplyRETS Paid aggregator with a simple REST API (basic auth). The public demo credentials simplyrets / simplyrets pull their sample market — a quick way to see real-shaped data.
Demo Bundled sample market (~60 Austin-area listings: residential + commercial, sale + lease, active/pending/sold). Zero credentials, zero network. Use it to explore the feature or demo the CMS.

Each feed also carries: listing types (residential / commercial / both), an IDX compliance disclaimer (shown wherever that feed's listings render, from Phase 2), a show sold listings toggle, a sitemap toggle, and an active switch. Test Connection validates credentials before saving. Credentials are encrypted at rest and never sent back to the browser — blank credential fields on edit mean "keep the saved secret".

Syncing

Feeds replicate incrementally: each sync pulls only records changed since the last watermark (ModificationTimestamp), upserts them into the local re_listings table, and processes deletions. Sync runs are slice-bounded (~2,500 records per run) so a large initial backfill never blocks a single request — the cursor advances chunk-by-chunk and the next run resumes where the last stopped.

Current inventory first (sold-history window). By default a feed imports active/pending listings plus sold listings closed within the last 24 months — Settings → Real Estate → Sold listings history (months) — rather than crawling the entire sold archive oldest-first. This keeps a fresh feed's first sync focused on the inventory visitors actually search (and skips off-market statuses like expired/withdrawn/canceled the site never displays). Every sync also prunes sold listings whose close date has aged past the window, so the local copy stays a rolling comps set for market reports; hand-featured listings are never pruned. Set the window to 0 to import and keep the full sold archive instead (slower first sync). The scope is applied server-side in the feed's OData query using eq/or (never the OData 4.01 in operator, which many RESO 4.0 servers reject). MLS Grid feeds are exempt — their in-stream delete contract (MlgCanView=false) owns removals, so they always pull unscoped and are never pruned.

  • Automatic: a LazyCron task (real-estate:sync-feeds) runs every 15 minutes and queues a sync per active feed.
  • Manual: the Sync Now button on each feed, or php artisan real-estate:sync-feeds [--feed=ID].
  • Monitoring: each feed shows its status (Ready / Syncing / Error with the message) and last-synced time; the Sync Log menu lists recent runs with fetched/saved/removed counts.

Listing photos are hot-linked from the MLS CDN URLs the feed provides by default (no local storage cost). Settings → Real Estate → Cache listing photos locally switches to downloading each listing's leading photos to this server in the background — they then serve as resized WebP variants with a responsive srcset and explicit dimensions, so cards and detail pages load noticeably faster and never break when feed URLs expire. The download runs on a schedule (no queue worker required), so after you enable it the cache fills in gradually over the following minutes/hours rather than all at once. Photos cached per listing (default 1) bounds the per-listing footprint: search/area/similar cards, the detail-page hero, social previews, and alert emails only ever render the leading photos, while the click-to-open gallery hot-links the rest; set it to 0 to mirror every photo. Confirm your MLS/IDX agreement permits local photo caching before enabling.

What gets cached is scoped to what you prominently display, not the whole sold archive. Active and pending listings are always cached; sold listings are cached only while they are recently sold — within the Cache recently-sold photos (days) window (default 90). That covers your "Recently Sold" surfaces without mirroring years of closed inventory (on a typical feed the sold archive is several times the active count, so this keeps both the disk footprint and the amount of re-hosted MLS photography bounded). Set the window to 0 to cache active + pending only.

The cache is a strict mirror of that scope, never an archive. Incomplete sets retry on the next sync; a photo set that changes between syncs is re-downloaded automatically (filenames are derived from the source URL). Cached photos are deleted the moment their listing leaves the scope — when it's removed from the feed (in-stream, sold-history prune, off-market reconcile, or dashboard delete), or when a sold listing simply ages past the recently-sold window (a status change keeps the row, so this is caught by a reconcile pass that runs every sync and daily via real-estate:photos-gc, which also reclaims directories orphaned by an interrupted sync and logs the space recovered). Everything the feed sends is normalized to RESO Data Dictionary semantics — price, beds, baths, living area, address, coordinates, agent/office attribution — with the full raw payload retained per listing.

Cross-feed dedupe — sites pulling from overlapping feeds (say, two MLS boards syndicating the same brokerage) get automatic duplicate collapse: after every sync, listings sharing an MLS number + ZIP across different feeds fold into one canonical row (the earliest feed's copy), and the duplicates disappear from every search, row, and alert. A feed dropping its copy releases the mark automatically.

Listings browser

Dashboard → Real Estate → Listings: a read-only browser over the synced inventory with search (address, city, neighborhood, MLS #), feed/status/sale-lease filters, and configurable table columns. Listing data itself is feed-owned and can't be edited, but two per-listing curation flags survive every re-sync:

  • Featured — surfaces the listing in the Featured Listings design-library row. Listings are also featured automatically when their agent/office MLS IDs match the ones configured in Settings.
  • Hidden — removes the listing from all public surfaces without touching the feed data.

Property search (/properties)

The public search page pairs a live-filtering results list with a clustered map. Every filter is shareable — the full filter state syncs into the URL (/properties?city=Austin&beds=3&maxPrice=500000), so saved links and ad campaigns land on pre-filtered results.

  • Filter bar — keyword box with grouped autocomplete (cities and neighborhoods with listing counts, plus direct address / MLS # matches that jump straight to the listing), a For Sale / For Lease toggle, price / beds / baths dropdowns, and an All Filters drawer (property types from the actual inventory, square footage, year built, sort).
  • Map — Leaflet with keyless basemap tiles (no API key or per-view cost). Listings cluster into price-bubble pins; hovering a result card highlights its pin and opening a pin popup (photo, price, stats) highlights the card. An optional "Search as I move the map" toggle re-runs the search against the visible map bounds. On mobile the map swaps in as a full-height panel via a floating List/Map button.
  • Draw a search area — the map's Draw area button lets the visitor click out a polygon (double-click or the button finishes it); results filter to homes inside the shape, combined with every other active filter. Clear it with one click. No extra map dependency — the drawing tool is built into the existing renderer.
  • Results — server-rendered cards (photo, price, $/sqft for sale listings, beds/baths/sqft or commercial facts, address) with load-more paging, plus an "Open Sat 1–3 PM" badge on listings with an upcoming open house. Vocabulary adapts to the site's mode: commercial-focused sites lead with square footage, lot size, and property type instead of beds/baths.
  • Compare — every card has a compare toggle (up to 4 homes, remembered per device); a floating bar opens /properties/compare, a side-by-side spec table (price, beds/baths, sqft, $/sqft, type, year, lot, days on market, HOA, status) with photos and remove buttons.
  • Compliance footer — each active feed's IDX disclaimer plus the data-last-updated stamp render below the results.

Listing detail (/properties/{slug})

Stable, crawlable URLs (slugs never change once assigned). The page shows a photo gallery with lightbox, price (and $/sqft for sales), a mode-aware fact sheet, the full remarks, a single-marker location map with directions link, agent/office attribution with the feed's compliance disclaimer, share links, and up to four similar listings (same city/type, ±25% price).

  • Open house section — upcoming open houses (date, time range, remarks, and a "Join virtually" link when the feed provides one) render between the fact sheet and the location map, each also emitted as a schema.org Event in the page's JSON-LD.
  • Mortgage calculator — pure client-side payment estimator prefilled from the listing: price, configurable down %, rate, and term, property tax from the listing's tax record (or the Settings fallback rate), and HOA dues. Lease listings show the monthly rate instead.
  • Contact form — "Request information" lead form with the listing pre-referenced. Honeypot + rate-limited.
  • Visibility — hidden listings 404; sold listings 404 unless their feed's show sold toggle is on.

Open houses

Feeds that expose a RESO OpenHouse resource (RESO Web API and MLS Grid platforms; the Demo feed ships ~10 sample open houses with dates always in the coming days) replicate scheduled open houses alongside the listings. Every sync pulls the feed's upcoming snapshot, upserts it, and prunes cancelled or long-past records — no configuration needed.

Where they surface:

  • Search cards get an "Open Sat 1–3 PM" badge showing each listing's next open house.
  • Listing detail pages get the Open house section + Event JSON-LD described above.
  • The Upcoming Open Houses design-library row (below) lists the homes hosting one soonest-first on any page.

Leads

Every public capture point funnels through one pipeline: the lead is stored (Dashboard → Real Estate → Leads), a CRM contact is created or updated with a timeline interaction, and a notification email goes out via the Marketing mail transport — to the configured lead address(es), else to every admin-or-above user. When a lead comes through an agent-profile page, it routes to that agent's email instead. CRM or mail failures never break the visitor-facing flow.

  • Submitted from — each lead stores the visitor's IP and country at capture time (CDN geo header first, local geo-database fallback), shown as a From column on the Leads table and a "Submitted from" row in the lead detail modal — and carried onto the CRM contact's "Registered from" field — so obviously-offshore junk leads are easy to spot. Leads captured before this shipped have no IP on record.
  • Per-type automation source — contacts carry the typed source real-estate:{type} (real-estate:packet, real-estate:valuation, real-estate:contact_agent, real-estate:questionnaire), so a CRM "contact is captured" automation can target packet requesters differently from valuation sellers. Source-specific rules also re-fire when an existing contact submits a new lead (a valuation follow-up task fires even if the contact was first captured by a contact request); catch-all rules deliberately fire only once, at first capture.
  • Marketing opt-in — when Marketing is enabled, every lead form (contact agent, home valuation, property packet) shows an optional "Email me new listings and market updates" checkbox. Ticking it subscribes the lead (an explicit opt-in — it reverses a previous unsubscribe) and adds their CRM contact to a Real Estate Leads group, targetable directly as a campaign audience.

Buyer activity (who saved which homes)

A saved home is a per-property intent signal from an identified person — often a stronger buying signal than a submitted form, since the visitor picked a specific house. Two surfaces expose it:

  • Dashboard → Real Estate → Buyer Activity — every visitor who has saved at least one home, most recent activity first, with a saved-home count and a searchable name/email filter. Opening a buyer lists every home they saved and when, each linking to the listing. Header stats show total buyers, total saved homes, and saves in the last 7 days. This screen is the full history and is always available, regardless of the digest setting below.
  • Daily buyer activity digest — once a day, a roll-up of which buyers saved which homes is emailed to the lead notification recipients. It is deliberately a digest, not a per-save notification: buyers shortlist in bursts (four homes in ten minutes is typical), and a per-save email would be unusable. A quiet day sends nothing — a daily "no activity" message would train recipients to ignore the one that matters.

Only liked saves count. The same table stores hidden ("never show me this again"), which is real preference data but the opposite of a follow-up list, so it is filtered out of both surfaces.

Mechanics worth knowing:

  • The digest tracks a cursor (real_estate.buyer_activity_cursor) and only reports activity since the last successful send. On the very first run the cursor is seeded and nothing is mailed, so switching the feature on never dumps an install's entire save history into an inbox — the Buyer Activity screen is where that backlog lives.
  • The cursor advances only after a send succeeds, so a mail outage re-sends the same window on the next run instead of dropping it.
  • Recipients are the same list as lead notifications (RealEstateLeads::notificationEmails()): the configured address(es), else every admin-or-above user. Because the digest carries visitor email addresses and their browsing activity, keep that list tight.
  • Runs as the real-estate:buyer-activity-digest background task (daily, min_hour = 7), so it lands in the local morning rather than whenever the scheduler first happened to tick — the hour is read in the site timezone (Settings → Business Info). --since= re-runs a window ad hoc without moving the cursor (use it once after enabling to send a catch-up covering existing saves); --force ignores the off switch.

Instant home estimate (AVM)

The home-valuation form is lead-first by default: it captures the seller's address and contact details, and the agent follows up with a personal valuation. Settings → Real Estate → Instant Home Estimate optionally adds an automated valuation on top — the visitor sees "Estimated value: $X (range $L – $H)" plus a your agent will follow up with a precise valuation disclaimer the moment they submit, while the lead flows through the standard pipeline either way.

  • Providers — Off (the default — today's manual/CMA flow), Demo (deterministic sample values, no key — for exploring the flow), RentCast, and ATTOM Data (both real AVM APIs; each needs its own API key). The provider seam (AvmProvider contract) keeps adding others (HouseCanary etc.) a one-class job.
  • API key — write-only, like feed credentials: saved server-side, never echoed back to the browser; a blank field on save keeps the stored key.
  • The estimate rides the lead — stored on the lead's payload, it appears in the agent notification email and the CRM interaction automatically. A provider error or timeout (5s cap) silently falls back to the plain lead-first flow.

Property packets

Gated document downloads on listing pages — the classic "get the full property packet" lead magnet (disclosures, floor plans, HOA documents, buyer's guides).

  • Uploading — Dashboard → Real Estate → Listings → row menu → Property Packet. Documents upload to private storage (never the public media library) and are only reachable through tokenized download links. A site-wide toggle puts a document (e.g. a buyer's guide) in every listing's packet.
  • Gates — each document declares what unlocks it: the lead form, a member account, or either (the default). Member-gated documents show guests a sign-in link; lead-gated documents ask even members for the form (capturing per-listing intent and a phone number).
  • Visitor flow — the detail page's Property documents block hydrates per visitor (the page stays response-cached). Signed-in members click Get instant access; guests fill a mini lead form (name, email, optional phone — honeypot + rate-limited) that captures a packet lead through the standard pipeline, unlocks the links inline, and emails them a copy.
  • Grants — every unlock mints a tokenized grant. Links expire after the configured number of days and stop after the configured per-unlock download cap (Settings → Property Packets; 0 disables either limit). Expired or exhausted links return 410 Gone. A member's still-usable grant is reused instead of minting duplicates.
  • Privacy — when packet documents exist, the privacy-policy generator documents the packet flow (contact details stored, tokenized links emailed).

Visitor accounts

Real Estate plugs into the site-wide member account system (shared with Memberships and Ecommerce — one sign-in, one "My Account"). Enabling Real Estate alone is enough to activate member login/registration, and registration requires agreeing to the privacy policy.

  • Saved homes — a heart on every search card and detail page. Guests who tap it are sent to member login (and return to where they were). Saved homes live at /members/saved-homes, alongside a hidden-listings list ("never show me this again" — hides the listing from that member's searches only) with one-click unhide. Agents see the other side of this at Dashboard → Real Estate → Buyer Activity (and in the daily digest email) — see Buyer activity.
  • Saved searches + alerts — the Save search button on /properties stores the current filter set with a chosen frequency (instant / at most daily / at most weekly). A background task mails new matches — only listings the feed changed since the last alert, capped at 10 per email, sent from the configured alert sender (falls back to the Marketing sender). The subject follows the frequency ("Daily listing updates: Recommended for you"), and the body invites the member to reply with questions or to schedule a showing — replies route to the alert Reply-To Email setting (falling back to the alert From Email), so point one of them at an inbox your agents actually watch. Members manage frequency, pause/resume, and deletion at /members/saved-searches; alerts never include listings the member hid.
  • SMS alerts — when the Marketing SMS provider is configured, each saved search gets an SMS on/off toggle and the saved-searches page collects the member's mobile number. Opted-in searches also text a short "N new listings match — link" alongside the email, with the standard opt-out notice.
  • Member dashboard — the shared /members/dashboard gains a property-search card with saved-home and saved-search counts.

Agent profiles (/properties/agents)

Dashboard → Real Estate → Agents manages public agent profiles: name, title, photo (media library), bio, contact details, and the agent's MLS agent IDs. The public index lists active agents; each profile page shows the bio and contact info, the agent's active listings (matched by MLS agent ID against the synced inventory), and a contact form with lead routing — messages sent from an agent's profile email that agent directly instead of the site-wide lead address, while still landing in the shared Leads list and CRM pipeline.

Registration gate

Settings → Real Estate → Registration Prompt: after a configurable number of listing views, guests see a sign-up prompt — soft (dismissible for the session) or hard (sign-in/register are the only ways on). View counting is client-side (the pages stay response-cached), and signed-in members are never prompted.

Phone verification — with a Marketing SMS provider configured, the optional Offer phone verification on the gate toggle adds a "continue with your phone number" path: the visitor gets a texted 6-digit code, and a verified number unlocks browsing on that device while dropping a verified-phone gate lead into the CRM — a lower-friction alternative to full account creation that still captures a real contact.

Buyer questionnaire

Signed-in members with an incomplete buyer profile get a one-time questionnaire on listing pages: purchase timeline, financing status, whether they have an agent, and (optionally) their own home's address for valuation tracking. Answers store on the member's profile; a provided address also raises a questionnaire lead into the CRM pipeline. Dismissing snoozes it for the session.

Design library rows

A Real Estate category appears in the design library and the editor's row picker whenever the feature is enabled (hidden otherwise — both the category and each row carry the real_estate feature gate). All listing rows pull live from the synced inventory through the same query engine as /properties, so curation flags, hidden listings, and per-feed sold visibility apply everywhere:

  • Hero with Property Search — full-width photo hero with a live search bar: grouped autocomplete (cities and neighborhoods with counts, address/MLS matches that jump straight to the listing) submitting to /properties.
  • Hero with Quick Filters — photo hero with a filter bar (sale/lease, price range, beds, baths, property types from the actual inventory) that lands on a pre-filtered search.
  • Featured Listings — card grid of flagged listings (or your configured agent/office MLS IDs' inventory) with photo, price, address, and mode-aware stats.
  • Upcoming Open Houses — card grid of listings hosting an open house soon, soonest first, with a date/time chip on each photo. Hides listings with no upcoming open house.
  • Sold & Pending Listings — track-record grid of Pending/Closed inventory with status badges; feeds with show sold off are excluded automatically.
  • Home Valuation Lead — two-column seller lead magnet: benefits copy beside an address + contact form that captures a valuation lead (honeypot + rate-limited, hydrates as a lazy island on cached pages).
  • Cities Grid / Neighborhoods Grid — photo tiles for your curated Areas, each linking to a pre-filtered search with a live listing count. When more areas exist than the grid shows, a View all communities link to /communities appears under the tiles automatically (and hides again once everything fits).
  • Area Market Stats — stat-forward cards for your curated Areas (median list price, $/sqft, days on market, active inventory, and a signed price-trend chip), each linking to its full market report page.

Three data-source presets back the rows (and are available to any custom row through the editor's Data button): Listings (status / transaction / featured / city / neighborhood / type / beds / baths / price filters, tokens for price, address, stats, status badge, photo, URL, MLS #), Open Houses (the Listings preset narrowed to active listings with an upcoming open house, soonest first, plus open-house date/time/virtual-URL tokens), and Areas (kind filter, tokens for name, image, search URL, listing count — plus market-stat tokens: median list price, median $/sqft, median days on market, active count, signed price trend, and the market-report URL).

Areas

Dashboard → Real Estate → Areas: the curated list of cities and neighborhoods your cities-grid / neighborhoods-grid rows display. Each area has a kind (city or neighborhood), a name (matched against the feed's city/subdivision values), an optional image from the media library, and optional extra search filters (query-string form, e.g. minPrice=500000&beds=3) appended to its search link. Drag rows to reorder — the grids honor the manual order. Each row also shows when its market stats were last computed, with View market report (opens the public page in a new tab) and Refresh stats (recomputes on the spot) actions.

Auto-add from your feed (on by default). You don't have to build this list by hand. Whenever an MLS feed syncs, every city with 5 or more visible active listings is added as an enabled city area, and the busiest subdivisions (3 or more visible active listings, up to 24 neighborhood areas total, busiest first) are added as enabled neighborhood areas — so the grids and market reports light up with zero setup. Auto-add is:

  • Non-destructive & idempotent — it only ever creates areas that don't already exist (matched by name, case-insensitively). It never edits or deletes an existing area, so your image, order, extra filters, and the Shown toggle always survive a re-sync. Areas that later drop below the threshold are kept. The feed's "Out of Area" placeholder cities and no-subdivision placeholders ("None", "N/A", "Not In Subdivision", …) are skipped, and the neighborhood ceiling only limits what auto-add creates — you can always add more by hand.
  • Per-area on/off — the Shown column toggles any area's public visibility without deleting it. A hidden area disappears from the cities-grid / neighborhoods-grid rows, its market-report page (which 404s), and the sitemap, but stays in this list so you can flip it back on. This is the way to hide an auto-added area — deleting one only removes it until the next sync re-adds it (while auto-add is on).
  • Controllable — the Auto-add areas from your MLS feed switch at the top of the page turns the behavior off entirely (existing areas are untouched), and Import areas now runs the same import immediately without waiting for a sync (and works even with auto-add switched off). The master toggle is stored as the real_estate.auto_import_areas setting.

"Active" here means exactly what the area card counts — visible, non-duplicate, active-status listings — so a newly added area never shows an empty card.

Market reports

Every curated area gets a public market report at /market-report/{slug} — the neighborhood-guide-with-data parity piece. The slug is generated from the area name on create and never changes (a city and neighborhood sharing a name are disambiguated with a -2 suffix). Each report shows:

  • Stat tiles — median list price, median sold price (trailing 90 days), median $/sqft, median days on market, active inventory, and new listings this month, each with a month-over-month change arrow.
  • A 12-month median-sold-price trend — an inline-SVG bar chart (no JS), with a muted tick for months that have no closes; hidden entirely when fewer than two months have data.
  • Recent sales — up to six recently-closed homes in the area, respecting each feed's show sold setting.
  • A call to action — browse the area's listings, plus a link to the home-valuation page, and a compliance footer with the contributing feeds' disclaimers.

Stats are cached monthly snapshots in re_area_stats, computed by the AreaStats service. The active side (inventory, list prices, days on market) is a live snapshot of the current month; the sold side is derived from close_date, so up to 12 prior months of sold history — and the trend chart — are available the first time a report is viewed. A report computes on demand the first time it's viewed (and whenever its snapshot is older than 24 hours), so no setup is required; the real-estate:compute-area-stats command (run daily by the built-in scheduler) is only a warm-keeper. Sold-side aggregates and the recent-sales cards only draw from feeds with show sold enabled, exactly like the sold & pending row. Curated areas are the opt-in — there are no market-report settings.

Landing pages

Enabling the feature materializes two editable pages (sourced from the theme's feature-pages/real-estate/, never overwriting existing edits): /home-valuation (valuation lead form + sold & pending proof) and /communities (cities + neighborhoods grids). Both are ordinary CMS pages — edit, re-arrange, or delete rows in the page editor like any other page. The property search and detail pages stay module-owned and are not page-editable.

The Realty theme

Fresh installs can pick the Realty theme (resources/themes/real-estate/) and start with a complete MLS-driven site instead of assembling one. Its manifest declares required_features: ["real_estate"], so installing it enables the feature, runs its migrations, and materializes /home-valuation + /communities automatically. What it ships:

  • A listing-driven homepage — hero with live property search and autocomplete, featured listings, the home-valuation lead magnet, a cities grid, recently sold & pending proof, and a buy/sell call-to-action — every row pulled live from your feeds once they sync.
  • Core pages — about, contact, privacy policy, terms, and a styled 404, with realty-flavored starter copy.
  • Navigation seeded as Home / Search / Communities / Home Valuation / About / Contact.
  • Two variants: Luxe (Playfair Display + Lora, deep navy and champagne gold, a transparent header over the hero photo) and Modern (Geist + Inter, blue and teal, a classic solid header). Switching variants re-skins the site and never touches content.

SEO

  • Sitemap — the search page, every visible listing (respecting the global Listings in sitemap setting and each feed's sitemap toggle), and every shown area's market report (hidden areas are excluded); active listings also appear in llms.txt.
  • Detail pages emit canonical URLs, OpenGraph/Twitter cards with the lead photo, and RealEstateListing JSON-LD (address, geo, price, availability) — plus an Event entry per upcoming open house. When sitemap listings are disabled the pages emit noindex instead.
  • Market reports emit a canonical URL, a stat-carrying meta description ("Median list price $X · N active listings · M median days on market in {Area}."), OpenGraph tags, and Place + BreadcrumbList JSON-LD.
  • Privacy — an active Real Estate feature registers a property-inquiry signal with the privacy-policy generator, so the generated policy documents what inquiry forms collect.

Settings

Dashboard → Real Estate → Settings (admin):

  • Site focus — residential, commercial, or both; drives search-page vocabulary and default filters (commercial leads with square footage and property type instead of beds/baths).
  • Default search type — for sale vs. for lease.
  • Lead notification email — where every lead (contact requests, valuations, packet downloads) is sent; accepts multiple comma-separated addresses. Blank = every admin-or-above user is notified. Note this is a replacement for the admin fallback, not an addition: once any address is set, only those addresses are notified.
  • Send a daily buyer activity digest — on by default; emails the addresses above a daily summary of which buyers saved which homes. Turning it off does not affect the Buyer Activity dashboard screen.
  • Instant home estimate — the AVM provider behind the home-valuation form (Off / Demo / RentCast) and its write-only API key.
  • Featured listings — agent + office MLS IDs whose listings auto-feature.
  • Property packets — link expiry in days and downloads allowed per unlock (0 = unlimited / never expires).
  • Mortgage calculator defaults — rate, term, down payment %, and a fallback property-tax rate for the detail-page payment estimator.
  • Registration prompt — off / soft (dismissible) / hard gate after N listing views, for lead capture on the public search experience.

Storage

re_feeds (connections + sync state), re_listings (normalized listings, indexed for price/beds/baths/location/status queries), re_open_houses (replicated open-house schedule, keyed to listings by feed + listing key), re_feed_sync_runs (sync history), re_leads (captured leads with type, contact fields, listing + CRM references), re_saved_listings (member hearts + hides), re_saved_searches (criteria + alert frequency/cursor), re_member_profiles (buyer questionnaire answers), re_areas (curated cities/neighborhoods for the area grids, each with a stable market-report slug and an is_enabled visibility flag; cities auto-populate from the synced inventory), re_area_stats (cached monthly market-stat snapshots per area + transaction), re_documents (packet documents on the private disk, with per-document gates), re_document_grants (tokenized packet unlocks with expiry + download counts). Disabling the feature hides the UI and 404s the routes but preserves all data.