Skip to main content

Real Estate GEO Guide

Most property listings are invisible to AI search. This guide shows you why, and how to fix it, whether you list 1 property or 10,000.

JSON-LD schema markup, structured data, and location enrichment to make property listings visible in ChatGPT, Perplexity, and Google AI Overviews.

JSON-LDAI SearchSchemaReal Estate

Without geo data

Location"Quiet street in a great neighborhood"
Nearby-
Transit-
Coordinates-

What AI sees: nothing matchable. Zero neighbourhood or proximity queries answered.

With GeoEnrich

LocationRuysdaelkade 21, Amsterdam De Pijp
NearbyAlbert Cuyp market (200m), 3 schools (500m)
TransitTram 3 and 12, 1 min walk
Coordinates52.3534, 4.8965

What AI sees: matchable for 50+ query types including "2-bedroom near tram in De Pijp", "apartment with parking under 400k", "quiet street close to schools".

GeoEnrich generates the right column automatically from an address. One API call.

Quick Start

Add this JSON-LD to your property listing page and AI search engines can immediately parse and recommend it:


{
  "@context": "https://schema.org",
  "@type": "RealEstateListing",
  "name": "2-Bedroom Apartment in Amsterdam De Pijp",
  "url": "https://www.example-agency.com/listings/ruysdaelkade-21",
  "description": "Bright 2-bedroom apartment on the Ruysdaelkade in De Pijp, Amsterdam. 85 square meters, south-facing balcony, open-plan kitchen, renovated bathroom. 200 meters from Albert Cuyp market, 1-minute walk to tram lines 3 and 12.",
  "datePosted": "2026-03-15",
  "about": {
    "@type": "Residence",
    "address": {
      "@type": "PostalAddress",
      "streetAddress": "Ruysdaelkade 21",
      "addressLocality": "Amsterdam",
      "addressRegion": "North Holland",
      "postalCode": "1072 AK",
      "addressCountry": "NL"
    },
    "geo": {
      "@type": "GeoCoordinates",
      "latitude": 52.3534,
      "longitude": 4.8965
    },
    "floorSize": {
      "@type": "QuantitativeValue",
      "value": 85,
      "unitCode": "MTK"
    },
    "numberOfRooms": 3,
    "numberOfBedrooms": 2,
    "numberOfBathroomsTotal": 1,
    "petsAllowed": false,
    "yearBuilt": "1925"
  },
  "offers": {
    "@type": "Offer",
    "price": 395000,
    "priceCurrency": "EUR",
    "availability": "https://schema.org/InStock"
  }
}

This covers the basics. The sections below explain how to add neighbourhood context, nearby POIs, transit data, and more to make your listings match dozens of additional query types. See the schema examples tab for complete, production-ready files.

How People Search for Property Through AI

Property searches through AI are fundamentally different from portal searches. Instead of filtering dropdowns, people describe what they want in natural language. Understanding these intent patterns is the foundation of real estate GEO.

Neighbourhood and Location Queries

These are the most common property queries and the hardest for traditional listings to answer:

  • "2-bedroom apartments in De Pijp, Amsterdam under 400k"
  • "Family homes near international schools in Barcelona"
  • "Quiet streets in London Zone 2 with good transport links"
  • "Apartments within walking distance of the beach in Lisbon"
  • "Houses near hospitals in Amsterdam-Zuid"

Every one of these queries requires structured location data, coordinates, and nearby POI context. Without it, your listing is invisible.

Proximity Queries

Buyers and renters care about what is nearby. AI engines need distance data to answer:

  • "Apartments near Vondelpark with a supermarket within 5 minutes"
  • "Homes within 500 meters of a metro station in Amsterdam"
  • "Properties close to restaurants and nightlife in Jordaan"

Feature and Specification Queries

These combine property attributes with location:

  • "3-bedroom apartment with balcony and parking in Amsterdam under 500k"
  • "Ground-floor apartment with garden in The Hague"
  • "Penthouse with rooftop terrace in Barcelona Eixample"
  • "Energy-efficient homes with solar panels in Rotterdam"

Investment Queries

Investors ask different questions:

  • "Best neighbourhoods for rental yield in Amsterdam"
  • "Up-and-coming areas in Lisbon for property investment"
  • "Average price per square meter in Berlin Mitte vs Kreuzberg"

To appear in any of these results, your listing needs structured data that AI engines can parse: exact coordinates, nearby POIs with distances, property specifications as structured fields, and neighbourhood context signals.

Why Property Listings Fail AI Search

The vast majority of property listings are invisible to AI search engines. Here is why, and what to fix.

1. Vague Location Text

"Located in a desirable neighbourhood" tells AI nothing. "Ruysdaelkade 21, Amsterdam De Pijp, 200 meters from Albert Cuyp market" tells AI everything. Vague descriptions are the single biggest reason listings fail. AI cannot infer that "great area" means De Pijp, or that "close to shops" means 200 meters from a market.

2. Missing Coordinates

Without latitude and longitude, AI cannot calculate distances. Every proximity query ("near the park", "close to metro", "walking distance to schools") requires coordinates on both the listing and the POI. Coordinates must be precise to 4+ decimal places. "52.35, 4.90" points to a 100-meter radius; "52.3534, 4.8965" points to a specific building.

3. No Nearby Context

This is where most listings fail even if they have an address. A listing with coordinates but no nearby POI data cannot answer "apartments near schools" because AI has no school data to match against. You need to explicitly state what is nearby, with names and distances.

4. No Structured Data

Property details buried in paragraph text are hard for AI to extract. "This lovely 85m2 apartment has 2 bedrooms, 1 bathroom, and a south-facing balcony" is human-readable. But structured schema fields like floorSize: 85, numberOfBedrooms: 2, and amenityFeature: "South-facing balcony" are machine-readable. AI engines strongly prefer structured data.

5. Stale Listings

A listing posted 6 months ago with no datePosted or dateModified field looks abandoned. AI engines deprioritise content that appears outdated. Always include dates and update them when the listing changes.

6. No Price in Structured Fields

Price buried in text ("asking price: EUR 395,000") is harder to parse than an Offer with price: 395000 and priceCurrency: "EUR". Price is one of the most common filters in property queries, so missing structured pricing means missing those queries entirely.

RealEstateListing Schema Markup

The RealEstateListing type from Schema.org is the correct schema for property listings. It wraps a property (Residence, Apartment, House) inside a listing context with price, date, and availability.

Core Structure

A RealEstateListing has three key parts:

  1. The listing itself: name, description, datePosted, URL
  2. The property (via about): address, geo, floorSize, numberOfRooms, amenities
  3. The offer: price, priceCurrency, availability

Property Types

Use the most specific @type for the property inside about:

  • Apartment for flats, condos, studio apartments
  • House or SingleFamilyResidence for detached/semi-detached houses
  • Residence as a general fallback

Essential Fields

These fields are the minimum for AI discoverability:


{
  "@context": "https://schema.org",
  "@type": "RealEstateListing",
  "name": "Descriptive title with key features and location",
  "description": "150-300 word description with specific details",
  "datePosted": "2026-03-15",
  "about": {
    "@type": "Apartment",
    "address": {
      "@type": "PostalAddress",
      "streetAddress": "Herengracht 100",
      "addressLocality": "Amsterdam",
      "addressRegion": "North Holland",
      "postalCode": "1015 BS",
      "addressCountry": "NL"
    },
    "geo": {
      "@type": "GeoCoordinates",
      "latitude": 52.3728,
      "longitude": 4.8882
    },
    "floorSize": {
      "@type": "QuantitativeValue",
      "value": 120,
      "unitCode": "MTK"
    },
    "numberOfRooms": 5,
    "numberOfBedrooms": 3,
    "numberOfBathroomsTotal": 2
  },
  "offers": {
    "@type": "Offer",
    "price": 650000,
    "priceCurrency": "EUR"
  }
}

Additional Property Fields

These fields increase the number of queries your listing can match:

  • yearBuilt: construction year (important for renovation queries)
  • petsAllowed: true/false (filters pet-friendly searches)
  • amenityFeature: array of features like "Balcony", "Parking", "Garden", "Elevator", "Storage"
  • numberOfFullBathrooms / numberOfPartialBathrooms: more specific than total
  • floorLevel: which floor the property is on
  • permittedUsage: "Residential", "Mixed-use", "Commercial"

Geo Enrichment for Property Listings

Coordinates alone tell AI where a property is. Geo enrichment tells AI what is around it. This is the difference between matching 5 query types and matching 50.

What Geo Enrichment Adds

For a property at Ruysdaelkade 21 in Amsterdam, geo enrichment provides:

  • Schools: De Pijp Primary School (350m), Montessori School Zuid (600m), International School (1.2km)
  • Transit: Tram 3 stop (80m), Tram 12 stop (120m), Metro De Pijp station (500m), Amsterdam Centraal (3.5km)
  • Shopping: Albert Cuyp Market (200m), Albert Heijn supermarket (150m), Ferdinand Bolstraat shopping street (300m)
  • Parks: Sarphatipark (400m), Vondelpark (1.2km)
  • Healthcare: OLVG Hospital (800m), Pharmacy (250m), GP practice (300m)
  • Restaurants: 23 restaurants within 500m

How to Structure Nearby POIs

Use the additionalProperty field on the property to add nearby context:


{
  "@type": "Apartment",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Ruysdaelkade 21",
    "addressLocality": "Amsterdam",
    "postalCode": "1072 AK",
    "addressCountry": "NL"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": 52.3534,
    "longitude": 4.8965
  },
  "additionalProperty": [
    {
      "@type": "PropertyValue",
      "name": "Nearest School",
      "value": "De Pijp Primary School, 350m"
    },
    {
      "@type": "PropertyValue",
      "name": "Nearest Supermarket",
      "value": "Albert Heijn, 150m"
    },
    {
      "@type": "PropertyValue",
      "name": "Nearest Tram Stop",
      "value": "Tram 3 (Ruysdaelkade), 80m"
    },
    {
      "@type": "PropertyValue",
      "name": "Nearest Park",
      "value": "Sarphatipark, 400m"
    },
    {
      "@type": "PropertyValue",
      "name": "Nearest Hospital",
      "value": "OLVG Hospital, 800m"
    },
    {
      "@type": "PropertyValue",
      "name": "Restaurants within 500m",
      "value": "23"
    }
  ]
}

Why This Matters

Without this data, AI cannot answer any of these queries about your listing:

  • "Apartments near schools in De Pijp" (needs school POI data)
  • "Property with good public transport in Amsterdam-Zuid" (needs transit data)
  • "Homes near supermarkets and parks" (needs POI data for both)
  • "Apartments close to hospitals" (needs healthcare POI data)

The MapAtlas GeoEnrich API generates all of this from a single address or coordinate pair. One API call returns schools, transit, shopping, parks, healthcare, and restaurants with names and distances, ready to embed as additionalProperty values.

Neighbourhood Context Signals

Beyond individual POIs, buyers and renters want to understand the neighbourhood itself. AI engines look for signals that describe the character and livability of an area.

Walkability and Transport Scores

Neighbourhood-level scores help AI answer lifestyle queries:


{
  "additionalProperty": [
    {
      "@type": "PropertyValue",
      "name": "Walk Score",
      "value": "92/100"
    },
    {
      "@type": "PropertyValue",
      "name": "Transit Score",
      "value": "88/100"
    },
    {
      "@type": "PropertyValue",
      "name": "Bike Score",
      "value": "95/100"
    }
  ]
}

These scores directly answer queries like "walkable neighbourhoods in Amsterdam for car-free living" or "best areas for cycling commuters in Amsterdam."

Commute Time Data

Commute time is one of the top decision factors for property buyers. Include it as structured data:


{
  "@type": "PropertyValue",
  "name": "Commute to Amsterdam Centraal",
  "value": "12 minutes by tram, 18 minutes by bike"
}

Neighbourhood Description

Your listing description should include neighbourhood context. Instead of "great neighbourhood", write:

"De Pijp is one of Amsterdam's most sought-after neighbourhoods, known for the Albert Cuyp street market, a diverse restaurant scene, and tree-lined canals. The area has excellent public transport with tram lines 3, 12, and 24, plus the recently opened Metro 52 (North-South line). Sarphatipark offers green space within 400 meters."

This paragraph alone matches dozens of AI queries because it contains specific, verifiable facts that AI can extract and cite.

Local Amenity Counts

Aggregate counts give AI a sense of density and convenience:

  • "14 restaurants within 300 meters"
  • "3 supermarkets within 500 meters"
  • "5 schools within 1 kilometre"
  • "2 parks within 600 meters"

These counts enable comparison queries: "Which Amsterdam neighbourhood has the most restaurants nearby?" or "Areas with the best school coverage."

Rental vs Sale Listings

Rental and sale listings use the same RealEstateListing wrapper, but the offer structure and some property fields differ.

Sale Listing Offer


{
  "offers": {
    "@type": "Offer",
    "price": 395000,
    "priceCurrency": "EUR",
    "availability": "https://schema.org/InStock",
    "validFrom": "2026-03-15"
  }
}

Rental Listing Offer

For rentals, the price represents monthly rent. Use priceSpecification to clarify the billing period:


{
  "offers": {
    "@type": "Offer",
    "priceSpecification": {
      "@type": "UnitPriceSpecification",
      "price": 1850,
      "priceCurrency": "EUR",
      "unitText": "MONTH"
    },
    "availability": "https://schema.org/InStock"
  }
}

Rental-Specific Fields

Rental listings benefit from additional fields that sale listings do not need:

  • leaseLength: minimum lease duration (e.g., 12 months)
  • petsAllowed: critical for rental searches ("pet-friendly rentals in Amsterdam")
  • amenityFeature: furnished/unfurnished, included utilities, parking
  • Deposit amount in the description or additionalProperty
  • Available from date (use validFrom on the Offer)

Holiday Rentals Are Different

Short-term holiday rentals (Airbnb-style) should not use RealEstateListing. They use LodgingBusiness with nightly pricing and check-in/check-out times. See the vacation rental section below for details.

Commercial Real Estate

Commercial property searches follow different patterns than residential. Businesses searching for office, retail, or industrial space ask questions that require specific structured data.

Common Commercial Queries

  • "Office space for rent in Amsterdam Zuidas under 50 EUR per sqm"
  • "Retail space near high foot traffic areas in Barcelona"
  • "Warehouse with loading dock in Rotterdam port area"
  • "Coworking-ready office near Centraal Station"
  • "Restaurant space for lease in Jordaan with terrace permit"

Schema for Commercial Properties

Use specific types where possible:

  • OfficeBuilding for office space
  • ShoppingCenter or Store for retail
  • Warehouse for industrial/logistics
  • LocalBusiness as a general fallback with additionalType

Commercial listings need fields that residential ones do not:


{
  "@context": "https://schema.org",
  "@type": "RealEstateListing",
  "name": "350m2 Office Space in Amsterdam Zuidas",
  "about": {
    "@type": "OfficeBuilding",
    "address": {
      "@type": "PostalAddress",
      "streetAddress": "Barbara Strozzilaan 201",
      "addressLocality": "Amsterdam",
      "postalCode": "1083 HN",
      "addressCountry": "NL"
    },
    "geo": {
      "@type": "GeoCoordinates",
      "latitude": 52.3361,
      "longitude": 4.8756
    },
    "floorSize": {
      "@type": "QuantitativeValue",
      "value": 350,
      "unitCode": "MTK"
    },
    "amenityFeature": [
      {"@type": "LocationFeatureSpecification", "name": "Fiber Internet"},
      {"@type": "LocationFeatureSpecification", "name": "24/7 Access"},
      {"@type": "LocationFeatureSpecification", "name": "Meeting Rooms"},
      {"@type": "LocationFeatureSpecification", "name": "Parking Garage"},
      {"@type": "LocationFeatureSpecification", "name": "Reception Desk"}
    ],
    "additionalProperty": [
      {"@type": "PropertyValue", "name": "Floor Level", "value": "8th floor"},
      {"@type": "PropertyValue", "name": "Nearest Metro", "value": "Amsterdam Zuid, 200m"},
      {"@type": "PropertyValue", "name": "Parking Spaces", "value": "12 included"}
    ]
  },
  "offers": {
    "@type": "Offer",
    "priceSpecification": {
      "@type": "UnitPriceSpecification",
      "price": 45,
      "priceCurrency": "EUR",
      "unitText": "SQM/YEAR"
    }
  }
}

Commercial-Specific Enrichment

Commercial tenants care about different nearby context than residents:

  • Transport hubs: train stations, motorway access, airport distance
  • Business ecosystem: nearby companies, business parks, conference centres
  • Amenities for employees: restaurants, gyms, childcare, parking
  • Foot traffic data: critical for retail spaces

The GeoEnrich API returns all of these POI categories, so you can automatically enrich commercial listings with the context that business tenants search for.

Vacation and Holiday Rental AEO

Vacation rentals (Airbnb-style short stays) need a completely different schema approach. These are hospitality businesses, not property sales or long-term rentals.

Use LodgingBusiness, Not RealEstateListing

The correct schema type for vacation rentals is LodgingBusiness (or the more specific VacationRental if supported). This tells AI engines that the property accepts short-term guests with nightly pricing, check-in/out times, and hospitality amenities.

Key Differences from Residential Listings

  • Pricing: nightly rate, not total sale price or monthly rent
  • Availability: check-in and check-out times, minimum stay
  • Amenities: WiFi, kitchen, washing machine, towels, linens
  • Guest capacity: maximum occupancy, beds, bedrooms
  • Reviews: aggregateRating from guest reviews
  • Nearby attractions: tourists care about different POIs than residents

Vacation Rental Query Patterns

Holiday rental searches are highly specific:

  • "Apartment in Barcelona Gothic Quarter for 4 guests under 150 per night"
  • "Holiday rental near the beach in Lisbon with sea view"
  • "Family-friendly vacation home in Amsterdam with garden and parking"
  • "Pet-friendly holiday cottage near Lake Garda"
  • "Romantic canal house rental in Amsterdam for couples"

Essential Vacation Rental Fields


{
  "@context": "https://schema.org",
  "@type": "LodgingBusiness",
  "name": "Canal View Apartment in Amsterdam Jordaan",
  "description": "Charming 1-bedroom canal house apartment in the heart of Jordaan. Sleeps 2 guests. Original wooden beams, modern kitchen, rain shower. 5-minute walk to Anne Frank House and Westerkerk. Free WiFi, Smart TV, Nespresso machine.",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Prinsengracht 263",
    "addressLocality": "Amsterdam",
    "postalCode": "1016 GV",
    "addressCountry": "NL"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": 52.3752,
    "longitude": 4.8839
  },
  "checkinTime": "15:00",
  "checkoutTime": "11:00",
  "numberOfRooms": 1,
  "petsAllowed": false,
  "amenityFeature": [
    {"@type": "LocationFeatureSpecification", "name": "Free WiFi"},
    {"@type": "LocationFeatureSpecification", "name": "Kitchen"},
    {"@type": "LocationFeatureSpecification", "name": "Washing Machine"},
    {"@type": "LocationFeatureSpecification", "name": "Smart TV"},
    {"@type": "LocationFeatureSpecification", "name": "Air Conditioning"},
    {"@type": "LocationFeatureSpecification", "name": "Canal View"}
  ],
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": 4.8,
    "reviewCount": 127,
    "bestRating": 5
  },
  "offers": {
    "@type": "Offer",
    "price": 135,
    "priceCurrency": "EUR",
    "unitText": "NIGHT"
  }
}

Tourist-Oriented Geo Enrichment

Vacation rental guests care about different nearby POIs than long-term residents:

  • Tourist attractions: museums, landmarks, historic sites with distances
  • Restaurants and bars: density and variety within walking distance
  • Airport and station access: travel time from major transport hubs
  • Beach or waterfront: distance for coastal properties
  • Supermarkets: nearest grocery store for self-catering guests

Use the GeoEnrich API to automatically generate tourist-relevant POI data for each vacation rental listing.

Implementation and Testing

Follow this process to implement schema markup across your property listings.

Step 1: Add JSON-LD to Listing Pages

Place the <script type="application/ld+json"> tag in the <head> of each listing page. For property portals with thousands of listings, generate the schema server-side from your listing database.

Step 2: Validate

Test each schema with these tools:

Step 3: Test with AI Engines

After deployment, ask AI engines about your listings:

  • "Tell me about apartments for sale on Ruysdaelkade in Amsterdam"
  • "What is near [your property address]?"
  • "Compare properties in De Pijp, Amsterdam"

If AI cannot answer with specifics, your schema is incomplete or not being crawled. Check that your page is indexable (no noindex tag), the JSON-LD is in the rendered HTML (not just client-side JS), and your sitemap includes listing pages.

Step 4: Use the Checklist

The checklist tab on this page covers every field and signal needed for complete property listing GEO. Work through each section systematically. Aim for 100% completion on the basic schema and address sections, then add nearby context and neighbourhood signals for maximum coverage.

Scaling with GeoEnrich API

Manually adding nearby POIs, transit data, and neighbourhood context to every listing is not feasible at scale. If you manage 100+ properties, you need automation.

How GeoEnrich Works

The MapAtlas GeoEnrich API takes an address or coordinate pair and returns structured nearby context:

  • Schools (names, types, distances)
  • Public transit (stops, lines, distances)
  • Shopping (supermarkets, markets, retail)
  • Parks and green spaces
  • Healthcare (hospitals, pharmacies, GPs)
  • Restaurants and cafes
  • Tourist attractions (for vacation rentals)
  • Walkability, transit, and bike scores

Integration Pattern

The typical workflow for property portals:

  1. Listing is created with address
  2. Address is geocoded to coordinates (MapAtlas Geocoding API or your existing provider)
  3. Coordinates are sent to GeoEnrich API
  4. Response is parsed into additionalProperty values
  5. JSON-LD schema is generated with full enrichment
  6. Schema is embedded in the listing page

This process runs automatically for every new listing and can be batch-processed for existing inventory.

Before and After

Without GeoEnrich, a listing matches queries about its address and basic specs (bedrooms, price). With GeoEnrich, the same listing matches queries about schools, transit, walkability, nearby restaurants, parks, hospitals, and commute times. That is the difference between matching 5 query types and 50+.

For implementation details and API documentation, see the GeoEnrich API page.

Automate this at scale

Writing schema manually works for one listing. What about thousands?

The MapAtlas GeoEnrich API adds coordinates, nearby POIs, transit access, neighbourhood context, and schema-ready geo data to every listing automatically, one API call per listing, at any scale.