Luxury property insights, tailored suggestions & a 24/7 AI Concierge — one script tag.
Add this once, ideally just before </body>, on every page where you want any of the AI features:
<script src="https://dexa.devsspace.com/widget.js"></script>
The script is ~10 KB, has no dependencies, and does nothing until you initialize one of the three contexts below.
Shows a pre-computed, investor-grade AI analysis of the property the visitor is viewing —
positioning summary, estimated gross rental yield, price per area (computed from listing data),
ROI potential, market outlook, investor highlights and risk considerations.
Place an empty container where the summary should appear (e.g. under the listing description),
then initialize it with the listing's uniqueIdentifier (the unique
reference from the property feed). Results are cached server-side, so repeat page loads are instant and cost nothing.
Pilot scope: this experimental integration is enabled for 50 selected Chestertons properties. For any other reference the widget automatically shows: "This is an experimental feature currently available for selected properties only."
<!-- 1. Container in your property template -->
<div id="ai-insights"></div>
<!-- 2. Initialize with the current listing's data -->
<script>
new AIPropertyInsights({
container: '#ai-insights',
propertyRef: '86818712', // the listing's uniqueIdentifier from the feed
themeColor: '#1e3c72'
});
</script>
Tip: on Chestertons, populate propertyRef from the listing template's uniqueIdentifier field — no property data needs to be passed; the platform already has the listing details. (Which identifier field is used will be configurable per client at onboarding.)
Recommends similar properties to the one being viewed, using vector similarity against the property database. Place a container in your sidebar or below the listing:
<!-- 1. Container -->
<div id="ai-suggestions"></div>
<!-- 2. Initialize -->
<script>
new AIPropertySuggestions({
container: '#ai-suggestions',
propertyRef: '86818712', // current listing — used to find similar ones
// Link each suggestion card to its listing page.
// {ref} is replaced with the property's uniqueIdentifier.
propertyUrlPattern: 'https://www.chestertons.com/en-ae/property-for-sale/{ref}',
linkTarget: '_self', // '_blank' to open in a new tab (default: '_self')
heading: 'You may also like',
themeColor: '#1e3c72'
});
</script>
Matching criteria: each candidate is scored against the property being viewed — location 35%, property type 25%, price closeness 25%, bedroom count 15%. If the visitor has browsed other pilot properties, their browsing profile (recency-weighted, kept in the browser's localStorage only) contributes 35% of the final score, with the current listing contributing 65%. Already-viewed properties are not re-suggested. Unsupported references show the experimental-feature notice.
Headless mode — if you want to render the suggestion cards yourself
(e.g. using your own property card template), omit container and pass an
onResults callback instead:
<script>
new AIPropertySuggestions({
propertyRef: '86818712',
onResults: function(refs, suggestions, meta) {
// refs — string[] property uniqueIdentifiers in ranked order
// suggestions — object[] full data: { ref, title, city, price, currency,
// bedrooms, bathrooms, area, areaUnit, type,
// saleType, thumbnail, similarity }
// meta — { explanation? } AI-generated match reason (if smart
// suggestions are enabled for this tenant), or
// { message? } when no results found
console.log('Top match:', suggestions[0]);
if (meta?.explanation) console.log(meta.explanation);
}
});
</script>
A floating multi-lingual chat widget that answers property questions, calculates ROI and captures after-hours leads. No container needed — it attaches itself to the bottom-right corner of the page:
<script>
new AIConciergeWidget({
themeColor: '#1e3c72',
welcomeMessage: 'Welcome to Chestertons! How can I help you today?',
// Optional: 2-4 starter chips shown under the welcome message, so a
// visitor can start the conversation with a tap instead of typing.
// Omit to use the tenant's admin-panel configuration, or the
// built-in defaults ("What areas do you cover?", "Speak to an agent").
starterChips: ['What areas do you cover?', 'Speak to an agent', 'Book a viewing'],
// Optional: on a property page, pass the listing reference so the
// concierge answers questions about THIS property specifically
propertyRef: '86818712',
// Optional: welcome message shown instead of welcomeMessage when
// propertyRef is set. Defaults to "Ask me anything about this
// property — price, size, the area, or arranging a viewing."
propertyWelcomeMessage: 'Ask me anything about this Marrakech villa.',
// Optional: chips for a property page. The generic starterChips above
// are suppressed on a property page unless propertyChips is set here
// instead — a single-listing conversation rarely wants "What areas
// do you cover?".
propertyChips: ['Book a viewing', 'What is the service charge?'],
// Optional: overrides the listing URL format set in the admin panel.
// Only needed to vary it per page or locale.
propertyUrlPattern: 'https://www.chestertons.com/en-ae/property-for-sale/{ref}',
linkTarget: '_self', // '_blank' to open in a new tab (default: '_self')
// Optional: a small proactive speech-bubble teaser beside the launcher,
// showing the opening line + starter chips before the visitor has done
// anything. OFF by default for a brand-new tenant — opt in per tenant in
// the admin panel, or per page here.
teaser: {
enabled: true, // default: false
trigger: { type: 'delay', delayMs: 8000 }, // 'delay' | 'scroll' (scrollPct) | 'exit'
propertyDelayMs: 4000, // used instead of trigger.delayMs on a property page
dismissDays: 7, // how long a dismissal is remembered
autoOpenDesktop: false, // true: open the full panel instead of the teaser (desktop only)
mobileMaxWidth: 768, // <= this width is "mobile": teaser only, never auto-open
message: null // optional override; falls back to the welcome copy above
}
});
</script>
On general pages (home, search results) omit propertyRef — the concierge acts as a general agent. On listing pages include it so answers are grounded in that property. If the reference is outside the 50-property pilot, the chat shows the experimental-feature notice.
Property results in chat. When a visitor asks for properties — "3 bed villas in Dubai under 9 million" — the concierge searches your listings and shows the matches as cards under its reply, instead of describing them in prose. It only ever names properties that are actually in your feed. The cards become clickable once a listing URL format is set; that is normally configured once in the admin panel, so propertyUrlPattern here is only for overriding it. With no pattern set anywhere, the cards still show — just without links.
Welcome copy and chips. welcomeMessage and propertyWelcomeMessage support light markdown (**bold**, and a blank line for a paragraph break) and render safely — anything else in the text (including stray HTML) shows up as plain visible text, never as markup. Both, plus starterChips, can also be set once for the whole tenant in the admin panel instead of per page; a value passed here always wins. propertyChips is page-level only (there is no tenant-wide default for it) since it usually makes sense to vary per listing type. Starter chips disappear as soon as one is tapped, and never reappear if the visitor already has an in-progress conversation from an earlier page.
Proactive teaser. Off by default (teaser.enabled: false) — a brand-new tenant's pages carry no teaser and no trigger is even installed. Once opted in, it appears beside the launcher after the configured trigger (a plain delay, a scroll percentage, or exit-intent — a touch device never arms exit-intent, since there is no meaningful mouseout there), shows the same opening line and starter chips the panel itself would, and a chip tap opens the panel and sends that question in one action. On a viewport at or under mobileMaxWidth only the teaser ever appears — the full panel never auto-opens there, even with autoOpenDesktop: true. It is suppressed for the rest of the browser session once shown, and for dismissDays after an explicit dismissal, but — deliberately — not for a visitor who has already shared their contact details, since those are exactly the returning buyers worth re-engaging. It never takes keyboard focus away from the page (no .focus() call), respects prefers-reduced-motion, and reads with a screen reader as a plain, tabbable element — not an announced dialog.
Everything together, as you would place it on a listing page (e.g. preprod.chestertons.com):
<!-- containers, placed where you want them in the layout -->
<div id="ai-insights"></div>
<div id="ai-suggestions"></div>
<!-- before </body> -->
<script src="https://dexa.devsspace.com/widget.js"></script>
<script>
// The listing's uniqueIdentifier from your template
var propertyRef = '86818712';
new AIPropertyInsights({ container: '#ai-insights', propertyRef: propertyRef, themeColor: '#1e3c72' });
new AIPropertySuggestions({ container: '#ai-suggestions', propertyRef: propertyRef, themeColor: '#1e3c72',
propertyUrlPattern: 'https://www.chestertons.com/en-ae/property-for-sale/{ref}' });
new AIConciergeWidget({ themeColor: '#1e3c72', propertyRef: propertyRef,
welcomeMessage: 'Welcome to Chestertons! How can I help you today?' });
</script>