Blog

How To Import TRREB PropTx Real Estate Listings Into Your WordPress Site

TLDR : Download the (Free) WordPress TRREB Listing Plugin Here!

Years ago, we hacked together a Python script that would download listing data from TREB’s RETS server (as a CSV) and feed it into a WordPress site. It worked for the most part. The learning curve for most people to integrate a scheduled job on their server to pull TREB data and import it into WordPress was the biggest barrier.

It pulled down a giant dump of property listings that we massaged into something usable for our clients’ real estate websites. You can still read that original blog post here: TREB IDX WordPress Integration , or check out the original GitHub repository for the python TREB import script.

But the TREB RETS CSV process? Its completely dead. Enter PropTx and the new API to access real estate listings in Toronto.

Who’s Behind PropTx?

PropTx isn’t just some random third-party vendor that somehow partnered with TRREB. It’s actually the MLS tech arm of TRREB itself. Officially called PropTx Innovations Inc., they’re the ones responsible for running the modernized backend stack for Ontario’s largest real estate board. That includes the Matrix/REALM™ platform, add-on services, and more relevant to this post the PropTx RESO Web API that now powers most modern listing integrations.

PropTx runs as its own Ontario corporation with its own leadership and board, but it’s fully aligned with TRREB’s strategic direction. In fact, in late 2025, TRREB shuffled the PropTx board and started a governance review, which is a good reminder that policy and roadmap changes tend to flow top-down from TRREB.

If you’re a developer or agency working with real estate data in Ontario, PropTx is who you’ll most likely deal with for API access, credentials, support, and rules of the road.

Welcome to the RESO Era (Thanks, PropTx)

TREB has officially migrated away from the aging RETS system, partnering with their own subsidiary company, PropTX , to roll out the RESO Web API. This is a modernized, OAuth 2.0-secured, standards-compliant system that’s supposed to make everything better. And in some ways, it does. But like most modernization efforts, it came with tradeoffs.

Gone are the days of flat CSV-style downloads. Now it’s about authenticated API calls, rate limits, JSON parsing, and keeping a persistent mapping of fields that don’t always behave the way you’d expect.

That’s why we built Shift8 TREB, a brand new WordPress plugin that works with the new RESO Web API and PropTX. It’s live in the WordPress plugin directory now.

Let’s break down the journey from a hacked together python script that processes CSV data, FTP downloads listing images to a modern and well-tested WordPress integrated (FREE) plugin and all the technical hurdles in between.

Challenge #1: Connecting WordPress to the RESO Web API (OAuth 2.0 and OData Headaches)

Getting listing data from the new RESO Web API wasn’t as simple as replacing a curl command.

We had to implement a full OAuth 2.0 flow with client credentials, bearer tokens, and proper refresh handling. PropTX doesn’t just hand you a static token. You need to hit a token endpoint, cache and refresh the token before expiry, and ensure all listing fetch requests use the correct headers. This alone required its own subsystem within the plugin.

Once authenticated, querying listings meant dealing with OData filtering syntax, which is powerful but verbose. A basic query ends up looking like:

$odataQuery = '$filter=PropertyType eq \'Residential\' and City eq \'Toronto\'&$top=100';

Then there’s pagination, rate limiting (hello 429s), and retry logic. We built the API handler to respect rate limit headers and automatically back off and retry failed requests. If we didn’t, we’d be locked out of the API for hours.

The plugin has a full settings page (Settings → Shift8 TREB) where users can:

  • Enter their RESO API Client ID / Secret
  • Configure how often to run the sync (via WP Cron)
  • Set a listing limit per run
  • Filter by city, listing status, or postal code

This settings panel essentially turns the plugin into a mini sync engine. You enter credentials once, choose your sync schedule, and let WordPress handle the rest.

Challenge #2: Inserting TRREB Listings into Standard WordPress Posts

Here’s the key design decision: we don’t use a custom post type. Listings are imported as regular WordPress posts.

This is the opposite of what most real estate plugins do. Typically they would create a custom listing post type, build custom templates, and force you to adopt their front-end display logic. We wanted the opposite. Compatibility with anything: Bricks Builder, Elementor, Gutenberg, Astra, whatever.

By sticking to the post type, we ensure:

  • You can use any standard post grid or builder block
  • SEO plugins, filters, and metadata just work
  • You don’t have to update your theme to support a “listing” type

Here’s how we handle the import:

$content = strtr(
    get_option('shift8_treb_template'),
    [
        '%ADDRESS%'       => $data['FullAddress'],
        '%LISTPRICE%'     => number_format($data['ListPrice'], 0, '.', ','),
        '%MLSNUMBER%'     => $data['MLSNumber'],
        '%BEDROOMS%'      => $data['Bedrooms'],
        '%BATHROOMS%'     => $data['Bathrooms'],
        '%DESCRIPTION%'   => wp_kses_post($data['PublicRemarks']),
        '%LISTING_IMAGES%' => implode(',', $data['PhotoUrls']),
    ]
);

$post_id = wp_insert_post([
    'post_title'   => "{$data['StreetAddress']} – {$data['ListPrice']}",
    'post_content' => $content,
    'post_status'  => 'publish',
    'post_type'    => 'post'
]);

You define the layout template in plugin settings with simple placeholders (like %BEDROOMS%, %ADDRESS%, etc). The plugin swaps in the live listing data and creates a new WordPress post.

Challenge #3: Handling Media Attachments and Setting Featured Images

Each listing can include dozens of images. In the old Python script, we used wget or requests to download photos and then manually uploaded them into WordPress via the Media Library API.

Now it’s native :

$image_id = media_sideload_image($photoUrl, $post_id, null, 'id');
set_post_thumbnail($post_id, $image_id);

We also store all other photo URLs as a serialized array in post meta so developers can build custom galleries or carousels however they want. For each image URL in the RESO feed, we:

  • Download the image to a temp location
  • Import it via media_handle_sideload()
  • Attach it to the newly created post
  • Optionally set the first image as the featured image

This required a fair bit of error handling: image URLs break, remote servers timeout, or WordPress fails to generate thumbnails. The plugin gracefully skips over broken images and logs any failed imports, instead of halting the entire job.

Challenge #4: Geocoordinate Detection with OpenStreetMap

A key feature we wanted to support was map integration whether that’s powering a LeafletJS-based map view, generating distance-based filters, or letting users view listings by area. That means every listing needs precise latitude and longitude coordinates.

The issue? Not every listing returned from the PropTX RESO API includes geolocation data. Some do, most don’t. Especially depending on the brokerage or listing type.

Instead of relying on Google’s expensive and quota-limited Geocoding API, we opted to integrate OpenStreetMap’s Nominatim API : a free, open-source geolocation service that provides structured geocoding results from normalized addresses.

The Process: Normalizing Addresses for OSM

Before we can geocode anything, we need a usable address string. That required normalizing the inconsistent and variably structured address fields we get from RESO. The API separates address elements like:

  • StreetNumber
  • StreetDirPrefix
  • StreetName
  • StreetSuffix
  • City
  • Province
  • PostalCode

These can come in multiple combinations, or sometimes be partially empty.

To produce a consistent input for OpenStreetMap, we stitched these together manually:

$address = trim("{$data['StreetNumber']} {$data['StreetDirPrefix']} {$data['StreetName']} {$data['StreetSuffix']}, {$data['City']}, ON {$data['PostalCode']}");

Once we have a well-formed full address, we query the OpenStreetMap Nominatim API:

$response = wp_remote_get("https://nominatim.openstreetmap.org/search", [
    'body' => [
        'q'     => $address,
        'format'=> 'json',
        'limit' => 1
    ],
    'headers' => [
        'User-Agent' => 'Shift8-TREB-Plugin/1.0 (https://shift8web.ca)'
    ]
]);

Why We Chose This Route

  • Free and open: No API keys, no monthly fees, no legal grey area.
  • Lightweight: Since we cache results and only query once per new listing, usage is minimal.
  • Privacy-respecting: OSM isn’t tracking user behavior across domains.
  • Fallback-safe: If a listing already includes lat/lng, we skip the lookup. If OSM fails, the plugin doesn’t break, it just skips coordinates for that listing.

This system keeps listing maps accurate and functional without incurring extra costs, and avoids creating yet another API dependency that might break in the future.

Final Challenge: Handling Duplicate Listings & Updates

When you’re syncing 1,000+ listings, you have to handle the case where the listing already exists.

We use the MLS Number as a unique key:

$existing = get_posts([
    'post_type'  => 'post',
    'meta_key'   => 'mls_number',
    'meta_value' => $data['MLSNumber'],
    'numberposts' => 1
]);

If the listing exists, we update the post. If not, we insert a new one.

This avoids duplicate entries, and allows brokers to keep their sites fresh with minimal overhead. The logic also handles listings that have been removed (optional: you can enable deletion of expired/removed listings).

This Plugin Exists Because It Had To

We built this plugin simply because the old flow stopped working. PropTX’s RESO Web API completely breaks the old RETS integration flow.

And to be fair: that’s a good thing. The RESO spec is modern and standardized. It takes work to get it right.

That’s why we open-sourced it! You can view the full code here. Hopefully this plugin will make it easier for anyone running a WordPress site to integrate real estate listings from TRREB. If you like the plugin, please rate it on the WordPress plugin directory!