AI Search Classic Contensis Implementation
Log in to add to favouritesPage last updated 28 July 2026
Add AI-powered search to a classic Contensis site with a single script tag. The widget is a custom element (<insytful-search>) you drop straight into a Razor view or layout.
1. Add the script
<script src="https://unpkg.com/insytful-ai-search-components@2.2.0/dist/insytful-search.js"></script>Pin the version number so a future release can't change behaviour on your site without you opting in.
2. Add the markup
@{
const string InsytfulAISearchTheme = @"
.insytful-root {
--insytful-font-family: 'Helvetica Neue', Arial, sans-serif;
--insytful-brand-primary: #da3949;
--insytful-btn-icon-search-bg-default: #da3949;
--insytful-btn-icon-search-bg-hover: #bf2f3d;
}
";
}
<style>
insytful-search:not(:defined) { display: none; }
</style>
<insytful-search
api-uri="@CurrentContext.Site.AI.Endpoint"
project-id="@CurrentContext.Site.AI.ProjectId"
suggestions-position="below"
theme="@InsytfulAISearchTheme"
>
<button slot="trigger">Search this site</button>
<span slot="title">Ask our AI</span>
<span slot="description">Get instant answers about our courses and services</span>
<span slot="disclaimer">AI responses may not always be accurate. Please verify important information.</span>
<insytful-close></insytful-close>
<img slot="avatar" src="/logo.png" alt="" width="32" height="32" />
<insytful-suggestion>How do I apply?</insytful-suggestion>
<insytful-suggestion>What courses do you offer?</insytful-suggestion>
<insytful-suggestion>Contact us</insytful-suggestion>
<insytful-mode name="ai">AI Search</insytful-mode>
<insytful-mode name="classic" path="/search/index.aspx?search_keywords=">Classic Search</insytful-mode>
</insytful-search>Note: api-uri and project-id come from your Insytful backend config. Get these values from your account manager, or contact support. Since these are Razor context values rather than literal strings, make sure they're prefixed with @ (e.g. @CurrentContext.Site.AI.Endpoint) so Razor evaluates them instead of rendering the property path as plain text.
insytful-search:not(:defined) { display: none; }hides the element until the script has loaded, avoiding a flash of unstyled content.- The
<insytful-mode name="classic" ...>block is optional — include it only if you want a fallback link to your existing classic search results page alongside the AI answer.
3. Wire it up to an existing search box (optional)
If your site already has a search input in the header, you can route it into the AI dialog instead of building a second entry point:
const element = document.getElementById('ai-search');
const input = document.getElementById('search');
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
element.open(input.value.trim());
}
});
4. Theming
Everything is styled through CSS custom properties (--insytful-*) set inside the theme attribute, as shown in step 2. Common ones to set for a rebrand:
| Variable | Controls |
|---|---|
--insytful-brand-primary | Accent color (e.g. blockquote border in AI answers) |
--insytful-btn-icon-search-bg-default / -hover | Send button color |
--insytful-font-family | Widget typeface |
--insytful-modal-radius | Dialog corner rounding |
--insytful-semantic-focus-ring | Focus outline color across every interactive element |
5. Attributes at a glance
| Attribute | Required | Purpose |
|---|---|---|
api-uri | Yes | RAG API endpoint |
project-id | Yes | Project identifier for the RAG API |
theme | No | Inline CSS string for branding (see above) |
suggestions-position | No | "above" (default) or "below" the input |
sections | No | Comma-separated section slugs to scope results |
dev-mode | No | Mocks responses so you can build/test the UI before the backend is live |
6. Testing without a live backend
Add dev-mode to the element while your RAG endpoint is still being set up — it returns canned streamed responses so you can check layout, theming, and copy independently of the backend team's timeline. Remove it before going live.
<insytful-search api-uri="..." project-id="..." dev-mode>
7. Slots
| Slot | Description |
|---|---|
trigger | Button that opens/closes the dialog |
title | Heading text for the empty state |
description | Subheading text below the title |
disclaimer | Footer text (e.g. AI accuracy warning) |
logo | Image shown in the dialog empty state (not in messages) |
avatar | Image shown next to AI responses and the typing indicator |
8. Child elements
<!-- Suggestion chips (shown before the first query) -->
<insytful-suggestion>How do I apply?</insytful-suggestion>
<!-- Close button (top-right inside the dialog).
Empty content uses the default X icon; or pass your own markup. -->
<insytful-close></insytful-close>
<insytful-close aria-label="Dismiss search">Cancel</insytful-close>
<!-- Avatar shown next to AI responses in the chat -->
<img slot="avatar" src="/logo.png" alt="" width="32" height="32" />
<!-- Mode switching (AI search + classic URL navigation) -->
<insytful-mode name="ai">AI Search</insytful-mode>
<insytful-mode name="classic" path="/search?q=">Classic Search</insytful-mode>
- The close button lives inside the dialog (focus-trap-aware) and is styled via
--insytful-btn-close-*variables. - The avatar appears next to each AI response and the typing indicator. On desktop it sits as a column beside the message; on mobile it floats left so the first line of text wraps beside it and subsequent content flows full width. Style the wrapper via
.insytful-search-message-logoin your theme CSS.
9. JavaScript API
const element = document.querySelector('insytful-search');
// Open/close programmatically
element.open(); // open the empty dialog
element.open('query'); // open and immediately send a query
element.close();
element.toggle();
// Check state
console.log(element.isOpen);
// Override markdown rendering
element.renderMarkdown = (md) => myCustomParser(md);
// Listen for events
element.addEventListener('insytful-open', () => console.log('Opened'));
element.addEventListener('insytful-close', () => console.log('Closed'));
element.addEventListener('insytful-search', (e) => console.log('Query:', e.detail.query));
element.addEventListener('insytful-message', (e) => console.log('Response:', e.detail.content));
element.addEventListener('insytful-mode-change', (e) => console.log('Mode:', e.detail.mode));
element.addEventListener('insytful-error', (e) => console.log('Error:', e.detail.error));
10. Dynamic offsets (sticky headers)
If your site has a sticky header, add data-insytful-modal-offset so the dialog doesn't overlap it:
<header data-insytful-modal-offset>Your sticky header</header>
The modal measures their combined height via ResizeObserver and adjusts its top offset automatically — no manual pixel values to maintain.