Declarative Site Adapters
Site Adapters are JSON configurations that tell the Appilot extension how to behave on a specific web application. They solve a fundamental challenge: not all web apps work the same way.
The Problem
Standard web applications change their URL when users navigate between pages. Appilot uses URL patterns to match knowledge content to the current page. Some frameworks break that assumption. Vaadin, GWT, and Ext JS build single-page applications where the URL never changes. Form elements may be wrapped in Shadow DOM, and every user action triggers a server roundtrip.
Without adapters, the extension cannot:
- Know which page the user is on
- Find form fields inside Shadow DOM
- Interact with framework-specific components
The Solution
A Site Adapter provides structured rules that the extension runtime interprets. Nothing in it executes as code:
| Configuration | Purpose | Example |
|---|---|---|
runtime.shadow_dom_max_depth | How deep to traverse Shadow DOM | 6 for Vaadin (default: 3) |
runtime.action_timeout_ms | Wait time for DOM updates after actions | 3000 for server-roundtrip apps |
page_detection.rules | DOM-based view identification | Read menu bar text to determine current view |
interaction_overrides | Custom interaction strategies per component | Open-then-select for combo boxes |
knowledge_hints | Cross-cutting retrieval hints | Always include domain_global scope |
Schema
{
"schema_version": "1.0",
"domain": "your-app.example.com",
"framework_hints": ["vaadin"],
"runtime": {
"shadow_dom_max_depth": 6,
"action_timeout_ms": 3000,
"mutation_observer_debounce_ms": 500
},
"page_detection": {
"strategy": "dom_selector",
"rules": [
{
"selector": "vaadin-menu-bar [selected]",
"read": "innerText",
"map": {
"Online Services": { "view_path": "zufi/online-services" }
}
}
]
},
"interaction_overrides": {},
"knowledge_hints": {
"always_include_scopes": ["domain_global"]
}
}
Page detection resolves to a view path, which matches a view configured for the domain. Knowledge is linked to views, so retrieval is driven by view identity rather than by the URL.
How It Works
- Extension loads on a domain
- Fetches adapter config from
GET /apps/domains/adapter/lookup?domain=<hostname> - Caches locally (5-minute TTL)
- Applies runtime overrides (Shadow DOM depth, timeouts)
- Uses page detection rules to identify the current view (resolved to a
view_path) - Retrieves knowledge content linked to that view via
content_views - Uses interaction overrides for framework-specific components
Credential fields are out of reach
An interaction override changes how a field is driven, never whether it may be driven. Password fields, one-time-code fields, payment-card fields and hidden fields are decided by one rule that every reader and every writer consults, and an adapter cannot open them. That covers the paths an adapter exists for: a value written into a shadow-root input, a custom element whose host takes the value directly, and an open-then-select combo box. A read reports the field and whether it is filled; a write is refused.
If your application builds a password box out of something that is not a real form control, the rule cannot recognise it, which is worth knowing before you write an override that reaches it.
Extensibility
The strategy fields are extension points. Currently supported:
- Page detection:
dom_selector, which reads DOM elements to determine the current page - Interaction:
open_then_select, for combo boxes that need a click to open
Future strategies can be added without schema changes, because the extension dispatches to handlers based on the strategy name.
API Endpoints
| Method | Endpoint | Auth | Purpose |
|---|---|---|---|
GET | /apps/domains/adapter/lookup?domain=<name> | Public | Extension fetches config |
GET | /apps/domains/:id/adapter | JWT | Read adapter for a domain |
PUT | /apps/domains/:id/adapter | JWT | Update adapter config |