# AeroIDX — LLM Integration Reference
# Version: 3.0 | Source of truth for all AI-assisted integrations
# Canonical URL: https://app.aeroidx.com/ai-ref/llms.txt
# Encoding: UTF-8 (always)
# Component docs: https://app.aeroidx.com/ai-ref/components/{tag}.md
---
## REFERENCE PROTOCOL — COMPLETE BEFORE WRITING ANY CODE
STOP. Do NOT write code until ALL steps below are confirmed done.
Step 1. READ this file in full — you are reading it now if it was fetched.
Canonical URL: https://app.aeroidx.com/ai-ref/llms.txt
If your environment supports URL fetching, fetch the live version to get the
most up-to-date rules. If not, continue — the rules in your prompt are current.
Do NOT stop or report an error just because you cannot browse a URL.
Step 2. IDENTIFY components you will use.
Step 3. FETCH each component's doc BEFORE using it (if your environment supports it):
https://app.aeroidx.com/ai-ref/components/{tag}.md
Extract: props table, required props, GOTCHA sections.
If unreachable: use ONLY the props listed in the COMPONENTS section of your prompt.
Do NOT invent props. Do NOT stop.
Step 4. USE ONLY props listed in the doc. Do NOT invent, guess, or assume any attribute.
Step 5. VERIFY: Before finalizing, check every attribute in your HTML against the prop
table. Remove any attribute not explicitly listed there.
CHECKPOINT: Steps 1–5 must be complete before you output a single line of AeroIDX code.
---
## ENCODING RULES — MANDATORY
The server that hosts AeroIDX pages MUST serve all responses with UTF-8 encoding.
Failure causes garbled text in component labels, search results, and notifications.
REQUIRED HTTP response header on every page:
Content-Type: text/html; charset=UTF-8
For nginx, add in server block:
charset utf-8;
For Apache, add to .htaccess:
AddDefaultCharset UTF-8
For any CMS (WordPress, Webflow, Squarespace), verify that the theme outputs
in
and that server headers agree.
FORBIDDEN: Do NOT serve pages without a charset declaration.
FORBIDDEN: Do NOT use ISO-8859-1 or any encoding other than UTF-8.
---
## What Is AeroIDX
AeroIDX is a white-label real estate IDX platform delivered as a set of
Web Components (Vue 3 Custom Elements). Clients embed a single
```
This single script tag is all that is required. The exact placement method varies
by website builder; for custom-coded sites, place it directly in .
IMPORTANT: This script must be on every page that uses any AeroIDX widget or component.
### Step 3 — Create the /aeroidx fallback router page
Create a page at the path /aeroidx and place this component inside it:
```html
```
This page acts as a router. If a user navigates to a path that doesn't have a
dedicated AeroIDX page, the request is routed through /aeroidx. For example, if
the site has no /search page, the search experience loads at /aeroidx?page=search.
### Step 4 — Create dedicated component pages
Create the following pages, each containing the corresponding component:
```
/search →
/details →
/sign-in →
/my-account →
/featured →
```
Team accounts (not Single accounts) also get:
```
/roster →
/agent →
```
Apply a min-height to each component's container to prevent layout shift while
the widget loads (e.g. min-height: 600px).
Every page that contains an AeroIDX component must include the Step 2 script tag.
### Step 5 — Mark pages as complete
AeroIDX has no way to detect which pages exist on the website. The user must
manually mark each page as complete at:
https://app.aeroidx.com/website/pages
### Step 6 — Add the sign-in button to the header
Once pages are marked complete, add the sign-in widget to the site header or
navigation on every page:
```html
```
See the POSITIONING RULES section below for critical placement constraints.
---
## Development and Staging Workaround
To use AeroIDX components on a domain that is NOT the registered production domain
(staging, local dev, a preview URL), add the data-base-url attribute:
```html
```
Set data-base-url to the registered production domain. This tells the components
to make API requests as if running on the production domain, while still rendering
on the staging environment.
Other supported data-* attributes on the script tag:
- data-base-url (optional) — override API base URL for dev/staging
- data-locale (optional) — e.g. "en-US"
- data-debug (optional) — "true" enables verbose console logging
---
## Attribute Naming Convention
Vue props use camelCase internally. In HTML attributes, use kebab-case:
Vue prop → HTML attribute
accountSettingsId → account-settings-id
primaryColor → primary-color
newTab → new-tab
borderRadius → border-radius
widgetId → widget-id
featuredListings → featured-listings (or featured_listings — both work)
---
## Widgets Overview
AeroIDX widgets accept configuration directly on the component element:
```html
```
The recommended approach is to use the widget builder at
https://app.aeroidx.com/widgets. Users can configure widgets visually and get
a generated embed code with a widget-id that loads saved configuration:
```html
```
### Common Home Page Setup
Most websites need three widgets on the home page:
**1. Search bar in the hero section**
The search bar is embedded inside other components (listing-results, search-widget).
On the home page, use one of the standalone search widgets:
```html
```
**2. Featured listings carousel**
```html
```
**3. Market areas showcase**
Displays the markets the agent or office covers, each with a representative photo.
The user creates the markets in the AeroIDX dashboard and uploads a photo for each.
```html
```
**4. Showcase slider**
Display a full width slider that spotlights one property per slide
```html
```
---
## Quick Reference by Use Case
### Shell (required on /aeroidx page)
### Standard property search form
### AI-powered search
— compact single-line widget (FIXED 600px width — NOT responsive)
— expanding textarea bar (fully responsive — use in hero/full-width sections)
— floating launcher + slide-out drawer (recommended for mobile)
### Browse and display listings
— horizontal swipeable carousel
— responsive grid
— Mapbox map with clusters
### Search results pages
— non-OMNI MLS (Repliers external data); place at /search
— OMNI MLS boards (local replication)
### Property detail page
— reads ?id= from URL automatically; place at /details
### User account and auth
— header/nav (every page) ⚠ read positioning rules below
— dedicated sign-in page; place at /sign-in
— account dashboard; place at /my-account
### Market content
— featured/supplemental property grid; place at /featured
— market snapshot for a saved search
— extended analytics version
— visual grid of market areas
### Office / team (Team accounts only)
— full agent directory; place at /roster
— individual agent page; place at /agent
### Utilities
— admin widget config UI
---
## POSITIONING AND STACKING CONTEXT RULES — CRITICAL
These rules are NOT optional. Violating them breaks dialogs, drawers, and toasts.
Read every rule before placing any AeroIDX component.
### UNIVERSAL RULE — Stacking Context Killers
NEVER wrap any AeroIDX component in a parent that has ANY of these CSS properties:
- transform: (any value including transform: none on some browsers)
- backdrop-filter: (any value)
- filter: (any value except none)
- perspective: (any value)
- will-change: transform
- contain: layout | paint | strict | content
- isolation: isolate
These CSS properties create a new stacking context that TRAPS position:fixed children
inside the element's bounding box instead of the viewport. The result is overlays
that scroll with the page, drawers that clip at the parent edge, and toasts that
misalign.
Common culprit: sticky/fixed headers with backdrop-blur (e.g. Tailwind's
`backdrop-blur-sm` or `backdrop-filter: blur(8px)`).
---
### — Positioning Rules
INTERNAL STRUCTURE:
- Login dialog: position:fixed inset-0, z-index:100 (covers full viewport)
- Dropdown menu: position:absolute, z-index:999 (anchored to button)
RULE 1 — Place as a SIBLING of the header, NOT a child.
The component must NOT be nested inside any element with backdrop-filter,
transform, filter, or will-change:transform.
RULE 2 — Do NOT apply position:relative to the direct parent of
unless you explicitly need to anchor the dropdown.
RULE 3 — Any ancestor with overflow:hidden WILL clip the dropdown. Never put
inside a container with overflow:hidden or overflow:clip.
RULE 4 — Do NOT set a fixed z-index on the parent lower than 100.
CORRECT placement:
```html
```
WRONG placement:
```html
```
---
### — Positioning Rules
RULE 1 — Place as a direct child of or the root layout
wrapper. It MUST NOT be inside any element with a stacking context.
RULE 2 — Required prop: account-settings-id. Without it, AI search calls will fail.
RULE 3 — Only ONE per page.
CORRECT placement:
```html
...
```
---
### (standalone page) — Container Rules
RULE 1 — The page that hosts MUST have available viewport height.
Wrap it in a container that has at minimum:
```html
```
RULE 2 — Do NOT set max-height on the parent. The component uses min-height:80vh.
---
### — Width Rules (FIXED 600px)
RULE 1 — has a FIXED width of 600px. It does NOT respond to
its container's width. Ensure the parent provides at least 600px.
RULE 2 — On viewports narrower than 600px (mobile), use instead.
NOTE: is a DIFFERENT component — it uses an expanding textarea and is
fully responsive. Use for hero sections and full-width inline search.
---
## Known Gotchas
### Dropdown menus clipped by parent overflow:hidden
Any AeroIDX component that renders a dropdown (sign-in-button, search-widget,
ai-search-widget) will have its dropdown clipped if any ancestor has overflow:hidden
or overflow:clip.
Fix: Remove overflow:hidden from ancestors, or use overflow:visible. If you need
overflow:hidden for layout reasons, move the AeroIDX component outside that container.
### Safari: position:fixed inside transformed ancestors
Safari (iOS and macOS) does not conform to the CSS spec on position:fixed inside
transformed ancestors. Always test on Safari.
### CSS Custom Properties and Shadow DOM
AeroIDX components use Shadow DOM. Standard CSS rules from the host page do NOT
pierce Shadow DOM. To theme components, use CSS custom properties (variables)
documented in each component's doc page, or pass props directly.
Do NOT attempt to target internal elements of AeroIDX components with CSS selectors
like `.sign-in-button .dialog` — these selectors will not work.
### in sticky headers with backdrop-filter
A sticky header with `position: sticky; backdrop-filter: blur(8px);` creates a
stacking context. Any position:fixed child is trapped inside the header's bounding
box. The login dialog appears clipped at the header height.
The ONLY correct fix is to move OUTSIDE the header DOM subtree.
### z-index stacking order
AeroIDX components use these z-index values internally:
- Dropdown menus: z-index: 999
- Dialogs and drawers: z-index: 100
- ai-search-drawer launch: z-index: 50
- Toaster: z-index: 99999
Recommended page z-index budget:
- Sticky header: z-index: 40 (below drawer launcher)
- Page modals: z-index: 90 (below AeroIDX dialogs)
- Cookie banners: z-index: 150 (above AeroIDX dialogs if needed)
---
## aero-idx Internal Pages (URL routing via ?page= param)
?page=search → ListingResults or SearchResults (OMNI)
?page=listing → ListingDetailsThemed (property detail)
?page=saved-link → SavedLink (market snapshot)
?page=market → SavedLink (alias)
?page=my-account → UserProfile (account dashboard)
?page=supplemental-featured→ SupplementalFeaturedResults
?page=sign-in → SignIn
?page=roster → Roster (agent directory)
?page=agent-listings → MemberListings (agent page)
?page=carousel → CarouselWidget (preview)
?page=ai-search-test → AiSearchWidget (preview)
?page=ai-search-drawer → AiSearchDrawer (preview)
(no ?page param) → displays "Setup Successfully" placeholder
---
## Global Window Objects
window.baseUrl
Type: string
Auto-detected from script src or current origin.
window.accountSettings
Type: object (from GET /api/initial-data/:domain)
.user.status "ACTIVE" | "DISABLED" | "TRIAL"
.mls_boards[].name Board name; "OMNI" in name = OMNI path
.settings.lead_routing.attribution_method "first" | "last"
.settings.sign_in_modal.search_page_visits default: 3
.settings.sign_in_modal.details_page_visits default: 3
.page_configurations per-page custom path config
.component_settings per-component style overrides
.theme account-level theme name
window.propertyTypes
Type: array (from same /api/initial-data endpoint)
Used by search-widget for property type dropdowns.
window.aerolocalStorage
Type: object — safe localStorage wrapper
Methods: .getItem(key), .setItem(key, val), .removeItem(key)
window.injectPropertyMetaTags(listing)
Type: function — injects OG/Twitter Card meta tags for a listing
---
## Agent Attribution
localStorage key: current_agent_id — updated on every nav (last-touch)
localStorage key: locked_agent_id — set once, never overwritten (first-touch)
Pass via URL: ?agent_id=AGENT_IDENTIFIER
Pass via props: featured-agent-id | featured-agent-identifier
(supported on carousel-widget, gallery-widget, map-widget)
---
## Sign-In Modal Auto-Trigger
Configured in: window.accountSettings.settings.sign_in_modal
Tracked in: localStorage (search_page_count, details_page_count)
Default: triggers after 3 search page visits OR 3 detail page visits
---
## Light / Dark Mode
Apply class="dark" on any ancestor element.
All components use CSS custom properties that respond to .dark.
No JS toggle — purely class-based, controlled by the host website.
---
## Initialization Flow (automatic, inside components.js)
1. getInitialData() — GET /api/initial-data/:domain
sets window.accountSettings
sets window.propertyTypes
sets sign-in modal config
2. AgentManager.updateFromUrl()— reads ?agent_id= for first-touch attribution
3. registerCustomElements() — calls defineCustomElement() for every tag
4. checkSignInModal() — triggers modal after N page visits (configurable)
5. injectMetaTagsFromUrl() — injects OG/social meta tags from URL params
---
## Component Documentation Index
RULE: Fetch the doc for every component you use. The URL is the tag name exactly as
written below — do NOT guess, rename, or prefix with "aeroidx-".
WRONG examples (never do this):
aeroidx-app.md — WRONG (correct: aero-idx.md)
aeroidx-auth-button.md — WRONG (correct: sign-in-button.md)
aeroidx-listing-results.md — WRONG (correct: listing-results.md)
aeroidx-listing-detail.md — WRONG (correct: listing-details.md)
aeroidx-ai-search-hero.md — WRONG (correct: ai-search.md)
aeroidx-listing-carousel.md — WRONG (correct: carousel-widget.md)
aeroidx-roster.md — WRONG (correct: office-roster.md)
CORRECT URLs (use EXACTLY these):
Tag Doc URL
────────────────────────────────────────────────────────────────────────────────
https://app.aeroidx.com/ai-ref/components/aero-idx.md
https://app.aeroidx.com/ai-ref/components/listing-details.md
https://app.aeroidx.com/ai-ref/components/listing-results.md
https://app.aeroidx.com/ai-ref/components/search-listings.md
https://app.aeroidx.com/ai-ref/components/sign-in-button.md
https://app.aeroidx.com/ai-ref/components/sign-in.md
https://app.aeroidx.com/ai-ref/components/my-account.md
https://app.aeroidx.com/ai-ref/components/search-widget.md
https://app.aeroidx.com/ai-ref/components/ai-search-widget.md
https://app.aeroidx.com/ai-ref/components/ai-search.md
https://app.aeroidx.com/ai-ref/components/ai-search-drawer.md
https://app.aeroidx.com/ai-ref/components/carousel-widget.md
https://app.aeroidx.com/ai-ref/components/gallery-widget.md
https://app.aeroidx.com/ai-ref/components/map-widget.md
https://app.aeroidx.com/ai-ref/components/supplemental-featured-results.md
https://app.aeroidx.com/ai-ref/components/saved-link.md
https://app.aeroidx.com/ai-ref/components/saved-link-ex.md
https://app.aeroidx.com/ai-ref/components/office-roster.md
https://app.aeroidx.com/ai-ref/components/agent-listings.md
https://app.aeroidx.com/ai-ref/components/market-areas.md
https://app.aeroidx.com/ai-ref/components/showcase-slider-widget.md
---
## Design Skills Index
INSTRUCTION: When a design skill is specified, you MUST fetch the SKILL.md before
building any UI. The SKILL.md contains: colors (with exact hex tokens), typography
(font names, weights, scale), AeroIDX component theming props (exact attribute values),
animation library recommendations, layout patterns for real estate, and explicit
Do/Don't rules. Do NOT guess — always fetch the file.
Skills overview:
bento — Bento grid, warm off-white, Inter 800, one solid blue accent card
cafe — Warm cream, Playfair Display headings, pill buttons, dark brown
corporate — Monochromatic black+white, ultra-minimal, text links, no accent color
luxury — Pure black, Oswald ALL-CAPS, split hero (text left / photo right), gold micro-accent
modern — Dark (#0C0F14), deep purple, Inter 800, announcement badge, app preview
paper — White, Inter, black filled CTA, 3D visual below fold, no accent color
spacious — Full-bleed photo header, Bebas Neue ALL-CAPS, thick black rule, editorial columns
storytelling— Split-screen 50/50, Playfair italic chapter numbers, diagonal divider, earthy tones
SKILL.md URLs (fetch the one matching the requested skill):
https://app.aeroidx.com/ai-ref/skills/bento/SKILL.md
https://app.aeroidx.com/ai-ref/skills/cafe/SKILL.md
https://app.aeroidx.com/ai-ref/skills/corporate/SKILL.md
https://app.aeroidx.com/ai-ref/skills/luxury/SKILL.md
https://app.aeroidx.com/ai-ref/skills/modern/SKILL.md
https://app.aeroidx.com/ai-ref/skills/paper/SKILL.md
https://app.aeroidx.com/ai-ref/skills/spacious/SKILL.md
https://app.aeroidx.com/ai-ref/skills/storytelling/SKILL.md
---
---
## AeroIDX MCP Server
AeroIDX includes a Model Context Protocol (MCP) server that gives AI tools
real-time access to leads, CRM contacts, property data, and website setup actions.
Once connected, your AI can query live data and automate setup steps without
manual dashboard navigation.
### Server details
Server URL: https://app.aeroidx.com/api/mcp
Protocol: MCP over HTTP (Streamable HTTP transport)
Auth: OAuth 2.0 (recommended) or Bearer token (API key)
### Connecting — Claude (claude.ai)
Claude on the web supports MCP via OAuth. Requires a Claude Pro or Team plan.
1. Go to claude.ai → avatar → Settings → Customize → Connectors
2. Click "+" → "Add custom connector"
3. Set Name: AeroIDX
4. Set URL: https://app.aeroidx.com/api/mcp
5. Expand Advanced settings and enter your OAuth credentials:
- OAuth Client ID
- OAuth Client Secret
6. Click Add
Find your OAuth credentials in the AeroIDX dashboard at:
https://app.aeroidx.com/mcp-server
Verify by opening a new conversation and asking:
"Use AeroIDX to show me my leads from the last 7 days."
### Connecting — Cursor / Windsurf / other MCP clients (Bearer token)
These clients use a JSON config file with a Bearer token (API key).
1. Generate an API key at: https://app.aeroidx.com/api-keys
2. Add the following to your MCP config file:
- Cursor: ~/.cursor/mcp.json
- Windsurf: ~/.codeium/windsurf/mcp_config.json
```json
{
"mcpServers": {
"aeroidx": {
"url": "https://app.aeroidx.com/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
```
3. Restart the client after saving the config.
Verify by asking:
"Use AeroIDX to show me uncontacted leads from this week."
### What the MCP server can do
The server exposes 30 tools across four categories:
Leads (10) — daily leads, hot leads, uncontacted leads, property
viewers/savers, weekly stats, today summary, comparisons
GHL / CRM (14) — contacts, opportunities, appointments, tasks, notes, tags
Lead Management (3) — create and retrieve saved property searches
AeroIDX Integration (3)— generate integration prompts, update website domain,
mark integration pages complete
---
## AeroIDX MCP Tools — Website Setup Actions
When connected to the AeroIDX MCP server, AI agents have access to tools that
automate steps from the Integration Setup Guide. Use these INSTEAD of asking the
user to do these steps manually in the dashboard.
### update_website_domain
Purpose: Register or update the website domain in the AeroIDX account settings.
This is the domain that AeroIDX components will render on.
Corresponds to: https://app.aeroidx.com/website/setup (Step 1 of the setup guide)
Parameter:
domain (string, required)
The full production URL of the website.
Must include the protocol.
Examples: "https://example.com", "https://luxuryhomes.miami"
WRONG: "example.com", "/example.com"
Returns:
previous_domain — the domain that was registered before
new_domain — the domain that is now registered
When to call:
- When the user provides their website URL during setup
- When the user wants to change the registered domain
- Do NOT call if the domain is already correct
### mark_pages_complete
Purpose: Mark integration pages as complete in the AeroIDX dashboard.
AeroIDX cannot auto-detect which pages exist on the website;
they must be manually marked. This tool does it programmatically.
Corresponds to: https://app.aeroidx.com/website/pages (Step 5 of the setup guide)
Parameter:
pages (array of strings, optional)
The page keys to mark complete. If omitted, ALL pages are marked complete.
Valid values:
"search" — /search ( or )
"details" — /details ()
"sign_in" — /sign-in ()
"my_account" — /my-account ()
"featured" — /featured ()
"agent_listings" — /agent () — Team accounts only
"roster" — /roster () — Team accounts only
Returns:
marked — pages newly marked as complete this call
already_complete — pages that were already marked before this call
not_found — page keys not present in the account's configuration
When to call:
- After the user confirms they have created the page(s) on their website
- After generating and applying an integration prompt that includes those pages
- NEVER mark a page complete if the user has not yet created the page
Example usage pattern:
1. User says "I just added the search and details pages."
2. Call mark_pages_complete with pages: ["search", "details"]
3. Report back: which pages are now marked, which were already done
---
Additional guides:
https://app.aeroidx.com/ai-ref/integration.md — full step-by-step setup guide
https://app.aeroidx.com/ai-ref/configuration.md — global config, script tag options, window objects