Apartments.com
Search millions of rental listings on Apartments.com directly from your conversation. Tell the assistant what you're looking for — city, neighborhood, price range, bedrooms, pet policy, amenities — and get curated results with photos, pricing, and availability in seconds. From a single chat you can explore floor plans, check unit availability, review fees and lease policies, get neighborhood insights, estimate affordability, schedule a tour, or contact a property directly. No forms, no tab-switching, no scrolling through pages. Just describe your ideal home and let the assistant do the searching.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Residential Property Listing Portals
- Secondary Subcategories
- None listed
- Brand
- Apartments.com
- Access
- Account required
- First tracked
- 2026-08-04
- Tool count
- 16
- Geography
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is visible.
ChatGPT Plugin Discoverability Score
ChatGPT organic discovery is not live yet
Apartments.com is tracked in the ChatGPT Plugin registry. Public organic-discovery measurement is not live for ChatGPT yet, so there is no score to publish today.
Get notified when your score goes live
Enter your work email and we’ll notify you when ChatGPT Plugin organic discovery scoring launches.
No spam. Unsubscribe any time.
Competing in ChatGPT Residential Property Listing Portals
View CategoryHow the Discoverability Score works
Organic discovery scoring for Apartments.com on ChatGPT is not live yet. The score will use measured agent conversations when it launches.
Organic discovery scoring is pending. Your Plugin score will appear on this scale when measurement goes live.
FoundDiagnostic
Whether Claude found your Plugin in connector search. It must be Found before it can reach the picker, but the score counts picker appearances—not search results.
PickedMain score
How often your Plugin appeared in the picker, or Claude invoked it directly, across contested conversations. This percentage is the Discoverability Score; the headline number is rounded.
PositionedDiagnostic
What position your Plugin appeared in when it was shown in the picker. This shows prominence, but it does not affect the score.
16 tools agents can invoke
Assess whether a rent amount fits a renter's budget using the 30% gross income guideline. WHEN TO CALL: call proactively when the user mentions their income, asks if they can afford a listing, asks what rent range they should look for, or asks how a specific rent compares to the market. Do not wait for an explicit request — treat any affordability signal as a trigger. Two modes: (1) Pure calculation — provide income and optionally a rent amount to get budget, ratio, and tier. (2) Market comparison — additionally provide a cityId (from search.listings or listing.details) to compare budget against average rents in that area. Income must be a raw number (no $ or K suffixes — convert before calling, e.g. '80K' → 80000). incomePeriod is required: 'annual' or 'monthly'. If both rentAmount and cityId are provided, both modes run simultaneously. AFTER RESPONSE: present the recommended monthly budget, the affordability tier (e.g. affordable, stretched, over budget), and if market data is available, how the budget compares to average rents in the area.
rent.affordability
Submit the tour booking with the renter's chosen date, time, and contact info. ALWAYS pass propertyName (from listing.details `name` field) and tourTypeName (10 = "In Person", 20 = "Self-Guided", 30 = "Personal Online") so the consent dialog shows meaningful labels. Before calling, you MUST have collected from the renter: first name, last name, email, and phone number. Do NOT call until all four fields are confirmed — the tool will reject the call without them. NAME PARSING: when the renter provides their name as one string (e.g. "Junhong xue", "Maria Garcia Lopez", "wei li"), split on whitespace — the FIRST token is firstName, the REMAINING tokens (joined with spaces) are lastName. Accept ANY non-empty token as a valid last name regardless of length, case, or origin — short names like "xue", "li", "ng", "wu", "ho" are valid. Do NOT re-ask for a last name based on how it looks. Reuse contact info already shared earlier in the conversation; only ask for missing fields. Pass isIntegrated from the tour.availability Turn 1 response. Pass isRequestTour=true when the listing.details `tourEligibility.state` was "RequestATour" — the booking is a request that the property must confirm, and the tool result will include a regulatory verificationNotice that MUST be rendered verbatim. Omit or set false for "ScheduleATour" properties. On success, you MUST display the Confirmation Number (appointmentConfirmationId from the tool result) — never omit it. It is the single most important field for the renter.
tour.confirm
Submit user contact information to express interest in a property. This tool powers the "Message" action shown on the listing card — it sends the renter's contact info to the leasing office. Use this tool when the user indicates interest in a specific listing. Treat both explicit requests and softer positive intent as interest signals when they refer to one listing, for example: asks to apply, asks to contact leasing, says they want this property, says this listing looks good, says they like this one, says this seems like a strong option, or asks about next steps for that listing. EXPLICIT MESSAGE INTENT — skip the consent question: When the user explicitly asks to message or contact the property (e.g., "send message to <property>", "message <property>", "message the leasing office", "contact leasing at <property>", "email them", "reach out to <property>"), treat this AS the consent — do NOT ask "Want me to connect you with the leasing manager?" again. Go directly to collecting full name, email, and phone (reusing anything already shared), then call this tool. SOFT INTEREST — ask consent first: If the user expresses positive interest in a specific listing but has NOT explicitly asked to message/contact (e.g., "I like this one", "this looks good", "what are next steps"), ask one consent question: "Want me to connect you with the leasing manager?" If yes, collect full name, email, and phone, then call this tool once. If the user declines, do not call this tool and continue helping with listings. Guardrail: if the user already shared contact info earlier in the conversation, do not ask for it again; reuse it for additional interested listings and only ask for missing fields. Search restriction: do NOT call listing.search or any search tool before, during, or after this tool call. The user has already identified the listing — searching will disrupt their experience. On success, you MUST display the Reference Number (leadId from the tool result) to the renter — never omit it; it is their proof of submission.
listing.lead
Retrieve detailed information about a specific rental listing. Requires the encrypted `listingKey` from search.listings results. Returns full property details including floor plans, amenities, photos, contact info, and neighborhood data. The response includes a numeric `rating` (renter score, 0–5) but does NOT include individual review text. If the user asks to read or see reviews, ALWAYS present `listingPageUrl` as a markdown link to the property's Apartments.com listing page — whether or not `rating` is present. Describe the link as the listing page (NOT "the reviews") — the reviews section lives on that page and lazy-loads as the user scrolls. If `rating` is present, state it; if missing or zero, note no reviews yet. Then add one short statement-form sentence presenting the link. Do NOT offer to open, fetch, summarize, or pull up the reviews on the user's behalf — the link IS the action; let the user click it themselves. After presenting listing details, ALWAYS proactively present the next action based on `tourEligibility`: If `tourEligibility.state` is "ScheduleATour", present "Schedule a Tour" and call tour.availability with `tourEligibility.selectedTourType`; the host will confirm via tour.confirm. If `tourEligibility.state` is "RequestATour", present "Request a Tour" and call tour.availability with `tourEligibility.selectedTourType` to fetch dates/times (the property supports online scheduling but must confirm the booking). When the renter picks a date+time, call tour.confirm with isRequestTour=true so the regulatory verificationNotice is rendered. If `tourEligibility.state` starts with "NotEligible_", inform the user that online tour scheduling is not available and offer listing.lead to contact the leasing office. If `tourEligibility` is null (eligibility check failed), do not offer a tour; offer listing.lead to contact the leasing office instead. The response also includes a `requiredFollowUpQuestion` field — ask it verbatim as the final sentence.
listing.details
Retrieve all community-level media for a property: photos, videos, 3-D virtual tours, and floor-plan images. WHEN TO CALL: (1) user explicitly asks to see photos, videos, virtual tours, 3D tours, Matterport, or floor plans for a property; (2) user asks "how many photos/videos/tours does this listing have?" — use `categoryCounts` in the response to answer without scanning items[]. INPUT: `listingKey` from listing.details or search.listings results. Set `preferredTab` based on the user's intent: "Photos" for photos/images, "Videos" for videos, "Virtual Tours" for virtual tours / 3D tours / Matterport, "Floor Plans" for floor plans. The response `selectedTab` field tells the MediaCard which tab to pre-select — pass it directly to the component. AFTER RESPONSE: render the MediaCard component using `selectedTab` as the active tab. If `hasUnitLevelMedia` is true and user is interested in a specific unit → also call media.unit with that unit's `unitKey`. If `hasModelLevelMedia` is true and user is interested in a specific floor-plan type → also call media.model with that model's `modelKey`.
media.listing
Retrieve transparent fees and policies for a specific floorplan/model within a listing. Returns model-level pricing details such as application fees, pet fees, parking fees, and storage fees. Use the `listingKey` from listing.details and the `modelKey` from any rental entry belonging to the floorplan the user is asking about. WHEN TO CALL: Call this tool when the user asks about fees for a floorplan, bedroom/bathroom count, or model type — i.e. the user has NOT selected a specific unit but is asking about a unit type (e.g. "2 bed 2 bath fees", "what are the fees for the A1 floorplan", "how much is the application fee for a 1 bedroom"). Do NOT call this tool if the user is asking about a specific individual unit by unit number — use unit.fees-and-policies instead. FALLBACK RULES: If this tool returns no fee data (empty fees array) or returns an error, do NOT surface the failure to the user. Instead, silently fall back to any fee information already present in the listing.details context (e.g. application fee, pet fee, deposit amounts) and present those listing-level figures as the cost estimate. Note naturally that exact amounts should be confirmed with the leasing office. RESPONSE RULES: Never mention tool calls, tool results, or data retrieval to the user. Never say phrases like "I tried to pull", "the tool returned", "data was unavailable", "fee projection was unavailable", or any language that exposes internal execution. If fee data is available, present it as a clean cost breakdown (up-front and monthly) in natural language. If fee data is missing or partial, silently omit those line items and note only that specific figures may vary — never attribute it to a system or data issue.
model.fees-and-policies
Retrieve media for a specific floor-plan model: floor plan images, representative interior photos, and model-level 3-D tours. WHEN TO CALL: (1) user asks for photos, floor plans, or tours for a specific floor-plan type (e.g. "show me the 2-bedroom floor plan"); (2) `hasModelLevelMedia` is true in a media.listing response and user is interested in a specific model. INPUT: `modelKey` from a model-level rental in listing.details (rentals[].modelKey). Set `preferredTab` based on the user's intent: "Photos", "Videos", "Virtual Tours" (also for 3D tours / Matterport), or "Floor Plans". The response `selectedTab` field tells the MediaCard which tab to pre-select — pass it directly to the component. Do NOT call if modelKey is absent on a rental — not all rentals have model-level media. AFTER RESPONSE: render the MediaCard component using `selectedTab` as the active tab.
media.model
Retrieves RentMatrix promotional pricing for a specific unit. Returns special pricing offers set by the PMC, in one of two shapes depending on the listing's RentInfoType: - rentInfoType = 1 (Term): a list of prices per lease term, each term has a single rent price (no move-in date selection) example for rentInfoType = 1 (Term): { "rentInfoType": 1, "leaseTerms": [ { "leaseTerm": 12, "options": [{ "rent": 2261, "currency": "USD" }] }, { "leaseTerm": 13, "options": [{ "rent": 1739, "currency": "USD" }] } ] } - rentInfoType = 2 (MoveInDate): a list of lease terms, each with multiple rent options per available move-in date (full price grid) example for rentInfoType = 2 (MoveInDate): { "rentInfoType": 2, "leaseTerms": [ { "leaseTerm": 12, "options": [ { "rent": 2261, "currency": "USD", "startDate": "2026-04-21T00:00:00-04:00" }, { "rent": 2266, "currency": "USD", "startDate": "2026-04-22T00:00:00-04:00" } ] } ] } ONLY call this tool automatically when BOTH are true: 1. hasRentMatrix is true in the unit context. 2. The user is viewing or showing interest in a specific unit (a specific unitId is in focus). Do not wait for the user to ask about pricing — call proactively as part of presenting the unit. Do not call during listing or unit-list browsing. If hasRentMatrix is false or missing, do NOT call this tool. Do not mention this tool, RentMatrix, or missing pricing to the user.
unit.rent-matrix
Fetch available tour dates and timeslots for a property. No personal data is submitted. Turn 1: call with listingKey + tourTypeId (no date) to get available dates with pre-fetched timeslots. Each entry in `openDates` has a `displayDate`, `rawDate`, and `times` array (each with `display` and `raw` fields). Show dates and times together and ask the renter to pick BOTH a date AND a time in one response. If the renter picks a date+time from the Turn 1 list, skip Turn 2 and go directly to tour.confirm using `rawDate` (YYYY-MM-DD) and `raw` time (HH:MM 24h). Turn 2 (fallback only): call with date + isIntegrated if the renter asks for a date not in the Turn 1 list. Pass isIntegrated back on all subsequent calls — it is returned in the Turn 1 response. Search restriction: do NOT call listing.search or any search tool before, during, or after this tool call. The user has already identified the listing — searching will disrupt their experience.
tour.availability
Retrieve transparent fees and policies for a specific individual unit within a listing. Returns unit-level pricing details such as application fees, pet fees, parking fees, and storage fees. Use the `listingKey` from listing.details and the `unitKey` from the specific rental entry in listing.details. WHEN TO CALL: Call this tool only when the user is asking about fees for a specific individual unit — i.e. the user has selected or is viewing a particular unit identified by a unit number or unitKey (e.g. "unit 301", "this unit", "the one on the 3rd floor"). Do NOT call this tool if the user is asking about a floorplan, bedroom count, or model type — use model.fees-and-policies instead. FALLBACK RULES: If this tool returns no fee data (empty fees array) or returns an error, do NOT surface the failure to the user. Instead, silently fall back to any fee information already present in the listing.details context (e.g. application fee, pet fee, deposit amounts) and present those listing-level figures as the cost estimate. Note naturally that exact amounts should be confirmed with the leasing office. RESPONSE RULES: Never mention tool calls, tool results, or data retrieval to the user. Never say phrases like "I tried to pull", "the tool returned", "data was unavailable", "fee projection was unavailable", or any language that exposes internal execution. If fee data is available, present it as a clean cost breakdown (up-front and monthly) in natural language. If fee data is missing or partial, silently omit those line items and note only that specific figures may vary — never attribute it to a system or data issue.
unit.fees-and-policies
Retrieve media specific to an individual apartment unit: interior photos, unit-specific floor plan, and virtual tour for that exact unit. WHEN TO CALL: (1) user asks to see photos or tours for a specific unit they are considering; (2) `hasUnitLevelMedia` is true in a media.listing response and user is focused on a specific unit. INPUT: `unitKey` from a unit-level rental in listing.details (rentals[].unitKey). Set `preferredTab` based on the user's intent: "Photos", "Videos", "Virtual Tours" (also for 3D tours / Matterport), or "Floor Plans". The response `selectedTab` field tells the MediaCard which tab to pre-select — pass it directly to the component. Do NOT call if unitKey is absent on a rental — not all rentals are unit-level. AFTER RESPONSE: render the MediaCard component using `selectedTab` as the active tab.
media.unit
Get neighborhood context for a geographic area — walk score, city demographics, rent trends, and top schools. Requires matchType and encrypted matchId from prior search or listing detail results. For non-City geographies, provide cityId for demographics. Returns structuredContent for conversational presentation.
local.guide
Resolves a user's selection from a typeahead disambiguation list to a listingKey. Call this after typeahead returns multiple results and the user has picked a property. Pass the disambiguationId from the typeahead result and the user's selection (e.g. "1", "2", "the Irvine one", "Volar Irvine"). AFTER THIS TOOL RETURNS: call listing.details immediately with the returned listingKey. Do NOT call residentialForRent, search.listings, or any other tool.
typeahead.resolve
GPS-based apartment search. Call this tool — with no arguments — whenever the user wants rentals near their current location and has NOT named a specific city, ZIP, or address. Trigger phrases (call immediately, no questions asked): "search nearby", "search near me", "apartments near me", "rentals near me", "nearby apartments", "nearby rentals", "near by rentals", "close by rentals", "rentals around here", "local apartments", "apartments in my area". Also triggers when filters are combined with proximity: "nearby under $2000", "2-bed near me". This tool takes NO arguments. The app retrieves GPS automatically and calls search.listings. After calling this tool, reply only: "Getting your location now…" and wait. When the updateModelContext message with GPS coordinates arrives, call search.listings immediately. If the user specified filters, include them. If no filters were specified, call search.listings with ONLY the GPS coordinates — do NOT ask the user for filters.
search.near_me
Search for rental property listings (apartments, houses, condos, townhouses) by location, price, bedrooms, amenities, and other criteria. Returns a paginated list of matching listings with pricing, photos, and coordinates for map display. LOCATION PRECONDITION: This tool REQUIRES a concrete location named by the user — a city, neighborhood, postal code, street address, or named landmark/area. When the user uses proximity words like "near", "nearby", "near by", "here", "around", "close", "local" without naming a specific place — even when combined with filters like price, beds, or amenities (e.g. "nearby rentals under $2000", "near me 2 bed") — call search.near_me instead of this tool. When the user mentions price/beds/amenities but no place and no proximity word (e.g., "find apartments under $3000"), ask: "Which city, neighborhood, or ZIP code should I search?" and wait. When the user names a place alongside a self-relative phrase (e.g., "near me in Atlanta", "apartments near the airport in Boston"), use the NAMED place directly and call as normal. PAGE SIZE RULES: Always use pageSize=50 (and pageNumber=1 for the first page). Applied uniformly across all UI modes so the result ordering is identical whether the user is in list, inline-map, or fullscreen-map view. Increment pageNumber to retrieve subsequent pages of 50. RESPONSE RULES: (1) For pageNumber=1, the opener, bullet count, and CTA BRANCH on listings.length. The "narrow down with more filters" option appears ONLY when listings.length >= 10 — below that, results are too few to narrow further; offer "adjust your search" instead: • 1 result → render 1 bullet. Opener: "<Property Name> matched your search criteria of <filters>." CTA: "Want details on it, or adjust your search?" No "see more", no "narrow". • 2 results → render both bullets. Opener: "<Property A> and <Property B> matched your search criteria of <filters>." CTA: "Want details on one, to compare them, or adjust your search?" No "see more", no "narrow". • 3 results → render all 3 bullets. Opener: "There are various places with <filters> — here are the top 3." CTA: "Want details on one, to compare a few, or adjust your search?" No "see more" (the top 3 ARE all results), no "narrow". • 4–9 results → render the top 3 bullets. Opener: "There are various places with <filters> — here are the top 3." CTA: "Want to see more rentals, get details on one, compare a few, or adjust your search?" No "narrow". After the user asks for "more", render the remaining bullets (4–listings.length) in a single chunk, then close with: "Want details on one, to compare a few, or adjust your search?" • 10+ results → render the top 3 bullets. Opener: "There are various places with <filters> — here are the top 3." CTA: "Want to see more rentals, get details on one, compare a few, or narrow down with more filters?" In all five cases, wait for the user before doing anything else. (2) PAGINATION WITHIN THE CURRENT RESULT — no new tool call (applies ONLY when listings.length >= 4 on page 1, or on any page>=2): on every 'see more rentals' reply, render the NEXT CHUNK of up to 10 bullets from the SAME result object already in context. Track how many bullets you have shown so far for this page (call it N). The next 'more' response renders bullets at 1-based indices (N+1)..min(N+10, listings.length). Page-1 chunk sequence (listings.length >= 10): top 3 → 4–13 → 14–23 → 24–33 → 34–43 → 44–50 (or fewer if listings.length < 50). For 4–9 results, there is just one follow-up chunk: 4–listings.length. DO NOT call search.listings while any listing in the current result is still unshown — they are already in the structuredContent of the previous tool result that is still in context. End each chunk response with: "Want details on one, to compare a few, see more rentals, or narrow down with more filters?" — but DROP "narrow down with more filters" (replace with "adjust your search") when listings.length < 10, and DROP "see more rentals" once every bullet on the current page has been rendered. Wait after each response. (2a) For pageNumber>=2, the FIRST response shows the top 10 (no summary-opener sentence — that was on page 1); subsequent 'more' replies follow the same chunk-of-10 pattern from rule (2): 11–20 → 21–30 → 31–40 → 41–50 (or fewer if listings.length < 50). DO NOT call search.listings until N === listings.length. End each response with exactly: "Want details on one, to compare a few, see more rentals, or narrow down with more filters?" and wait. (2b) Branch on the user's follow-up answer: (i) "see more rentals" / "more" / "show more" / "yes" / "sure" → render the NEXT CHUNK of up to 10 bullets from the result already in context, per the chunk sequence in rule (2) (page 1: 3 → 13 → 23 → 33 → 43 → 50) or rule (2a) (page 2+: 10 → 20 → 30 → 40 → 50). This is a CHAT-ONLY response with NO tool call. Only when you have already rendered every listing in the current result as a bullet (N === listings.length) does the NEXT "more" reply trigger search.listings again with pageNumber incremented by 1. Never call search.listings just to fetch listings that are already in the previous result. (ii) "details" / a specific property name → wait for the user to name a property if not yet specified, then call listing.details with that listingKey. (iii) "compare" → wait for the user to name 2–3 properties, then briefly contrast their key attributes (price, beds/baths, amenities the user cares about, location) in a single side-by-side response using the data already in the current result; do NOT call any tool. (iv) "ratings" / "reviews" / "stars" / "how are they rated" / "show me ratings and reviews" / similar → answer from the `reviewRating` field already in the current search result for the requested listings; do NOT call listing.details (the search result is the source of truth for ratings). ALWAYS present each requested listing's `listingDetailPageUrl` as a markdown link on its name — whether or not the property has a rating. The `listingDetailPageUrl` points to the property's full Apartments.com listing page; the page itself contains the reviews section (which lazy-loads as the user scrolls down), so do NOT describe the link as going "to the reviews" — describe it as the listing page. Branch on how many properties the user is asking about: • SINGLE property (the user named one specific property, e.g. "show me reviews of Colonnade at The Market Place") → do NOT render a table. Reply with one short prose sentence: state the rating if `reviewRating` is present (e.g. "Colonnade at The Market Place is rated 5/5 by renters."), or note no reviews yet if it is missing (e.g. "Enzo doesn't have any renter reviews yet."). Follow that with one short statement-form sentence presenting the listing name as a markdown link to `listingDetailPageUrl` — e.g. "Tap [Colonnade at The Market Place](url) to view its Apartments.com listing page." If unrated, you may append a brief CTA hint, e.g. "Tap [Enzo](url) to view its Apartments.com listing page — you can be the first to leave a review there." • MULTIPLE properties (the user asked about two or more, or asked broadly across the current result set) → render a clean two-column table: Apartment, Rating. Render every apartment name as a markdown link to that listing's `listingDetailPageUrl` regardless of whether it has a rating. Do NOT add a Reviews, Notes, Commentary, or Analysis column, and do NOT editorialize on which listing has the "strongest" or "best" rating. If `reviewRating` is missing for a row, write "Not rated" in the Rating cell — but still link the name. After the table, add exactly one short sentence acknowledging the link goes to the Apartments.com listing page (statement, not offer — e.g. "Tap a property name to view its Apartments.com listing page."). Individual written reviews are NOT in the search response — only the aggregate `reviewRating`. Then end with a conversational follow-up question. Do NOT offer to open, fetch, summarize, or pull up the reviews on the user's behalf — the link IS the action; let the user click it themselves. (v) "narrow" / "more filters" / ANY mention of changing the search criteria → call search.listings AGAIN with the updated criteria. Triggers include (non-exhaustive): a new bedroom or bathroom count, a different price range, a new must-have amenity (gym, pool, parking, etc.), a different neighborhood/city, a pet-policy change, "show only ones with X", "actually I need…", "what about under $X", "any with a Y", etc. Merge the user's new criteria onto the existing listingFilters and re-call this tool — do NOT try to filter the existing in-context result client-side. If the user said "narrow" without specifying what to narrow on, ask 1–2 short clarifying questions first (e.g. "Any must-have amenities?", "Closer to a specific neighborhood?", "Tighter budget?"), then call. (vi) "amenities" / "features" / "what amenities" / "does it have a [gym/pool/etc]" / "what's included" / similar follow-up about what a SPECIFIC property offers → answer from the `amenities` array already in the current search result for that listing; do NOT call listing.details. The `amenities` array is a flat, curated subset of enum values — the Apartments.com listing page has the full, categorized list (Unique Features / Community / Apartment) which may include items not in our enum. To make that source of truth reachable, render the property name as a markdown link to its `listingDetailPageUrl` (use the URL as-is, no anchor) on first mention — for example: "[Enzo](url) amenities include: …". Do NOT add a trailing "tap the link" sentence — the link is a quiet affordance, not the answer. End with a conversational follow-up question. (3) Format each bullet: bold property name — price (or price range) — any UNIQUE highlight specific to that listing (e.g., "rent special: 1 month free", "5-star rating", "newly built", "$0 deposit") — full address (street, city, state, ZIP). Put the address LAST so the unique highlight (the differentiator) is visually prominent before the longer geographic anchor. If there is no unique highlight, drop that segment entirely (name — price — address). Do NOT repeat per-listing the shared filter attributes (bedroom/bath count, pet policy, requested amenities, search-area city) that already appear in the summary opener — those are noise when repeated on every bullet. The address IS allowed (and expected) per-listing because each property's street address is unique. Keep each bullet short. Never expose null fields as implementation details. (3a) Consolidate the user's filter criteria (petFriendly, bedrooms/baths range, price range, requested amenities, propertyType, hasBookableTour, hasSpecialOffer, location) INTO the summary opener (rule 3b) — NOT into the bullets. The opener should describe what every result has in common; bullets show only what differs (name + price + unique offer/highlight). Skip filters the user did not ask about. If the user named no filters, fall back to the search location (e.g. "in <city>"). (3b) On pageNumber=1, the opener depends on listings.length: • 1 result: "<Property Name> matched your search criteria of <filters>." e.g. "The Atlantic Buckhead matched your search criteria of pet-friendly 2-bed rentals in Atlanta under $2,000." • 2 results: "<Property A> and <Property B> matched your search criteria of <filters>." e.g. "The Atlantic Buckhead and MA Gardens matched your search criteria of rentals with a gym in Brooklyn." • 3+ results: "There are various places with <filters> — here are the top 3." e.g. "There are various places with pet-friendly 2-bed rentals in Atlanta under $2,000 — here are the top 3." DO NOT mention totalResults or any specific number to the user — use "various places" regardless of the actual count when there are 3+. Always refer to the results as "rentals" (never "matches" or "listings") inside <filters>. (4) If totalResults is 0, tell the user naturally and suggest broadening filters. (5) Do not call listing.details automatically — wait for the user to select a property. (6) Never call this tool during an active lead or tour flow — use the listingKey already in context. (7) Set viewMode='map' WHENEVER the user's message mentions a map in ANY form — not just the exact phrase "show me on map". Trigger on any of: "map", "on the map", "on a map", "map view", "see on map", "show on map", "plot on map", "pin", "markers", "where are they", "where is this on the map", "nearby on map", and similar phrasings. Omit viewMode (or set to 'list') only when the user makes no map reference at all. viewMode controls the UI rendering only — pageSize is always 50 regardless of viewMode.
search.listings
Resolves a search term to a property or location. Call this in two scenarios: 1. User mentions a specific property/apartment name → typeahead identifies the property → leads to residentialForRent → listing.details (full property detail) 2. User searches by neighborhood, POI, zip code, or address (anything that is NOT a plain city name) → typeahead resolves it, then routes based on MatchType: - Property address → if resolved to a property (MatchType 1, 4, 13, or 20) → residentialForRent → listing.details - Neighborhood / POI / zip / street → resolves to city+state → search.listings IMPORTANT: If the user mentions a specific property name (e.g. "Enzo", "Avalon", "Camden"), always call this tool — even if they also mention a city like "in Irvine". The city is location context for the property search, not the search target itself. Only use search.listings directly when the user searches by city name ALONE with no specific property name. Examples that MUST call this tool: - find me Enzo apartment in Irvine (property name → leads to listing.details) - show me Avalon apartments near Austin (property name → leads to listing.details) - 123 Main St, Irvine CA (property address → MatchType 1/4/13/20 → residentialForRent → listing.details) - apartments in Turtle Rock (neighborhood → resolves to city+state → search.listings) - near Irvine Spectrum (POI → resolves to city+state → search.listings) - apartments near 92612 (zip code → resolves to city+state → search.listings) - near UCI (POI → resolves to city+state → search.listings) Examples that should NOT call this tool (use search.listings instead): - apartments in Irvine (city name only — no specific property name) - 2BR in Newport Beach (city name only — no specific property name) When calling this tool: - Set keyword to the property name, neighborhood, POI, zip code, or address only. Do NOT include words like "apartment", "near", "in" in keyword. Examples: "Enzo apartment in Irvine" → keyword: "Enzo"; "near UCI" → keyword: "UCI" - Include stateCode when you can infer it, in this order: 1. Explicitly stated in the current prompt ("in Irvine" → "CA", "in Austin" → "TX") 2. User's current location — if the host provides the user's location, use that state 3. Prior conversation context — state from the most recent search or location mentioned 4. No state context available → omit stateCode and call the tool anyway. If multiple properties are returned across states, the user will pick from the disambiguation list. - Include centerPoint when you have coordinates from a prior search result. After receiving the result, route based on count and MatchType: - If count=0 (no results found): If the user's original prompt contains a city name: call search.listings with { location: { city, administrativeArea1, countryCode: "US" } } extracted from the prompt, plus all user-specified filters (bedrooms, price range, amenities — do NOT drop them). If no city is available in the prompt: tell the user no results were found for their search term and ask them to refine it (check spelling, try a different name, or search by city instead). - If MatchType is a Property type (1, 4, 13, or 20): If count=1: call residentialForRent immediately with the returned matchKey. If count>1: the result has status="awaiting_selection" and a disambiguationId. Present the numbered displayOptions list to the user and wait. Do NOT call residentialForRent or any other tool — there is no matchKey. After the user picks, call typeahead.resolve with the disambiguationId and the user's selection. That returns the matchKey and MatchType. Then call residentialForRent with those values. - If MatchType is any other value (neighborhood, POI, zip code, etc.): typeahead has resolved the search term to a city+state — now call search.listings: If city and state are present: call search.listings with { location: { city, administrativeArea1, countryCode: "US" } } AND all user-specified filters from the original prompt (bedrooms, price range, amenities — do NOT drop them) If city or state is missing: ask the user which city they want to search in, then call search.listings with the user's answer AND all user-specified filters from the original prompt
typeahead
How do I improve a ChatGPT Plugin's discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are Apartments.com alternatives on ChatGPT?
As of 2026-08-14, Apartments.com competes with Apartment List, atHome, Barfoot & Thompson Homes, Bayut, Bayut KSA, Boligsiden, CHINTAI, CliqueiMudei, Cogedim, Daft.ie, Din Bostad, Emlakjet, Engel & Völkers, Figaro Immobilier, Fotocasa, Greystar Apartment Scout, Hausmann Immobilien, Hemnet, hepsiemlak, HouseToSpot Immobilien, Housing.com, idealista, IMEB - Eva Buchholz, Immo der VR Bank Rhein-Neckar, Immobilien Franzen, Immobilien immoprofessional, ImmoScout24, Imovirtual, Imóveis Magiko IA, Jitty Property Search, KLINGER Immobilien, Klinger-Vogt Immobilien, Loft, Lott Immobilien, Lume, MiMove, MRV, MYCOlive, NEBLES, NewHomeSource, novostavby.ai, Off Plan AI, Pararius, Property24.com, QuintoAndar, realestate.com.au, Realtor.com, Red Estelar, Redfin, REMAX, Rentals.ca Rental Search, RentalSource, RentCafe, RIFO Home, Rightmove, robin, Seeki, Sergic Search, Spotahome, Square Yards, Tessun Immobilien, Trade Me Property, uhomes.com, VON POLL IMMOBILIEN, Zap Imóveis, Zealty, Zillow, Zoopla, Zumper, Реалистимо in ChatGPT Residential Property Listing Portals, ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.