Browser-Backed Adapters
Keep the same SDK and MCP surface when the only reliable interface is the UI.
SiteKit prefers direct HTTP and GraphQL adapters because they are fast, portable, and stable enough for pipelines.
Some sites do not expose a useful backend interface. Important behavior may live inside frontend JavaScript, IndexedDB, WebSockets, canvas, encrypted payloads, or UI-only workflows. In those cases, SiteKit can still expose the same typed operations while executing them through a browser automation backend.
await expense_portal.expenses.createDraft({
employeeId: 'A123',
reportName: 'Quarterly field audit',
expenseType: 'Reimbursement',
amount: 146.52,
});The caller does not need to know whether that method uses HTTP, Playwright, or a hybrid implementation.
Backend Types
operations:
events.list:
backend: http
endpoint: searchEvents
sideEffects:
category: read
expenses.createDraft:
backend: browser
script: playwright/expenses/createDraft.ts
sideEffects:
category: create
externalEffects:
- submits_external_record
defaultMode: preview
requiresConfirm: true
reports.downloadCsv:
backend: hybrid
setup:
browserScript: playwright/reports/openReport.ts
endpoint: reportsCsv
sideEffects:
category: readhttp: call a discovered internal API directly.browser: drive the UI with Playwright.hybrid: use the browser to establish state, then call HTTP endpoints.
Playwright Scripts
Browser-backed operations are generated as reviewed scripts:
export async function createDraft(page, input) {
await page.goto('/expenses/drafts/new');
await page.getByLabel('Report name').fill(input.reportName);
await page.getByLabel('Expense type').selectOption(input.expenseType);
await page.getByLabel('Amount').fill(String(input.amount));
if (!input.confirm) {
return previewFromPage(page);
}
await page.getByRole('button', { name: 'Save draft' }).click();
return readCreatedReport(page);
}The script is deterministic code generated from adapter IR and reviewed before use. It is not an LLM browsing the site at runtime.
Runtime Tradeoffs
Browser-backed adapters are powerful, but they cost more:
- Slower execution.
- More infrastructure for cloud jobs.
- Higher sensitivity to copy and layout changes.
- More complex authentication and session management.
- More need for screenshots, traces, and selector drift reports.
SiteKit should recommend http when possible, hybrid when useful, and
browser when the UI is the only reliable contract.
Testing
Browser-backed tests should produce artifacts that make breakage obvious:
sitekit test expense_portal --live --traceexpense_portal.expenses.createDraft failed
Selector drift:
getByLabel("Expense type")
expected: select or combobox
found: no matching element
Last screenshot:
traces/expense_portal/createDraft/failed.pngFixture tests can still validate input schemas, transforms, and preview payloads. Live tests are needed to prove UI selectors and browser flows.
Deployment
HTTP adapters can run almost anywhere. Browser-backed adapters need an execution environment with browser support:
- Local scripts with Playwright installed.
- CI runners with browser dependencies.
- Cloud workers connected to a browser service.
- A dedicated SiteKit worker pool for team deployments.
The generated TypeScript and Python APIs stay the same. Only the adapter runtime requirements change.
Best Use Cases
Browser-backed adapters fit:
- Sites with no discoverable internal API.
- Workflows locked behind complex frontend state.
- Export screens that only produce files after UI interactions.
- Admin tools where the UI is the supported interface.
- Temporary bridges while an HTTP adapter is being repaired.
They should not be the first choice for high-volume reads when a direct API can be discovered. Pulling tens of thousands of records through a browser is a last resort.