Building an Autocomplete Search Feature with Repliers APIs
A comprehensive guide to implementing a unified search experience that combines MLS® listings with cities and neighborhoods using the Repliers API.
Overview
This recipe demonstrates how to build a powerful autocomplete search feature that allows users to search for both MLS® listings and locations simultaneously. The results are presented categorically, giving users a seamless search experience whether they're looking for a specific property address, MLS® number, or exploring different areas.
Example
Implementation Steps
Step 1: Search MLS® Listings
The first step involves searching through MLS® listings using the /listings
endpoint. This allows users to find properties by address components or MLS® numbers.
API Request
GET https://api.repliers.io/listings?search={user_input}&searchFields=address.streetNumber,address.streetName,mlsNumber,address.city&fields=address.*,mlsNumber,listPrice
Request Parameters Breakdown
Parameter | Description | Example |
---|---|---|
| The user's input from the search field | |
| Comma-separated list of fields to search within | |
| Fields to include in the response (for performance optimization) | |
Why These Search Fields?
address.streetNumber
- Allows finding properties by house numberaddress.streetName
- Enables searching by street namesmlsNumber
- Lets users search by listing ID/MLS® numberaddress.city
- Enables city-based property searches
Field Selection Best Practices
Only request the fields you need to display in your autocomplete results. This improves API performance significantly. Learn more about field optimization in our Fields Parameter Guide.
Example Response
{
"apiVersion": "1",
"page": 1,
"numPages": 3,
"pageSize": 100,
"count": 293,
"statistics": {
"listPrice": {
"min": 1,
"max": 14585000
}
},
"listings": [
{
"mlsNumber": "X12151945",
"listPrice": "1250000.00",
"address": {
"area": "Peterborough",
"city": "Trent Lakes",
"country": "Canada",
"district": null,
"majorIntersection": "Hwy 36 & Bessie Ave",
"neighborhood": "Trent Lakes",
"streetDirection": null,
"streetName": "Fire Route 123",
"streetNumber": "13",
"streetSuffix": "N/A",
"unitNumber": null,
"zip": "K0M 1A0",
"state": "Ontario",
"communityCode": null,
"streetDirectionPrefix": null
}
},
{
"mlsNumber": "X12196167",
"listPrice": "1895000.00",
"address": {
"area": "Grey County",
"city": "Grey Highlands",
"country": "Canada",
"district": null,
"majorIntersection": "Lakeview Rd off of Rd 63",
"neighborhood": "Grey Highlands",
"streetDirection": null,
"streetName": "Lakeview",
"streetNumber": "123",
"streetSuffix": "Rd",
"unitNumber": null,
"zip": "N0C 1M0",
"state": "Ontario",
"communityCode": null,
"streetDirectionPrefix": null
}
}
]
}
Note: Results are returned in order of relevance based on our proprietary algorithm, refined over years of optimization.
Step 2: Search Locations (Asynchronous)
Simultaneously search for matching locations using the /locations/autocomplete
endpoint. This provides cities, neighborhoods, and areas from MLS® data.
API Request
GET https://api.repliers.io/locations/autocomplete?search={user_input}
Filtering by Location Type
You can limit results to specific location types if needed:
GET https://api.repliers.io/locations/autocomplete?search=tor&type=city&type=neighborhood
This example excludes areas (counties/regions) and only returns cities and neighborhoods.
Example Response
{
"page": 1,
"numPages": 2,
"pageSize": 10,
"count": 20,
"locations": [
{
"resource": "Property:2381",
"locationId": "CAONCIREWPFEEZ",
"name": "Toronto",
"type": "city",
"map": {
"latitude": "43.653226",
"longitude": "-79.3831843"
},
"address": {
"state": "ON",
"country": "CA",
"city": "Toronto",
"area": "Toronto",
"neighborhood": ""
}
},
{
"resource": "Property:2381",
"locationId": "CAONNBZFGYQLJV",
"name": "Toronto Gore Rural Estate",
"type": "neighborhood",
"map": {
"latitude": "43.8003876",
"longitude": "-79.7014332"
},
"address": {
"state": "ON",
"country": "CA",
"city": "Brampton",
"area": "Peel",
"neighborhood": "Toronto Gore Rural Estate"
}
}
]
}
Step 3: Combine and Present Results
Concatenate the listings and locations results, then present them to users in organized categories (e.g., "Properties", "Cities", "Neighborhoods").
Implementation Best Practices
Performance Optimization
Debounce User Input Implement a debounce mechanism to prevent API calls on every keystroke. Recommended delay: 300-500ms after the user stops typing.
// Example debounce implementation
const debounce = (func, delay) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(null, args), delay);
};
};
const debouncedSearch = debounce(performSearch, 300);
Field Selection Only request the fields you need in your fields
parameter. This significantly improves response times and reduces bandwidth usage.
Concurrent Requests Execute both API calls (listings and locations) simultaneously using Promise.all() or similar concurrent execution patterns.
User Experience Considerations
Categorized Results Present results in clear categories:
- Properties (from listings endpoint)
- Cities (from locations endpoint)
- Neighborhoods (from locations endpoint)
- Areas (from locations endpoint, if included)
Visual Hierarchy Use clear visual distinctions between categories and include relevant details like:
- Property addresses and prices
- Location types (city, neighborhood, area)
- Geographic context when helpful
Loading States Implement appropriate loading indicators while API requests are in progress.
Code Example
async function performAutocompleteSearch(query) {
if (query.length < 2) return; // Don't search for very short queries
try {
// Execute both searches concurrently
const [listingsResponse, locationsResponse] = await Promise.all([
fetch(`https://api.repliers.io/listings?search=${encodeURIComponent(query)}&searchFields=address.streetNumber,address.streetName,mlsNumber,address.city&fields=address.*,mlsNumber,listPrice`),
fetch(`https://api.repliers.io/locations/autocomplete?search=${encodeURIComponent(query)}`)
]);
const listings = await listingsResponse.json();
const locations = await locationsResponse.json();
// Combine and categorize results
const results = {
properties: listings.listings || [],
cities: locations.locations?.filter(loc => loc.type === 'city') || [],
neighborhoods: locations.locations?.filter(loc => loc.type === 'neighborhood') || [],
areas: locations.locations?.filter(loc => loc.type === 'area') || []
};
displayResults(results);
} catch (error) {
console.error('Search failed:', error);
// Handle error appropriately
}
}
// Apply debouncing
const debouncedSearch = debounce(performAutocompleteSearch, 300);
// Attach to search input
document.getElementById('search-input').addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
Alternative Approaches
Hybrid Location Services
For markets where MLS® location data doesn't align with local terminology, consider combining:
Option 1: Google Places Integration
// Use Google Places for locations, Repliers for listings
const [listingsResponse, placesResponse] = await Promise.all([
searchReplierListings(query),
searchGooglePlaces(query)
]);
Option 2: Mapbox Integration
// Use Mapbox for locations, Repliers for listings
const [listingsResponse, mapboxResponse] = await Promise.all([
searchReplierListings(query),
searchMapboxPlaces(query)
]);
This hybrid approach provides the comprehensive MLS® listing data from Repliers while leveraging the superior location recognition capabilities of specialized mapping services.
Conclusion
This autocomplete implementation provides users with a comprehensive search experience that bridges the gap between specific property searches and general location exploration. By combining both endpoints and following the optimization practices outlined above, you can create a fast, intuitive search interface that helps users find exactly what they're looking for.
Updated on: 16/07/2025
Thank you!