
Playwright-inspired DSL for browser automation, enabling reusable UI workflows, locators, network interception, screenshots, session-state handling and an AI-agent command interface for compact control.
Browser automation for Kotlin Multiplatform. Write a workflow once and run it inside Android WebView, iOS WKWebView or JVM Chromium. Use a Playwright-inspired Kotlin API, or give an AI agent the same browser through compact commands.
Website · Documentation · Examples
[!NOTE] 0.0.1 alpha. Available on Maven Central. APIs and platform coverage may change.
Add to commonMain.dependencies in your module’s build.gradle.kts:
implementation("io.github.bernaferrari:kmpwright-core:0.0.1")One dependency covers Android, iOS and JVM. Gradle selects the platform variant.
Requires mavenCentral() in your project's repositories.
repositories { mavenCentral() }
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.bernaferrari:kmpwright-core:0.0.1")
}
}
}For the Android Compose wrapper, add this to androidMain.dependencies:
implementation("io.github.bernaferrari:kmpwright-compose:0.0.1")Fill a form, click its button and verify the rendered result. This demo uses a self-contained page, so it runs without a server or an account.
import com.bernaferrari.kmpwright.core.*
suspend fun demo(page: Page) = with(page) {
setContent(demoHtml)
getByLabel("Name").fill("Ada")
getByRole("button", name = "Say hello").click()
expect(getByRole("status")).toHaveText("Hello, Ada!")
}Result: the page displays Hello, Ada! and the assertion passes. Locators wait for actionable elements; assertions wait for the expected result. The same workflow runs on Android, iOS and JVM.
Define this alongside demo() in your shared Kotlin code:
val demoHtml = """
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>KMPwright demo</title>
<label for="name">Name</label>
<input id="name">
<button onclick="document.getElementById('greeting').textContent =
'Hello, ' + document.getElementById('name').value + '!'">Say hello</button>
<p id="greeting" role="status"></p>
</html>
""".trimIndent()Connect your platform's browser, then pass its Page to the shared workflow.
Run suspending APIs in a coroutine, on the main thread for mobile WebViews.
Android — attach to your app’s WebView:
Browser(AndroidPlatformContext(activity, webView)).use { browser ->
demo(browser.page())
}iOS — attach to your app’s WKWebView from iosMain:
Browser(IOSPlatformContext(webView = webView)).use { browser ->
demo(browser.page())
}JVM — launch an installed Chrome or Chromium:
launchBrowser(executablePath).use { launched ->
demo(launched.browser.newPage())
}See the platform guides for Android, iOS and Swift, and JVM and cloud browsers.
page.runCommand("snapshot -i")
// @e1 [input type="email"]
// @e2 [button] "Sign in"
page.runCommand("fill @e1 ada@example.com")
page.runCommand("click @e2")Expose runCommand() as a tool to your LLM SDK. The model reads snapshots and
acts on element references, using the documented
agent-browser command subset.
| Workflow | Guide |
|---|---|
| Find elements, enter text and assert results | Locators |
| Intercept requests and inspect network history | Networking |
| Capture pages and compare images | Screenshots |
| Save cookies and browser storage | Session state |
| Record a Chromium workflow | Recording |
| Platform | Browser | Minimum |
|---|---|---|
| Android | WebView | Android 8 |
| iOS | WKWebView | iOS 15 · arm64 device and simulator |
| JVM | Chromium through CDP | JDK 17 |
Features follow each backend’s abilities. Inspect page.capabilities() before
using an optional feature; the capability matrix
explains partial and unsupported behavior.
KMPwright adapts browser behavior from agent-browser into Kotlin APIs. It is independent of Playwright. The upstream comparison records the pinned revision and coverage; upstream source is not included in this repository.
For contributions, see development and tests. For artifact verification, see the release guide.
Browser automation for Kotlin Multiplatform. Write a workflow once and run it inside Android WebView, iOS WKWebView or JVM Chromium. Use a Playwright-inspired Kotlin API, or give an AI agent the same browser through compact commands.
Website · Documentation · Examples
[!NOTE] 0.0.1 alpha. Available on Maven Central. APIs and platform coverage may change.
Add to commonMain.dependencies in your module’s build.gradle.kts:
implementation("io.github.bernaferrari:kmpwright-core:0.0.1")One dependency covers Android, iOS and JVM. Gradle selects the platform variant.
Requires mavenCentral() in your project's repositories.
repositories { mavenCentral() }
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.bernaferrari:kmpwright-core:0.0.1")
}
}
}For the Android Compose wrapper, add this to androidMain.dependencies:
implementation("io.github.bernaferrari:kmpwright-compose:0.0.1")Fill a form, click its button and verify the rendered result. This demo uses a self-contained page, so it runs without a server or an account.
import com.bernaferrari.kmpwright.core.*
suspend fun demo(page: Page) = with(page) {
setContent(demoHtml)
getByLabel("Name").fill("Ada")
getByRole("button", name = "Say hello").click()
expect(getByRole("status")).toHaveText("Hello, Ada!")
}Result: the page displays Hello, Ada! and the assertion passes. Locators wait for actionable elements; assertions wait for the expected result. The same workflow runs on Android, iOS and JVM.
Define this alongside demo() in your shared Kotlin code:
val demoHtml = """
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>KMPwright demo</title>
<label for="name">Name</label>
<input id="name">
<button onclick="document.getElementById('greeting').textContent =
'Hello, ' + document.getElementById('name').value + '!'">Say hello</button>
<p id="greeting" role="status"></p>
</html>
""".trimIndent()Connect your platform's browser, then pass its Page to the shared workflow.
Run suspending APIs in a coroutine, on the main thread for mobile WebViews.
Android — attach to your app’s WebView:
Browser(AndroidPlatformContext(activity, webView)).use { browser ->
demo(browser.page())
}iOS — attach to your app’s WKWebView from iosMain:
Browser(IOSPlatformContext(webView = webView)).use { browser ->
demo(browser.page())
}JVM — launch an installed Chrome or Chromium:
launchBrowser(executablePath).use { launched ->
demo(launched.browser.newPage())
}See the platform guides for Android, iOS and Swift, and JVM and cloud browsers.
page.runCommand("snapshot -i")
// @e1 [input type="email"]
// @e2 [button] "Sign in"
page.runCommand("fill @e1 ada@example.com")
page.runCommand("click @e2")Expose runCommand() as a tool to your LLM SDK. The model reads snapshots and
acts on element references, using the documented
agent-browser command subset.
| Workflow | Guide |
|---|---|
| Find elements, enter text and assert results | Locators |
| Intercept requests and inspect network history | Networking |
| Capture pages and compare images | Screenshots |
| Save cookies and browser storage | Session state |
| Record a Chromium workflow | Recording |
| Platform | Browser | Minimum |
|---|---|---|
| Android | WebView | Android 8 |
| iOS | WKWebView | iOS 15 · arm64 device and simulator |
| JVM | Chromium through CDP | JDK 17 |
Features follow each backend’s abilities. Inspect page.capabilities() before
using an optional feature; the capability matrix
explains partial and unsupported behavior.
KMPwright adapts browser behavior from agent-browser into Kotlin APIs. It is independent of Playwright. The upstream comparison records the pinned revision and coverage; upstream source is not included in this repository.
For contributions, see development and tests. For artifact verification, see the release guide.