Back to Blog

Real Estate SaaS MLS Integration & Property Data

Published: June 29, 2026
Real Estate SaaS MLS Integration & Property Data

Developers new to proptech all make the same assumption: that somewhere there's a single "property database" you connect to. There isn't. In North America alone there are roughly 500 independent MLS boards, each with its own schema, field names, and compliance rules — and a real-estate MLS integration is mostly the work of making that fragmentation look like one clean dataset to your users.

Here's the shape of a build that survives: pull from the RESO Web API (not legacy RETS), sync incrementally with delta queries, normalize every board into one internal schema, and serve images and map search from infrastructure built for it. Do that and you get a fast listing search without burning your API quota or tripping an IDX violation. Here are the eight rules that matter.

Real estate MLS integration turns hundreds of fragmented listing feeds into one clean dataset

Rule 1: RESO Web API Over Legacy RETS

Two protocols connect you to a board:

  • RETS — the old XML-over-HTTP standard. It makes you download massive dumps (often gigabytes) to sync, wasting storage and bandwidth.
  • RESO Web API — the modern, mandated standard built on OData and REST. You run granular JSON queries and pull only what you need.

The National Association of Realtors requires RESO Web API support, so build against it. Keep a RETS bridge in your back pocket only for the occasional board that hasn't fully migrated.

Rule 2: Query With OData Parameters

The RESO Web API uses OData's $filter, $select, and $top to slice data precisely — fetch active residential listings modified since yesterday, only the fields you need:

HTTP
1GET https://{mls-host}/odata/Property
2  ?$filter=ModificationTimestamp gt 2026-06-28T00:00:00Z and StandardStatus eq 'Active' and ListPrice gt 500000
3  &$select=ListingId,ListPrice,BedroomsTotal,BathroomsFull,PublicRemarks
4  &$top=100
5Authorization: Bearer {access_token}

Note gt, not > — OData spells its operators out (gt, lt, eq). Selecting only the fields you render keeps payloads small.

Rule 3: Normalize Every Board to One Schema

SqFt here, LivingArea there, BuildingAreaTotal somewhere else — same number, three names. Don't build a table per board. Map everything into one internal schema aligned to the RESO Data Dictionary with adapter modules:

TypeScript
1// src/mls/adapters/mls-normalizer.service.ts
2import { Injectable } from '@nestjs/common';
3
4@Injectable()
5export class MlsNormalizerService {
6  normalize(raw: Record<string, any>) {
7    return {
8      listingId: raw.ListingId ?? raw.ListingID ?? raw.id,
9      price: Number(raw.ListPrice ?? raw.Price ?? raw.CurrentPrice),
10      bedrooms: Number(raw.BedroomsTotal ?? raw.Beds ?? raw.Bedrooms),
11      squareFeet: Number(raw.LivingArea ?? raw.SqFt ?? raw.BuildingAreaTotal),
12    };
13  }
14}

Onboarding a new board becomes writing one adapter, not reworking your data layer.

Adapter modules map every board's field names into one normalized listing shape

Rule 4: Sync Incrementally With Delta Queries

This is the rule that keeps your API access alive. Never re-pull the whole dataset on a schedule — hundreds of thousands of listings daily will exhaust your quota and lock your workers. Track your last sync time and ask only for what changed:

TypeScript
1// runs on a worker, not in a request
2async function incrementalSync(lastSync: Date) {
3  const since = lastSync.toISOString();
4  const endpoint = `/odata/Property?$filter=ModificationTimestamp gt ${since}`;
5  const changed = await fetchFromMls(endpoint);
6  await db.propertyListings.upsertBatch(changed);
7}

Run it on your background job infrastructure, and treat the MLS like any flaky upstream — timeouts, retries, and backoff, the standard third-party API reliability patterns.

Rule 5: Proxy Images at the Edge, Don't Copy Them

A listing has dozens of high-res photos. Copy every one into your own bucket and your storage bill balloons; hotlink the raw MLS URLs and you get broken images when listings change. Instead, store only the source URL and pass it through an on-demand edge proxy (Cloudflare Images, Imgix) that scales and compresses on the fly. Cheap storage, fast delivery, no stale copies.

Rule 6: Build Map Search With PostGIS

Letting users draw a search area on a map is a geospatial query, not application math. Use PostGIS: store coordinates as GEOMETRY(Point, 4326), index with GiST, and answer polygon searches in milliseconds:

SQL
1SELECT listing_id, price, coordinates
2FROM property_listings
3WHERE ST_Contains(
4  ST_GeomFromText('POLYGON((-73.93 40.7, -73.91 40.7, -73.91 40.8, -73.93 40.8, -73.93 40.7))', 4326),
5  coordinates
6);

A GiST index organizes space into nested bounding boxes so the database skips everything outside the shape — the same "index, don't scan" lesson from any PostgreSQL performance work, applied to geometry.

PostGIS turns a drawn search area into a millisecond query instead of application-side math

Rule 7: Stay IDX-Compliant

Displaying listings publicly means honoring each board's IDX rules. The common ones:

  1. Branding — show the originating MLS logo and copyright disclaimer on listing displays.
  2. Attribution — credit the listing broker and agent, often at a required prominence.
  3. Refresh cadence — keep stored data fresh (many boards require at least every 12 hours) so nothing shown is stale.

The exact rules vary per board, so read every MLS agreement you sign — IDX non-compliance doesn't get you a warning email, it gets your feed cut.

Rule 8: MLS Integration Protocols Compared

Legacy RETSRESO Web APIAggregator (Bridge, Trestle)
ProtocolXML over HTTPREST + OData JSONUnified REST wrapper
IngestionFull dumpsIncremental deltasOne multi-board endpoint
MemoryHeavyLight, streamableLight (no raw storage)
SetupSlow, complex parsingMedium (OData)Fast
CostServer maintenanceFlat infraPer-query licensing

If a board only speaks RETS, a RESO-aligned aggregator like Bridge Interactive or CoreLogic Trestle can normalize it to clean REST so you don't write legacy parsing yourself — at the cost of per-query licensing.

Connect via RESO, sync the deltas, normalize to one schema, and let PostGIS and an image proxy do the heavy lifting. Get those right and an MLS integration stops being a fragmented data nightmare and becomes the fast, compliant search that makes a real-estate product feel effortless — while you quietly handle 500 boards' worth of inconsistency behind the scenes.

Frequently Asked Questions

RETS is the legacy protocol — XML over HTTP that makes you download bulky data dumps to sync. The RESO Web API is the modern standard, built on OData and REST, so you run granular JSON queries and pull only what changed. The National Association of Realtors mandates RESO Web API support, so build against it; only reach for a RETS bridge if a specific older board hasn't migrated yet.

Never pull the full dataset on a schedule — hundreds of thousands of listings will blow your API quota and lock up your workers. Use incremental delta sync: store the timestamp of your last successful run and query only records with a ModificationTimestamp greater than it (OData $filter), or use the API's delta tokens. You fetch the handful that changed instead of everything that exists.

Every board names fields differently — SqFt vs LivingArea vs BuildingAreaTotal. Don't build per-board tables. Map every feed into one internal schema aligned to the RESO Data Dictionary using adapter modules that normalize incoming variations on the way in. Your application then queries one consistent shape, and onboarding a new board is writing one adapter, not reworking your database.

Use PostGIS in PostgreSQL. Store coordinates as GEOMETRY(Point, 4326), add a GiST index, and answer 'properties inside this drawn polygon' with ST_Contains in milliseconds. Doing the geometry math in application code instead is orders of magnitude slower — spatial indexes organize space into bounding boxes so the database skips everything outside your shape.

IDX (Internet Data Exchange) rules are set by each MLS board for displaying listings publicly. Common requirements: show the originating MLS logo and copyright disclaimer, credit the listing broker and agent, and refresh stored data on a schedule (often at least every 12 hours) so listings aren't stale. The exact rules vary by board, so read the agreement for each MLS you connect — non-compliance can cost you the feed.

Portrait of Umar Farooq

About Umar Farooq

Umar Farooq is the founder and lead engineer of Codify SaaS. He builds B2B SaaS products and web applications on modern TypeScript stacks and enterprise Java, and writes code-first guides drawn from real production work — the schema decisions, the migrations that almost went wrong, and the performance fixes that actually moved the numbers. When he recommends an approach, he shows the code and explains the trade-offs.

Read full bio