AI Real Estate Assistant in Mobile Applications
Property search is a task with rich structured datasets (listings) but poorly formalized user requirements. "Quiet neighborhood, near metro, bright apartment"—these aren't filters, they're intentions. The AI assistant translates intentions into search parameters and explains why a property fits or doesn't.
Requirement Parsing via Function Calling
Users describe desired properties in free text. Function calling extracts structured criteria:
let extractFiltersFunction: [String: Any] = [
"name": "extract_search_filters",
"description": "Extract real estate search criteria from user message",
"parameters": [
"type": "object",
"properties": [
"property_type": ["type": "string", "enum": ["apartment", "house", "studio", "commercial"]],
"min_rooms": ["type": "integer"],
"max_rooms": ["type": "integer"],
"min_area_sqm": ["type": "number"],
"max_price": ["type": "number"],
"metro_walk_minutes": ["type": "integer", "description": "Max walking time to metro"],
"districts": ["type": "array", "items": ["type": "string"]],
"floor_preference": ["type": "string", "enum": ["not_ground", "not_top", "high", "any"]],
"must_haves": ["type": "array", "items": ["type": "string"],
"description": "Required features: parking, balcony, new_building, quiet_street, etc."],
"deal_type": ["type": "string", "enum": ["buy", "rent"]]
]
]
]
The dialog can be refined—"what counts as near metro?", "what price range?" This is multi-turn conversation, accumulating context.
Listing API Integration
After filter extraction, query the listings database (CIAN, Avito, Yandex.Real Estate, or proprietary).
class RealEstateSearchService {
func search(filters: SearchFilters) async throws -> [Property] {
var params = [URLQueryItem]()
params.append(URLQueryItem(name: "type", value: filters.propertyType))
if let maxPrice = filters.maxPrice {
params.append(URLQueryItem(name: "price_max", value: String(maxPrice)))
}
if let rooms = filters.minRooms {
params.append(URLQueryItem(name: "rooms_min", value: String(rooms)))
}
// ... remaining filters
var url = URLComponents(string: baseURL + "/search")!
url.queryItems = params
let (data, _) = try await URLSession.shared.data(from: url.url!)
return try JSONDecoder().decode([Property].self, from: data)
}
}
Geo-filter "near metro" is implemented via station coordinates + MapKit.MKCoordinateRegion or CLLocation.distance(from:). Not by neighborhood name—more reliable.
AI Match Explanation
A list of listings without "why does this fit?" explanations is weak UX. Generate short AI explanations for each property (or top 3) explaining relevance.
func generateMatchExplanation(property: Property, userRequirements: String) async throws -> String {
let prompt = """
The user is looking for: \(userRequirements)
Property details:
- \(property.rooms) rooms, \(property.area) sqm
- Floor: \(property.floor)/\(property.totalFloors)
- Metro: \(property.metroStation), \(property.metroWalkMinutes) min walk
- Price: \(property.price) \(property.currency)/month
- Features: \(property.features.joined(separator: ", "))
- District: \(property.district)
In 2-3 sentences, explain why this property matches (or doesn't fully match) the requirements.
Be specific about matches and mismatches. No marketing language.
"""
return try await openAI.complete(prompt: prompt, maxTokens: 100)
}
100 tokens—hard limit. Explanations should be short and to the point.
Map with Clustering
Always show listings on a map. On iOS use MapKit with custom MKAnnotationView. For many points, use clustering via MKClusterAnnotation.
// Clustering setup
let annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "property")
annotationView.clusteringIdentifier = "properties" // enables auto-clustering
// Custom cluster view with count
class PropertyClusterAnnotationView: MKAnnotationView {
override func prepareForDisplay() {
super.prepareForDisplay()
if let cluster = annotation as? MKClusterAnnotation {
let count = cluster.memberAnnotations.count
image = drawClusterBadge(count: count)
}
}
}
On Android, use Google Maps SDK with ClusterManager from android-maps-utils library.
Saved Searches and Notifications
When users save search criteria, the system notifies them of new listings. On the server, a periodic job runs saved filters against new properties and sends push notifications.
// Android - handle push with new listing
class NewPropertyNotificationHandler : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val propertyId = remoteMessage.data["property_id"] ?: return
val notification = NotificationCompat.Builder(this, CHANNEL_NEW_PROPERTIES)
.setContentTitle("New listing matching your search")
.setContentText(remoteMessage.data["summary"])
.setSmallIcon(R.drawable.ic_home)
.setContentIntent(buildDeepLinkIntent(propertyId))
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(this).notify(propertyId.hashCode(), notification)
}
}
Timeline Estimates
Basic search with AI filter parsing + results list—5–7 days. Full assistant with dialog, map, AI match explanations, saved searches, and push notifications—4–6 weeks.







