The same community search that powers sortresidential.com — one line of HTML on a website, one URL in a mobile app. Free, and built for the organizations already helping people find a place to live.
Takes a minute. We email you a code — no password — and hand you snippets with your key already in them.
If your organization helps someone reach the point of needing an apartment, this closes the last gap — without sending them off your product to do it.
A participant ready for a place of their own browses real listings inside the app they already trust, instead of being handed a link and a hope.
Show housing near a new job site or campus, filtered to the right city and price band before the first conversation.
Off-campus and new-hire housing pages that stay current on their own, because the listings come from the properties themselves.
Point members at vetted communities from your own site, with any resulting inquiry going straight to that property's leasing team.
Sign in to see the snippets, the options table and the mobile guides. We'll send a code — no password to remember.
Use whichever we already have for you — a partner account is matched on either. Your key and your leads live on your partner dashboard.
Two lines. Paste them where you want the search to appear. (Building a mobile app? Skip to the app instructions.)
<!-- Sort apartment search --> <div data-sort-embed data-key="emb_your_key_here"></div> <script src="https://sortresidential.com/embed/sort-embed.js" async></script>
That's the whole integration. The widget loads the live community list, sizes itself to fit your page, and routes every inquiry to the property's leasing team.
<div data-sort-embed data-key="emb_your_key_here" data-city="Atlanta" data-state="GA" data-maxrent="1500" data-filters="0" data-accent="#0F766E"></div> <script src="https://sortresidential.com/embed/sort-embed.js" async></script>
If your CMS won't allow a script tag, use a plain iframe. You lose only the automatic height — set one that suits your layout.
<iframe src="https://sortresidential.com/embed/find-property/?key=emb_your_key_here&city=Atlanta" width="100%" height="900" style="border:0" title="Apartment search by Sort Residential"></iframe>
Every option is a data- attribute on the container — and the same name as a query parameter if you're using the plain iframe or a mobile WebView (?key=emb_your_key_here&city=Atlanta). All are optional.
| Attribute | Values | What it does |
|---|---|---|
| data-key | emb_… | Your issued embed key — credits every lead and widget load to your organization. Get yours. |
| data-city | city name | Restricts the widget to one city. Visitors can't filter out of it. |
| data-state | 2-letter code | Restricts to one state, e.g. GA. |
| data-beds | studio, 0–4 | Starting bedroom filter. 4 means 4 or more. |
| data-maxrent | number | Hides communities whose starting rent is above this. Communities that don't publish a price still show. |
| data-pets | 1 | Pet-friendly communities only. |
| data-limit | number | Caps how many communities render — good for a sidebar or a teaser block. |
| data-layout | grid, list | grid is the default. list forces one card per row for narrow columns. |
| data-filters | 0 | Hides the search and filter controls, leaving a fixed list. |
| data-contact | 0 | Hides the contact form. Visitors are sent to the full listing on Sort instead. |
| data-accent | #RRGGBB | Recolors buttons and links to match your brand. |
| data-height | pixels | Starting height before the widget reports its own. Only matters for the first paint. |
The widget is a web page, so any native app can host it in a WebView — no SDK to add, nothing to ship an update for when listings change. Point the WebView at the same URL with your partner slug on it.
https://sortresidential.com/embed/find-property/?key=emb_your_key_here
In an app the widget skips the resize handshake and simply scrolls, the way any other screen does. Register the bridge below and it will also hand you events your app can act on.
import { WebView } from 'react-native-webview'; import { Linking } from 'react-native'; <WebView source={{ uri: 'https://sortresidential.com/embed/find-property/?key=emb_your_key_here' }} onMessage={(e) => { const msg = JSON.parse(e.nativeEvent.data); // the visitor tapped through to a full listing if (msg.type === 'sort-embed:open') Linking.openURL(msg.url); }} />
final controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..addJavaScriptChannel('SortEmbedFlutter', onMessageReceived: (m) { final msg = jsonDecode(m.message); if (msg['type'] == 'sort-embed:open') launchUrl(Uri.parse(msg['url'])); }) ..loadRequest(Uri.parse( 'https://sortresidential.com/embed/find-property/?key=emb_your_key_here'));
// the handler must be named "sortEmbed" let config = WKWebViewConfiguration() config.userContentController.add(self, name: "sortEmbed") let webView = WKWebView(frame: view.bounds, configuration: config) webView.load(URLRequest(url: URL( string: "https://sortresidential.com/embed/find-property/?key=emb_your_key_here")!)) // MARK: WKScriptMessageHandler func userContentController(_ c: WKUserContentController, didReceive message: WKScriptMessage) { guard let body = message.body as? [String: Any], body["type"] as? String == "sort-embed:open", let url = (body["url"] as? String).flatMap(URL.init) else { return } UIApplication.shared.open(url) }
webView.settings.javaScriptEnabled = true // the interface must be named "SortEmbedAndroid" webView.addJavascriptInterface(object { @JavascriptInterface fun postMessage(raw: String) { val msg = JSONObject(raw) if (msg.getString("type") == "sort-embed:open") { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(msg.getString("url")))) } } }, "SortEmbedAndroid") webView.loadUrl("https://sortresidential.com/embed/find-property/?key=emb_your_key_here")
Every bridge — web, React Native, Flutter, iOS, Android — receives the same four events. Ignore the ones you don't need.
| Event | Carries | When |
|---|---|---|
| sort-embed:open | url, property_id, property_slug | The visitor tapped through to a full listing. In an app, open it yourself — a WebView won't. |
| sort-embed:lead | property_id, property_slug, property_name | An inquiry was sent to that property's leasing team. |
| sort-embed:height | height | Web only. The widget's content height changed; the loader resizes the frame for you. |
| sort-embed:scroll-into-view | — | Web only. A listing was opened or closed and the frame should be scrolled to. |
If your container mounts after page load — React, Vue, Angular, or anything that renders late — call the loader yourself.
// after the container is in the DOM window.SortEmbed.render('#housing', { key: 'emb_your_key_here', city: 'Atlanta', maxrent: 1500, }); // or re-scan the page for any new [data-sort-embed] containers window.SortEmbed.refresh();
The loader is idempotent — a container that already holds a widget is skipped, so refresh() is safe to call on every route change.
The widget collects a name, email, optional phone, and message — only when a visitor chooses to contact a property — plus anonymous usage counts so we can report your embed's activity back to you. It asks for no location, no camera, and no login, and it sets one anonymous identifier in its own storage, never in yours.
On the web it runs in a sandboxed iframe on Sort's origin: it cannot read your page, your cookies, or your users' data, and your page cannot be reached from inside it. In a mobile WebView it can only reach Sort's own listing service, and it talks to your app through the one-way event bridge — nothing more. Nothing a visitor enters is sold or shared beyond the property they contacted — see our privacy policy and security practices.
Check that the container has the bare data-sort-embed attribute and that the script URL is exact. If your site sets a Content Security Policy, it needs frame-src https://sortresidential.com and script-src https://sortresidential.com.
That means the height messages aren't arriving — usually the plain-iframe snippet, which has no loader to receive them. Switch to the script version, or set a taller fixed height.
A WebView won't follow a target="_blank" link on its own. Register the bridge for your platform above and open the URL from the sort-embed:open event — that's exactly what it's there for. Also confirm JavaScript is enabled on the WebView.
Your filters may be narrower than the current inventory — a data-city with no Sort communities in it yet, or a data-maxrent below local pricing. Remove them one at a time to confirm.
Still stuck? Email [email protected] with the page URL and we'll look at it.
Sign in, copy your snippet, done. Building something unusual? We're happy to help you scope it.
Get your embed key →