On dedicated hardware the system WebView is a liability: it is replaced underneath your app, it differs across every model in the fleet, you cannot state what it contacts, and on cheap or old units it is ancient and unupdatable. Cefrium puts a full Chromium engine inside your APK, so the kiosk renders the same way everywhere and changes only when you publish.
That split is how real kiosks are built, and it is the point: the customer-facing UI changes weekly -- prices, promotions, seasons, languages -- while the shell (screen pinning, peripherals, provisioning, update channel) barely changes. Update a fleet by publishing a page, not by shipping an APK to hardware you may not reach.
One page, two engines, same device, same moment. The page detects its own capabilities, so nothing is asserted by the app. Rows that need a gesture or a permission render a VERIFY button instead of a verdict -- tap it and watch the probe resolve.
Measured on a tablet in October 2026. The argument is predictability, not freshness: the engine only changes when you publish, so a fleet renders identically whatever each unit happens to carry. Freshness becomes an argument too on the old hardware kiosks actually run on, where the WebView stopped updating years ago and cannot be updated.
The comparison page deliberately uses conservative CSS. If it used the latest features it would fail on an old WebView and measure the author's stylesheet instead of the engines.
This is where a pinned engine stops being a preference. An obsolete tablet's WebView cannot be updated, so whatever shipped with the device is what a web UI gets, forever. Cefrium carries its own engine, so a modern interface runs on hardware the platform gave up on.
The engine contacts exactly two endpoints that are not your app's own traffic, and both are documented and opt-out. The screen keeps the audited list and the live measurements visually separate on purpose, so nobody assumes the audit is as fresh as the measurement.
git clone https://codeberg.org/cefrium/cefrium-sample
cd cefrium-sample/kiosk-pos
./gradlew assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk
The sample pulls the SDK from the Maven registry, so there is nothing else to fetch. JDK 25 is required.
P=com.cefrium.pos
adb shell am start -n $P/.POSActivity
adb shell am start -n $P/.EngineCompareActivity
adb shell am start -n $P/.CarKioskActivity
adb shell am start -n $P/.AttestationActivity
The comparison screen opens the Cefrium side; its button adds the system-WebView side alongside it in split screen.
CefriumWebView(
url = "https://kiosk.example.com",
modifier = Modifier.fillMaxSize()
)
That is the whole integration. The shell keeps the device concerns; your page keeps the interface.
startLockTask() // screen pinning
Screen pinning is what makes a kiosk deployable: a customer or passenger cannot leave the app. Without device-owner provisioning Android asks for confirmation the first time; a provisioned fleet device pins silently.
DeviceMotionEvent, which works.If you need a signed statement of a release's network behaviour, or a validated configuration for an air-gapped deployment kept current with security updates, get in touch.