# 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