From 2f36d99723ed6d25182e9ebb9aa9fbae605adeab Mon Sep 17 00:00:00 2001
From: Ilyaas Kapadia <86218345+IlyaasK@users.noreply.github.com>
Date: Fri, 29 May 2026 11:19:18 -0400
Subject: [PATCH] docs: add Go SDK examples
---
.docs/code-example-guide.md | 138 ++++++++++++-
README.md | 30 +--
apps/invoke.mdx | 55 ++++++
apps/logs.mdx | 29 +++
apps/status.mdx | 52 ++++-
apps/stop.mdx | 24 +++
auth/configuration.mdx | 145 ++++++++++++++
auth/connection-lifecycle.mdx | 37 ++++
auth/credentials.mdx | 171 ++++++++++++++++
auth/hosted-ui.mdx | 170 ++++++++++++++++
auth/overview.mdx | 61 ++++++
auth/profiles.mdx | 190 ++++++++++++++++++
auth/programmatic.mdx | 292 ++++++++++++++++++++++++++++
auth/react.mdx | 18 ++
browsers/bot-detection/stealth.mdx | 34 ++++
browsers/computer-controls.mdx | 301 +++++++++++++++++++++++++++++
browsers/curl.mdx | 69 +++++++
browsers/extensions.mdx | 26 +++
browsers/gpu-acceleration.mdx | 23 +++
browsers/headless.mdx | 23 +++
browsers/live-view.mdx | 33 ++++
browsers/playwright-execution.mdx | 82 ++++++++
browsers/pools/overview.mdx | 151 +++++++++++++++
browsers/pools/policy-json.mdx | 49 ++++-
browsers/replays.mdx | 119 ++++++++++++
browsers/termination.mdx | 44 +++++
browsers/viewport.mdx | 151 +++++++++++++++
info/api-keys.mdx | 94 +++++++++
info/projects.mdx | 97 ++++++++++
integrations/1password.mdx | 38 ++++
introduction/control.mdx | 89 +++++++++
introduction/create.mdx | 72 +++++++
introduction/observe.mdx | 68 +++++++
proxies/custom.mdx | 78 ++++++++
proxies/datacenter.mdx | 70 +++++++
proxies/isp.mdx | 62 +++++-
proxies/overview.mdx | 219 +++++++++++++++++++++
proxies/residential.mdx | 126 ++++++++++++
38 files changed, 3497 insertions(+), 33 deletions(-)
diff --git a/.docs/code-example-guide.md b/.docs/code-example-guide.md
index d73dbb4..5bcaa2a 100644
--- a/.docs/code-example-guide.md
+++ b/.docs/code-example-guide.md
@@ -4,10 +4,13 @@ This guide defines the standards for code examples across the Kernel documentati
## General Principles
-1. **Complete and runnable**: Every code example should be complete enough to run as-is
+1. **Context-aware completeness**: Full examples must run as-is. Focused snippets can rely
+ on variables introduced by surrounding text or sibling examples, but they must make those
+ dependencies obvious.
2. **Consistent naming**: Use standardized variable names across all examples
-3. **No hardcoded credentials**: Never include API keys or credentials in examples
-4. **Multi-language support**: When applicable, show both TypeScript/JavaScript and Python examples
+3. **No real secrets**: Never include real API keys, passwords, tokens, or live credentials.
+ Use obviously fake values when an auth-flow example needs credential-shaped input.
+4. **Multi-language support**: When applicable, show TypeScript/JavaScript, Python, and Go examples
## Variable Naming Conventions
@@ -27,8 +30,25 @@ This guide defines the standards for code examples across the Kernel documentati
- Context: `context`
- Page: `page`
+### Go
+- SDK client: `client`
+- Browser instance: `kernelBrowser`
+- Additional browsers: `kernelBrowser2`, etc.
+- Context: `ctx`
+- Session ID: `sessionID`
+- Invocation ID: `invocationID`
+
## Code Example Structure
+### Full examples vs focused snippets
+
+Use a full example when the reader needs to copy and run a standalone program. Include imports,
+SDK initialization, context setup, the main operation, and error handling.
+
+Use a focused snippet when the page is walking through one step in a larger flow. Keep the snippet
+small, but rely only on variables the page already introduced, such as `client`, `ctx`,
+`kernelBrowser`, `auth`, or `browser`.
+
### Minimal Example (Browser Creation)
Always include:
@@ -55,6 +75,29 @@ kernel = Kernel()
kernel_browser = kernel.browsers.create()
print(kernel_browser.session_id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(kernelBrowser.SessionID)
+}
+```
### Full Example (With Browser Automation)
@@ -129,6 +172,16 @@ const kernel = new Kernel();
kernel = Kernel()
```
+```go
+package main
+
+import "github.com/kernel/kernel-go-sdk"
+
+func main() {
+ _ = kernel.NewClient()
+}
+```
+
The SDK automatically reads the API key from the `KERNEL_API_KEY` environment variable.
### ❌ Incorrect - Hardcoded credentials
@@ -145,6 +198,22 @@ kernel = Kernel(api_key="your-api-key")
kernel = Kernel(api_key=os.getenv("KERNEL_API_KEY"))
```
+```go
+// DON'T DO THIS
+package main
+
+import (
+ "github.com/kernel/kernel-go-sdk"
+ "github.com/kernel/kernel-go-sdk/option"
+)
+
+func main() {
+ _ = kernel.NewClient(
+ option.WithAPIKey("your-api-key"),
+ )
+}
+```
+
## Feature-Specific Examples
### Simple Feature Toggle
@@ -171,6 +240,28 @@ kernel_browser = kernel.browsers.create(
stealth=True,
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ _, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Stealth: kernel.Bool(true),
+ })
+ if err != nil {
+ panic(err)
+ }
+}
+```
### Feature with Configuration
@@ -197,10 +288,36 @@ kernel_browser = kernel.browsers.create(
stealth=True
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Stealth: kernel.Bool(true),
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ _ = kernelBrowser
+}
+```
## App Development Examples
+Kernel app examples currently use TypeScript/JavaScript and Python. Add a Go version only after the Go SDK has documented app framework support and the snippet has been tested against that SDK.
+
For Kernel app examples, follow this pattern:
@@ -299,17 +416,19 @@ finally:
### Indentation
- TypeScript/JavaScript: 2 spaces
- Python: 4 spaces
+- Go: tabs from `gofmt`
### String Quotes
- TypeScript/JavaScript: Single quotes `'` (except for avoiding escaping)
- Python: Double quotes `"`
+- Go: Double quotes `"`
### Line Length
- Keep lines under 100 characters when possible
- Break long parameter lists across multiple lines
### Comments
-- Use comments sparingly - code should be self-explanatory
+- Use comments sparingly; keep code self-explanatory
- Add comments only for non-obvious logic or important context
- Never add comments like "NEW CODE:" or similar meta-comments
@@ -340,6 +459,10 @@ Always use `` with proper language labels:
```python Python
# Python code here
```
+
+```go Go
+// Go code here
+```
````
@@ -350,11 +473,13 @@ Before publishing a code example, verify:
- [ ] Includes all necessary imports
- [ ] SDK is initialized without hardcoded API keys
- [ ] Variable names follow conventions
-- [ ] Code is complete and runnable
+- [ ] Code is complete and runnable, or it is a focused snippet with obvious prerequisites
- [ ] Includes error handling (for full examples)
- [ ] Includes cleanup code (for full examples)
- [ ] Uses proper indentation and formatting
-- [ ] Both TypeScript and Python versions are provided (when applicable)
+- [ ] TypeScript/JavaScript, Python, and Go versions are provided (when applicable)
+- [ ] Go examples are formatted with `gofmt`
+- [ ] Go examples are tested against the actual Go SDK version the docs claim to support
- [ ] Code has been tested or follows proven patterns
## Reference
@@ -363,4 +488,3 @@ See these files for examples:
- `introduction/create.mdx` - Standard browser creation pattern
- `apps/develop.mdx` - App development pattern
- `browsers/file-io.mdx` - Complex automation example
-
diff --git a/README.md b/README.md
index 7e558f1..5d5b0d9 100644
--- a/README.md
+++ b/README.md
@@ -11,31 +11,15 @@ This is the documentation for the Kernel platform. It's connected to [onkernel.c
## Code Snippets
-Code samples in the docs are generated from our OpenAPI spec so the examples stay in sync with the API. There are two ways the generator is invoked:
+Code samples in the docs are authored inline in MDX. Keep SDK examples aligned with the SDK repos, and follow the standards in `.docs/code-example-guide.md` when adding or editing examples.
-- Custom MDX tag: use `get /api/v1/users` (or omit the verb to use the default behavior).
+When you add Go examples:
-How the generator works (current behavior):
-
-- The script is `.github/scripts/generate_code_samples.ts` and is executed with Bun. It fetches the OpenAPI spec from the URL configured at the top of that script.
-- It reads `x-codeSamples` entries for each operation and extracts samples for TypeScript/JavaScript and Python. Samples are normalized and may be transformed by simple "overrides" (see the script for the override parsing and injection heuristics).
-- It writes snippet files under `snippets/openapi/` as MDX files containing a `` with the generated code fences. It also updates any MDX files under `apps/` and `browsers/` that contain the inline or tag forms by replacing them with the generated `` blocks.
-- The generator can produce a base snippet and additional variant snippets controlled by `.github/scripts/code_samples.config.json` (variants are keyed by `"method /path"`).
-- The script also removes stale snippet files matching the `-.mdx` suffix pattern.
-
-How it affects the repository:
-
-- New or updated files are created under `snippets/openapi/*.mdx`.
-- MDX pages in `apps/` and `browsers/` may be modified in-place to replace ``/mustache tags with generated `` blocks.
-- A GitHub Action (`.github/workflows/generate_code_snippets.yaml`) runs the script on push (except to `main`), commits any changes, and pushes them to the `gh_action_generated_docs` branch so Mintlify can deploy the generated docs.
-
-Notes and gotchas:
-
-- The generator runs remotely against the OpenAPI URL defined in the script, so it needs network access and the spec to include `x-codeSamples` for useful output.
-- The override parsing and code injection are heuristic. Complex sample sources might not be transformed exactly as intended. See the script for details on how keys/`log` overrides are applied.
-- The GitHub Action installs Bun and runs the script; if you run it locally, install Bun and run `bun run .github/scripts/generate_code_samples.ts` from the repo root.
-
-Example: to add a snippet placeholder to a page, add `get /api/v1/users` and let the generator fill `snippets/openapi` and update the page during the next run.
+- Test complete snippets, or wrapped focused snippets, against the minimum released Go SDK version
+ that supports the API you're documenting.
+- Run `gofmt` on complete snippets and on wrapper files used to validate focused snippets before
+ publishing.
+- Note the validation you ran in the pull request description.
## Local Development
diff --git a/apps/invoke.mdx b/apps/invoke.mdx
index 6a37c63..494ddc4 100644
--- a/apps/invoke.mdx
+++ b/apps/invoke.mdx
@@ -34,6 +34,33 @@ invocation = kernel.invocations.create(
)
print(invocation.id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ invocation, err := client.Invocations.New(ctx, kernel.InvocationNewParams{
+ ActionName: "analyze",
+ AppName: "my-app",
+ Version: "1.0.0",
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(invocation.ID)
+}
+```
### Asynchronous invocations
@@ -70,6 +97,34 @@ invocation = kernel.invocations.create(
)
print(invocation.id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ invocation, err := client.Invocations.New(ctx, kernel.InvocationNewParams{
+ Async: kernel.Bool(true),
+ ActionName: "analyze",
+ AppName: "my-app",
+ Version: "1.0.0",
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(invocation.ID)
+}
+```
## Via CLI
diff --git a/apps/logs.mdx b/apps/logs.mdx
index 3c80749..1345439 100644
--- a/apps/logs.mdx
+++ b/apps/logs.mdx
@@ -21,6 +21,35 @@ from kernel import Kernel
kernel = Kernel()
logs = kernel.invocations.follow(invocation_id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ logs := client.Invocations.FollowStreaming(ctx, "inv_123", kernel.InvocationFollowParams{})
+ defer logs.Close()
+
+ for logs.Next() {
+ event := logs.Current()
+ if event.Event == "log" {
+ fmt.Println(event.Message)
+ }
+ }
+ if err := logs.Err(); err != nil {
+ panic(err)
+ }
+}
+```
Log lines will be truncated to 64KiB. For large payloads write data to external storage and log a reference instead.
diff --git a/apps/status.mdx b/apps/status.mdx
index 90b8f0f..21a8198 100644
--- a/apps/status.mdx
+++ b/apps/status.mdx
@@ -30,6 +30,35 @@ kernel = Kernel()
response = kernel.invocations.follow(id="id")
print(response)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ stream := client.Invocations.FollowStreaming(ctx, "id", kernel.InvocationFollowParams{})
+ defer stream.Close()
+
+ for stream.Next() {
+ event := stream.Current()
+ if event.Event == "invocation_state" {
+ fmt.Println(event.Invocation.Status)
+ }
+ }
+ if err := stream.Err(); err != nil {
+ panic(err)
+ }
+}
+```
### Example
@@ -86,5 +115,26 @@ kernel = Kernel()
invocation = kernel.invocations.retrieve("rr33xuugxj9h0bkf1rdt2bet")
print(invocation.status)
```
-
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ invocation, err := client.Invocations.Get(ctx, "rr33xuugxj9h0bkf1rdt2bet")
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println(invocation.Status)
+}
+```
+
diff --git a/apps/stop.mdx b/apps/stop.mdx
index dfdea0a..da53a56 100644
--- a/apps/stop.mdx
+++ b/apps/stop.mdx
@@ -33,6 +33,30 @@ invocation = kernel.invocations.update(
output='{"error":"Invocation cancelled by user"}',
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ invocation, err := client.Invocations.Update(ctx, "invocation_id", kernel.InvocationUpdateParams{
+ Status: kernel.InvocationUpdateParamsStatusFailed,
+ Output: kernel.String(`{"error":"Invocation cancelled by user"}`),
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = invocation
+}
+```
## Via CLI
diff --git a/auth/configuration.mdx b/auth/configuration.mdx
index 35e5c58..2a8e61e 100644
--- a/auth/configuration.mdx
+++ b/auth/configuration.mdx
@@ -37,6 +37,21 @@ auth = await kernel.auth.connections.create(
auto_reauth=False,
)
```
+
+```go Go
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "example.com",
+ ProfileName: "my-profile",
+ HealthChecks: kernel.Bool(false),
+ AutoReauth: kernel.Bool(false),
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = auth
+```
Both flags can be flipped on an existing connection with `auth.connections.update`; changes take effect immediately on the running connection.
@@ -63,6 +78,20 @@ auth = await kernel.auth.connections.create(
login_url="https://example.com/auth/signin",
)
```
+
+```go Go
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "example.com",
+ ProfileName: "my-profile",
+ LoginURL: kernel.String("https://example.com/auth/signin"),
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = auth
+```
## SSO/OAuth Support
@@ -89,6 +118,20 @@ auth = await kernel.auth.connections.create(
allowed_domains=["sso.custom-provider.com"],
)
```
+
+```go Go
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "example.com",
+ ProfileName: "my-profile",
+ AllowedDomains: []string{"sso.custom-provider.com"},
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = auth
+```
## Custom Proxy
@@ -123,6 +166,29 @@ auth = await kernel.auth.connections.create(
proxy={"id": proxy.id},
)
```
+
+```go Go
+proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeIsp,
+})
+if err != nil {
+ panic(err)
+}
+
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "example.com",
+ ProfileName: "my-profile",
+ Proxy: kernel.ManagedAuthCreateRequestProxyParam{
+ ID: kernel.String(proxy.ID),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = auth
+```
You can also reference a proxy by `name` instead of `id`. The proxy must belong to the same org and project as the connection.
@@ -144,6 +210,19 @@ await kernel.auth.connections.update(
proxy={"id": new_proxy.id},
)
```
+
+```go Go
+_, err := client.Auth.Connections.Update(ctx, auth.ID, kernel.AuthConnectionUpdateParams{
+ ManagedAuthUpdateRequest: kernel.ManagedAuthUpdateRequestParam{
+ Proxy: kernel.ManagedAuthUpdateRequestProxyParam{
+ ID: kernel.String(newProxy.ID),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+```
You can also override the connection's proxy for a single login by passing `proxy` on `.login()` — useful when you want to try a one-off egress without changing the connection-wide default (which would also affect subsequent health checks and reauths).
@@ -161,6 +240,18 @@ login = await kernel.auth.connections.login(
proxy={"id": one_off_proxy.id},
)
```
+
+```go Go
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{
+ Proxy: kernel.AuthConnectionLoginParamsProxy{
+ ID: kernel.String(oneOffProxy.ID),
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = login
+```
## Record Sessions for Debugging
@@ -183,6 +274,20 @@ auth = await kernel.auth.connections.create(
record_session=True,
)
```
+
+```go Go
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "example.com",
+ ProfileName: "my-profile",
+ RecordSession: kernel.Bool(true),
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = auth
+```
You can also override the connection default for a single login by passing `record_session` on `.login()` — useful for one-off debugging on a specific login attempt without flipping the connection-wide flag (which would also record subsequent health checks and reauths).
@@ -200,6 +305,16 @@ login = await kernel.auth.connections.login(
record_session=True,
)
```
+
+```go Go
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{
+ RecordSession: kernel.Bool(true),
+})
+if err != nil {
+ panic(err)
+}
+_ = login
+```
Managed auth recordings are subject to the same retention rules as other session replay recordings. Each managed auth session row stores its own `replay_id` for the recording captured during that session.
@@ -225,6 +340,23 @@ if managed_auth.post_login_url:
await page.goto(managed_auth.post_login_url)
# Start automation from the dashboard/home page
```
+
+```go Go
+managedAuth, err := client.Auth.Connections.Get(ctx, auth.ID)
+if err != nil {
+ panic(err)
+}
+
+if managedAuth.PostLoginURL != "" {
+ _, err := client.Browsers.Playwright.Execute(ctx, browser.SessionID, kernel.BrowserPlaywrightExecuteParams{
+ Code: fmt.Sprintf(`await page.goto(%q);`, managedAuth.PostLoginURL),
+ })
+ if err != nil {
+ panic(err)
+ }
+ // Start automation from the dashboard/home page
+}
+```
## Updating a Connection
@@ -262,4 +394,17 @@ await kernel.auth.connections.update(
save_credentials=True,
)
```
+
+```go Go
+_, err := client.Auth.Connections.Update(ctx, auth.ID, kernel.AuthConnectionUpdateParams{
+ ManagedAuthUpdateRequest: kernel.ManagedAuthUpdateRequestParam{
+ LoginURL: kernel.String("https://example.com/new-login"),
+ HealthCheckInterval: kernel.Int(1800),
+ SaveCredentials: kernel.Bool(true),
+ },
+})
+if err != nil {
+ panic(err)
+}
+```
diff --git a/auth/connection-lifecycle.mdx b/auth/connection-lifecycle.mdx
index 48d2adc..535002e 100644
--- a/auth/connection-lifecycle.mdx
+++ b/auth/connection-lifecycle.mdx
@@ -47,6 +47,17 @@ await kernel.auth.connections.update(
health_check_interval=1800, # 30 minutes
)
```
+
+```go Go
+_, err := client.Auth.Connections.Update(ctx, auth.ID, kernel.AuthConnectionUpdateParams{
+ ManagedAuthUpdateRequest: kernel.ManagedAuthUpdateRequestParam{
+ HealthCheckInterval: kernel.Int(1800), // 30 minutes
+ },
+})
+if err != nil {
+ panic(err)
+}
+```
### Sessions that expire faster than the interval
@@ -96,6 +107,22 @@ if state.status == "NEEDS_AUTH":
login = await kernel.auth.connections.login(auth.id)
# Handle login flow as usual
```
+
+```go Go
+state, err := client.Auth.Connections.Get(ctx, auth.ID)
+if err != nil {
+ panic(err)
+}
+
+if state.Status == kernel.ManagedAuthStatusNeedsAuth {
+ login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+ if err != nil {
+ panic(err)
+ }
+ _ = login
+ // Handle login flow as usual
+}
+```
## When a login fails
@@ -140,6 +167,16 @@ login = await kernel.auth.connections.login(
record_session=True,
)
```
+
+```go Go
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{
+ RecordSession: kernel.Bool(true),
+})
+if err != nil {
+ panic(err)
+}
+_ = login
+```
To record every auth session on the connection (logins, health checks, and reauths), set `record_session: true` connection-wide — see [Record Sessions for Debugging](/auth/configuration#record-sessions-for-debugging).
diff --git a/auth/credentials.mdx b/auth/credentials.mdx
index 5850aa9..e31350a 100644
--- a/auth/credentials.mdx
+++ b/auth/credentials.mdx
@@ -26,6 +26,14 @@ const login = await kernel.auth.connections.login(auth.id);
```python Python
login = await kernel.auth.connections.login(auth.id)
```
+
+```go Go
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+if err != nil {
+ panic(err)
+}
+_ = login
+```
Once saved, browser profiles stay authenticated automatically. When the session expires, Kernel re-authenticates using the stored credentials. Credentials are updated after every successful login. One-time codes (TOTP, SMS, etc.) are not saved.
@@ -48,6 +56,20 @@ auth = await kernel.auth.connections.create(
save_credentials=False,
)
```
+
+```go Go
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "example.com",
+ ProfileName: "my-profile",
+ SaveCredentials: kernel.Bool(false),
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = auth
+```
## Pre-store credentials
@@ -76,6 +98,23 @@ credential = await kernel.credentials.create(
},
)
```
+
+```go Go
+credential, err := client.Credentials.New(ctx, kernel.CredentialNewParams{
+ CreateCredentialRequest: kernel.CreateCredentialRequestParam{
+ Name: "my-netflix-login",
+ Domain: "netflix.com",
+ Values: map[string]string{
+ "email": "user@netflix.com",
+ "password": "secretpassword123",
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = credential
+```
Then link the credential when creating a connection:
@@ -102,6 +141,28 @@ auth = await kernel.auth.connections.create(
# Start login - authenticates automatically using stored credentials
login = await kernel.auth.connections.login(auth.id)
```
+
+```go Go
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "netflix.com",
+ ProfileName: "my-profile",
+ Credential: kernel.ManagedAuthCreateRequestCredentialParam{
+ Name: kernel.String(credential.Name),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+
+// Start login - authenticates automatically using stored credentials
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+if err != nil {
+ panic(err)
+}
+_ = login
+```
### 2FA with TOTP
@@ -132,6 +193,24 @@ credential = await kernel.credentials.create(
totp_secret="JBSWY3DPEHPK3PXP", # From authenticator app setup
)
```
+
+```go Go
+credential, err := client.Credentials.New(ctx, kernel.CredentialNewParams{
+ CreateCredentialRequest: kernel.CreateCredentialRequestParam{
+ Name: "my-login",
+ Domain: "github.com",
+ Values: map[string]string{
+ "username": "my-username",
+ "password": "my-password",
+ },
+ TotpSecret: kernel.String("JBSWY3DPEHPK3PXP"), // From authenticator app setup
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = credential
+```
### SSO / OAuth
@@ -176,6 +255,37 @@ auth = await kernel.auth.connections.create(
credential={"name": credential.name},
)
```
+
+```go Go
+credential, err := client.Credentials.New(ctx, kernel.CredentialNewParams{
+ CreateCredentialRequest: kernel.CreateCredentialRequestParam{
+ Name: "my-google-login",
+ Domain: "accounts.google.com",
+ SSOProvider: kernel.String("google"),
+ Values: map[string]string{
+ "email": "user@gmail.com",
+ "password": "password",
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "target-site.com",
+ ProfileName: "my-profile",
+ Credential: kernel.ManagedAuthCreateRequestCredentialParam{
+ Name: kernel.String(credential.Name),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = auth
+```
## Partial Credentials
@@ -245,6 +355,67 @@ while state.flow_status == "IN_PROGRESS":
state = await kernel.auth.connections.retrieve(auth.id)
# TOTP auto-submitted from credential → SUCCESS
```
+
+```go Go
+credential, err := client.Credentials.New(ctx, kernel.CredentialNewParams{
+ CreateCredentialRequest: kernel.CreateCredentialRequestParam{
+ Name: "my-login",
+ Domain: "example.com",
+ Values: map[string]string{
+ "email": "user@example.com", // No password
+ },
+ TotpSecret: kernel.String("JBSWY3DPEHPK3PXP"),
+ },
+})
+if err != nil {
+ panic(err)
+}
+
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "example.com",
+ ProfileName: "my-profile",
+ Credential: kernel.ManagedAuthCreateRequestCredentialParam{
+ Name: kernel.String(credential.Name),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+if err != nil {
+ panic(err)
+}
+_ = login
+
+// Poll until password is needed
+state, err := client.Auth.Connections.Get(ctx, auth.ID)
+if err != nil {
+ panic(err)
+}
+for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
+ if state.FlowStep == kernel.ManagedAuthFlowStepAwaitingInput && len(state.DiscoveredFields) > 0 {
+ // Only password field will be pending (email auto-filled from credential)
+ _, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
+ SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
+ Fields: map[string]string{"password": "user-provided-password"},
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ time.Sleep(2 * time.Second)
+ state, err = client.Auth.Connections.Get(ctx, auth.ID)
+ if err != nil {
+ panic(err)
+ }
+}
+// TOTP auto-submitted from credential → SUCCESS
+```
This is useful when you want to:
diff --git a/auth/hosted-ui.mdx b/auth/hosted-ui.mdx
index 3e6d289..d052d69 100644
--- a/auth/hosted-ui.mdx
+++ b/auth/hosted-ui.mdx
@@ -30,6 +30,19 @@ auth = await kernel.auth.connections.create(
profile_name="linkedin-profile", # Name of the profile to associate with the connection
)
```
+
+```go Go
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "linkedin.com",
+ ProfileName: "linkedin-profile", // Name of the profile to associate with the connection
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = auth
+```
### 2. Start a Login Session
@@ -44,6 +57,14 @@ const login = await kernel.auth.connections.login(auth.id);
```python Python
login = await kernel.auth.connections.login(auth.id)
```
+
+```go Go
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+if err != nil {
+ panic(err)
+}
+_ = login
+```
### 3. Collect Credentials
@@ -59,6 +80,11 @@ window.location.href = login.hosted_url;
# Return the URL to your frontend
print(f"Redirect to: {login.hosted_url}")
```
+
+```go Go
+// Return the URL to your frontend
+fmt.Println("Redirect to:", login.HostedURL)
+```
The user will:
@@ -94,6 +120,25 @@ while state.flow_status == "IN_PROGRESS":
if state.status == "AUTHENTICATED":
print("Authentication successful!")
```
+
+```go Go
+state, err := client.Auth.Connections.Get(ctx, auth.ID)
+if err != nil {
+ panic(err)
+}
+
+for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
+ time.Sleep(2 * time.Second)
+ state, err = client.Auth.Connections.Get(ctx, auth.ID)
+ if err != nil {
+ panic(err)
+ }
+}
+
+if state.Status == kernel.ManagedAuthStatusAuthenticated {
+ fmt.Println("Authentication successful!")
+}
+```
@@ -124,6 +169,26 @@ browser = await kernel.browsers.create(
# Navigate to the site—you're already logged in
await page.goto("https://linkedin.com")
```
+
+```go Go
+browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String("linkedin-profile"),
+ },
+ Stealth: kernel.Bool(true),
+})
+if err != nil {
+ panic(err)
+}
+
+// Navigate to the site—you're already logged in
+_, err = client.Browsers.Playwright.Execute(ctx, browser.SessionID, kernel.BrowserPlaywrightExecuteParams{
+ Code: `await page.goto("https://linkedin.com");`,
+})
+if err != nil {
+ panic(err)
+}
+```
@@ -202,6 +267,77 @@ if state.status == "AUTHENTICATED":
# Navigate to the site—you're already logged in
await page.goto("https://doordash.com")
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/kernel/kernel-go-sdk"
+ "github.com/kernel/kernel-go-sdk/shared"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ // Create connection
+ auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "doordash.com",
+ ProfileName: "doordash-user-123",
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ // Start authentication
+ login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ // Send user to hosted page
+ fmt.Println("Login URL:", login.HostedURL)
+
+ // Poll for completion
+ state, err := client.Auth.Connections.Get(ctx, auth.ID)
+ if err != nil {
+ panic(err)
+ }
+ for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
+ time.Sleep(2 * time.Second)
+ state, err = client.Auth.Connections.Get(ctx, auth.ID)
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ if state.Status == kernel.ManagedAuthStatusAuthenticated {
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String("doordash-user-123"),
+ },
+ Stealth: kernel.Bool(true),
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ // Navigate to the site—you're already logged in
+ _, err = client.Browsers.Playwright.Execute(ctx, browser.SessionID, kernel.BrowserPlaywrightExecuteParams{
+ Code: `await page.goto("https://doordash.com");`,
+ })
+ if err != nil {
+ panic(err)
+ }
+ }
+}
+```
## Success / error redirects
@@ -236,6 +372,40 @@ query["error_url"] = "https://example.com/auth-failed"
redirect_url = urlunparse(parsed._replace(query=urlencode(query)))
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+ "net/url"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ login, err := client.Auth.Connections.Login(ctx, "auth_123", kernel.AuthConnectionLoginParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ redirectURL, err := url.Parse(login.HostedURL)
+ if err != nil {
+ panic(err)
+ }
+
+ query := redirectURL.Query()
+ query.Set("success_url", "https://example.com/connected")
+ query.Set("error_url", "https://example.com/auth-failed")
+ redirectURL.RawQuery = query.Encode()
+
+ fmt.Println(redirectURL.String())
+}
+```
diff --git a/auth/overview.mdx b/auth/overview.mdx
index 07c95d3..3a6653b 100644
--- a/auth/overview.mdx
+++ b/auth/overview.mdx
@@ -25,6 +25,19 @@ auth = await kernel.auth.connections.create(
profile_name="netflix-user-123",
)
```
+
+```go Go
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "netflix.com",
+ ProfileName: "netflix-user-123",
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = auth
+```
@@ -66,6 +79,33 @@ while state.flow_status == "IN_PROGRESS":
if state.status == "AUTHENTICATED":
print("Authenticated!")
```
+
+```go Go
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+if err != nil {
+ panic(err)
+}
+
+// Send user to login page
+fmt.Println("Login URL:", login.HostedURL)
+
+// Poll until complete
+state, err := client.Auth.Connections.Get(ctx, auth.ID)
+if err != nil {
+ panic(err)
+}
+for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
+ time.Sleep(2 * time.Second)
+ state, err = client.Auth.Connections.Get(ctx, auth.ID)
+ if err != nil {
+ panic(err)
+ }
+}
+
+if state.Status == kernel.ManagedAuthStatusAuthenticated {
+ fmt.Println("Authenticated!")
+}
+```
@@ -92,6 +132,27 @@ browser = await kernel.browsers.create(
# Navigate to the site—you're already logged in
await page.goto("https://netflix.com")
```
+
+```go Go
+browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String("netflix-user-123"),
+ },
+ Stealth: kernel.Bool(true),
+})
+if err != nil {
+ panic(err)
+}
+_ = browser
+
+// Navigate to the site—you're already logged in
+_, err = client.Browsers.Playwright.Execute(ctx, browser.SessionID, kernel.BrowserPlaywrightExecuteParams{
+ Code: `await page.goto("https://netflix.com");`,
+})
+if err != nil {
+ panic(err)
+}
+```
diff --git a/auth/profiles.mdx b/auth/profiles.mdx
index 2e44aaf..5833b55 100644
--- a/auth/profiles.mdx
+++ b/auth/profiles.mdx
@@ -38,6 +38,35 @@ try:
except ConflictError:
pass
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "errors"
+ "net/http"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ _, err := client.Profiles.New(ctx, kernel.ProfileNewParams{
+ Name: kernel.String("profiles-demo"),
+ })
+ if err != nil {
+ var apiErr *kernel.Error
+ if errors.As(err, &apiErr) && apiErr.StatusCode == http.StatusConflict {
+ // Profile already exists
+ return
+ }
+ panic(err)
+ }
+}
+```
## 2. Start a browser session using the profile and save changes
@@ -63,6 +92,19 @@ kernel_browser = await kernel.browsers.create(
}
)
```
+
+```go Go
+kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String("profiles-demo"),
+ SaveChanges: kernel.Bool(true),
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = kernelBrowser
+```
## 3. Use the browser, then close it to persist the state
@@ -89,6 +131,16 @@ print("Live view:", kernel_browser.browser_live_view_url)
await kernel.browsers.delete_by_id(kernel_browser.session_id)
```
+
+```go Go
+fmt.Println("Live view:", kernelBrowser.BrowserLiveViewURL)
+
+// Navigate and create login state...
+
+if err := client.Browsers.DeleteByID(ctx, kernelBrowser.SessionID); err != nil {
+ panic(err)
+}
+```
## 4. Start a new session with the saved profile (read-only)
@@ -110,6 +162,18 @@ kernel_browser2 = await kernel.browsers.create(
)
print("Live view:", kernel_browser2.browser_live_view_url)
```
+
+```go Go
+kernelBrowser2, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String("profiles-demo"),
+ },
+})
+if err != nil {
+ panic(err)
+}
+fmt.Println("Live view:", kernelBrowser2.BrowserLiveViewURL)
+```
## Override opening existing tabs in a new session
@@ -130,6 +194,19 @@ browser = await kernel.browsers.create(
start_url="https://example.com/dashboard",
)
```
+
+```go Go
+browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String("profiles-demo"),
+ },
+ StartURL: kernel.String("https://example.com/dashboard"),
+})
+if err != nil {
+ panic(err)
+}
+_ = browser
+```
The same behavior applies to browser pools configured with both a profile and start url.
@@ -156,6 +233,24 @@ kernel_browser = await kernel.browsers.create()
# Later, load a profile into the browser
await kernel.browsers.update(kernel_browser.session_id, profile={"name": "profiles-demo"})
```
+
+```go Go
+// Create a browser without a profile
+kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+if err != nil {
+ panic(err)
+}
+
+// Later, load a profile into the browser
+_, err = client.Browsers.Update(ctx, kernelBrowser.SessionID, kernel.BrowserUpdateParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String("profiles-demo"),
+ },
+})
+if err != nil {
+ panic(err)
+}
+```
@@ -226,6 +321,56 @@ browser = await kernel.browsers.create(
stealth=True,
)
```
+
+```go Go
+// Create a single profile with auth connections for three sites
+gmailAuth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "gmail.com",
+ ProfileName: "workflow-bot",
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = gmailAuth
+
+slackAuth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "slack.com",
+ ProfileName: "workflow-bot",
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = slackAuth
+
+crmAuth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "crm.example.com",
+ ProfileName: "workflow-bot",
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = crmAuth
+
+// Authenticate each connection (omitted for brevity)
+
+// Launch a single browser — logged in to Gmail, Slack, and the CRM
+browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String("workflow-bot"),
+ },
+ Stealth: kernel.Bool(true),
+})
+if err != nil {
+ panic(err)
+}
+_ = browser
+```
### User-to-profile mapping
@@ -286,6 +431,51 @@ browser = await kernel.browsers.create(
stealth=True,
)
```
+
+```go Go
+// For each user on your platform, create one profile
+// and attach all their accounts as auth connections
+userID := "user-123"
+
+if _, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "gmail.com",
+ ProfileName: userID,
+ },
+}); err != nil {
+ panic(err)
+}
+
+if _, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "linkedin.com",
+ ProfileName: userID,
+ },
+}); err != nil {
+ panic(err)
+}
+
+if _, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "github.com",
+ ProfileName: userID,
+ },
+}); err != nil {
+ panic(err)
+}
+
+// When user-123 triggers a workflow, launch a browser with their profile
+browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String(userID),
+ },
+ Stealth: kernel.Bool(true),
+})
+if err != nil {
+ panic(err)
+}
+_ = browser
+```
## Notes
diff --git a/auth/programmatic.mdx b/auth/programmatic.mdx
index 5161fff..a547737 100644
--- a/auth/programmatic.mdx
+++ b/auth/programmatic.mdx
@@ -44,6 +44,19 @@ auth = await kernel.auth.connections.create(
profile_name="github-profile", # Name of the profile to associate with the connection
)
```
+
+```go Go
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "github.com",
+ ProfileName: "github-profile", // Name of the profile to associate with the connection
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = auth
+```
### 2. Start a Login Session
@@ -56,6 +69,14 @@ const login = await kernel.auth.connections.login(auth.id);
```python Python
login = await kernel.auth.connections.login(auth.id)
```
+
+```go Go
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+if err != nil {
+ panic(err)
+}
+_ = login
+```
Credentials are saved automatically on successful login, enabling automatic re-authentication when the session expires.
@@ -99,6 +120,69 @@ while state.flow_status == "IN_PROGRESS":
if state.status == "AUTHENTICATED":
print("Authentication successful!")
```
+
+```go Go
+state, err := client.Auth.Connections.Get(ctx, auth.ID)
+if err != nil {
+ panic(err)
+}
+
+for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
+ // Submit when fields are ready (login or 2FA)
+ if state.FlowStep == kernel.ManagedAuthFlowStepAwaitingInput && len(state.DiscoveredFields) > 0 {
+ fieldValues := map[string]string{}
+ missingFields := []string{}
+
+ for _, field := range state.DiscoveredFields {
+ switch field.Name {
+ case "username":
+ fieldValues[field.Name] = "dev-user"
+ case "email":
+ fieldValues[field.Name] = "dev@example.com"
+ case "password":
+ fieldValues[field.Name] = "correct-horse-battery-staple"
+ case "otp", "code", "totp":
+ fieldValues[field.Name] = "123456"
+ default:
+ switch field.Type {
+ case "email":
+ fieldValues[field.Name] = "dev@example.com"
+ case "password":
+ fieldValues[field.Name] = "correct-horse-battery-staple"
+ case "code", "totp":
+ fieldValues[field.Name] = "123456"
+ default:
+ missingFields = append(missingFields, field.Name)
+ }
+ }
+ }
+
+ if len(missingFields) > 0 {
+ fmt.Println("Collect values for fields:", missingFields)
+ break
+ }
+
+ _, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
+ SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
+ Fields: fieldValues,
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ time.Sleep(2 * time.Second)
+ state, err = client.Auth.Connections.Get(ctx, auth.ID)
+ if err != nil {
+ panic(err)
+ }
+}
+
+if state.Status == kernel.ManagedAuthStatusAuthenticated {
+ fmt.Println("Authentication successful!")
+}
+```
The `discovered_fields` array tells you what the login form needs:
@@ -216,6 +300,117 @@ if state.status == "AUTHENTICATED":
# Navigate to the site—you're already logged in
await page.goto("https://github.com")
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/kernel/kernel-go-sdk"
+ "github.com/kernel/kernel-go-sdk/shared"
+)
+
+func promptUserForCode() string {
+ return "123456"
+}
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ // Create connection
+ auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "github.com",
+ ProfileName: "github-profile",
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+ if err != nil {
+ panic(err)
+ }
+ _ = login
+
+ // Single polling loop handles login + 2FA
+ state, err := client.Auth.Connections.Get(ctx, auth.ID)
+ if err != nil {
+ panic(err)
+ }
+
+ for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
+ if state.FlowStep == kernel.ManagedAuthFlowStepAwaitingInput && len(state.DiscoveredFields) > 0 {
+ // Check what fields are needed
+ fieldNames := map[string]bool{}
+ for _, field := range state.DiscoveredFields {
+ fieldNames[field.Name] = true
+ }
+
+ if fieldNames["username"] {
+ // Initial login
+ _, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
+ SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
+ Fields: map[string]string{
+ "username": "my-username",
+ "password": "my-password",
+ },
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ } else {
+ // 2FA or additional fields
+ code := promptUserForCode()
+ _, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
+ SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
+ Fields: map[string]string{
+ state.DiscoveredFields[0].Name: code,
+ },
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ }
+ }
+
+ time.Sleep(2 * time.Second)
+ state, err = client.Auth.Connections.Get(ctx, auth.ID)
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ if state.Status == kernel.ManagedAuthStatusAuthenticated {
+ fmt.Println("Authentication successful!")
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String("github-profile"),
+ },
+ Stealth: kernel.Bool(true),
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ // Navigate to the site—you're already logged in
+ _, err = client.Browsers.Playwright.Execute(ctx, browser.SessionID, kernel.BrowserPlaywrightExecuteParams{
+ Code: `await page.goto("https://github.com");`,
+ })
+ if err != nil {
+ panic(err)
+ }
+ }
+}
+```
@@ -261,6 +456,25 @@ if state.pending_sso_buttons:
sso_button_selector=state.pending_sso_buttons[0]["selector"],
)
```
+
+```go Go
+if len(state.PendingSSOButtons) > 0 {
+ // Show the user available SSO options
+ for _, btn := range state.PendingSSOButtons {
+ fmt.Printf("%s: %s\n", btn.Provider, btn.Label)
+ }
+
+ // Submit the selected SSO button
+ _, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
+ SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
+ SSOButtonSelector: kernel.String(state.PendingSSOButtons[0].Selector),
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+}
+```
@@ -289,6 +503,20 @@ if state.pending_sso_buttons:
sso_provider=state.pending_sso_buttons[0]["provider"], # e.g., "google"
)
```
+
+```go Go
+if len(state.PendingSSOButtons) > 0 {
+ // Submit by provider name instead of selector
+ _, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
+ SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
+ SSOProvider: kernel.String(state.PendingSSOButtons[0].Provider), // e.g., "google"
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+}
+```
@@ -326,6 +554,25 @@ if state.mfa_options:
mfa_option_id="sms",
)
```
+
+```go Go
+if len(state.MfaOptions) > 0 {
+ // Available types: sms, email, totp, push, call, password, switch
+ for _, opt := range state.MfaOptions {
+ fmt.Printf("%s: %s\n", opt.Type, opt.Label)
+ }
+
+ // Submit the selected MFA method
+ _, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
+ SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
+ MfaOptionID: kernel.String("sms"),
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+}
+```
After selecting an MFA method, the flow continues. Poll for `discovered_fields` to submit the code, or handle external actions for push/security key.
@@ -368,6 +615,28 @@ if state.sign_in_options:
sign_in_option_id=state.sign_in_options[0]["id"],
)
```
+
+```go Go
+if len(state.SignInOptions) > 0 {
+ // Show available options to the user
+ for _, opt := range state.SignInOptions {
+ fmt.Printf("%s: %s\n", opt.ID, opt.Label)
+ if opt.Description != "" {
+ fmt.Println(" " + opt.Description)
+ }
+ }
+
+ // Submit the selected option
+ _, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
+ SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
+ SignInOptionID: kernel.String(state.SignInOptions[0].ID),
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+}
+```
@@ -413,6 +682,29 @@ if state.flow_step == "AWAITING_EXTERNAL_ACTION":
# Otherwise keep polling—the flow resumes automatically when the user completes the action
```
+
+```go Go
+if state.FlowStep == kernel.ManagedAuthFlowStepAwaitingExternalAction {
+ // Show the message to the user
+ fmt.Println(state.ExternalActionMessage)
+ // e.g., "Check your phone for a push notification"
+
+ // Some sites offer fallback methods alongside the external action
+ // (e.g. "Try another way"). Submit one to switch verification methods.
+ if len(state.MfaOptions) > 0 {
+ _, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
+ SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
+ MfaOptionID: kernel.String(state.MfaOptions[0].Type),
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ // Otherwise keep polling—the flow resumes automatically when the user completes the action
+}
+```
diff --git a/auth/react.mdx b/auth/react.mdx
index bd295d5..4402a33 100644
--- a/auth/react.mdx
+++ b/auth/react.mdx
@@ -42,6 +42,24 @@ auth = await kernel.auth.connections.create(
login = await kernel.auth.connections.login(auth.id)
# login.id, login.handoff_code
```
+
+```go Go
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "netflix.com",
+ ProfileName: "user-123",
+ },
+})
+if err != nil {
+ panic(err)
+}
+
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+if err != nil {
+ panic(err)
+}
+fmt.Println(login.ID, login.HandoffCode)
+```
diff --git a/browsers/bot-detection/stealth.mdx b/browsers/bot-detection/stealth.mdx
index 53c110a..e21d0f2 100644
--- a/browsers/bot-detection/stealth.mdx
+++ b/browsers/bot-detection/stealth.mdx
@@ -37,6 +37,29 @@ kernel_browser = kernel.browsers.create(
stealth=True,
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Stealth: kernel.Bool(true),
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = kernelBrowser
+}
+```
## Bring your own proxy or CAPTCHA solver
@@ -65,6 +88,17 @@ kernel_browser = kernel.browsers.create(
proxy_id=my_proxy.id,
)
```
+
+```go Go
+kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Stealth: kernel.Bool(true),
+ ProxyID: kernel.String(myProxy.ID),
+})
+if err != nil {
+ panic(err)
+}
+_ = kernelBrowser
+```
If you're looking for proxy-level configuration with Kernel browsers, see [Proxies](/proxies/overview).
diff --git a/browsers/computer-controls.mdx b/browsers/computer-controls.mdx
index fe5f916..98471df 100644
--- a/browsers/computer-controls.mdx
+++ b/browsers/computer-controls.mdx
@@ -58,6 +58,45 @@ kernel.browsers.computer.click_mouse(
)
```
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ // Basic left click at (100, 200)
+ if err := client.Browsers.Computer.ClickMouse(ctx, kernelBrowser.SessionID, kernel.BrowserComputerClickMouseParams{
+ X: 100,
+ Y: 200,
+ }); err != nil {
+ panic(err)
+ }
+
+ // Double right-click while holding Shift
+ if err := client.Browsers.Computer.ClickMouse(ctx, kernelBrowser.SessionID, kernel.BrowserComputerClickMouseParams{
+ X: 100,
+ Y: 200,
+ Button: kernel.BrowserComputerClickMouseParamsButtonRight,
+ ClickType: kernel.BrowserComputerClickMouseParamsClickTypeClick,
+ NumClicks: kernel.Int(2),
+ HoldKeys: []string{"Shift"},
+ }); err != nil {
+ panic(err)
+ }
+}
+```
+
```bash CLI
# Click the mouse at coordinates (100, 200)
kernel browsers computer click-mouse --x 100 --y 200
@@ -139,6 +178,52 @@ kernel.browsers.computer.move_mouse(
)
```
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ // Human-like smooth movement (default)
+ if err := client.Browsers.Computer.MoveMouse(ctx, kernelBrowser.SessionID, kernel.BrowserComputerMoveMouseParams{
+ X: 500,
+ Y: 300,
+ }); err != nil {
+ panic(err)
+ }
+
+ // Smooth movement with custom duration
+ if err := client.Browsers.Computer.MoveMouse(ctx, kernelBrowser.SessionID, kernel.BrowserComputerMoveMouseParams{
+ X: 800,
+ Y: 600,
+ Smooth: kernel.Bool(true),
+ DurationMs: kernel.Int(1500),
+ }); err != nil {
+ panic(err)
+ }
+
+ // Instant teleport (disable smooth)
+ if err := client.Browsers.Computer.MoveMouse(ctx, kernelBrowser.SessionID, kernel.BrowserComputerMoveMouseParams{
+ X: 100,
+ Y: 200,
+ Smooth: kernel.Bool(false),
+ }); err != nil {
+ panic(err)
+ }
+}
+```
+
```bash CLI
# Smooth movement (default)
kernel browsers computer move-mouse --x 500 --y 300
@@ -210,6 +295,68 @@ with open('region.png', 'wb') as f:
f.write(image_data.read())
```
+```go Go
+package main
+
+import (
+ "context"
+ "io"
+ "os"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ // Full screenshot
+ response, err := client.Browsers.Computer.CaptureScreenshot(ctx, kernelBrowser.SessionID, kernel.BrowserComputerCaptureScreenshotParams{})
+ if err != nil {
+ panic(err)
+ }
+ imageData, err := io.ReadAll(response.Body)
+ closeErr := response.Body.Close()
+ if err != nil {
+ panic(err)
+ }
+ if closeErr != nil {
+ panic(closeErr)
+ }
+ if err := os.WriteFile("screenshot.png", imageData, 0644); err != nil {
+ panic(err)
+ }
+
+ // Region screenshot
+ response, err = client.Browsers.Computer.CaptureScreenshot(ctx, kernelBrowser.SessionID, kernel.BrowserComputerCaptureScreenshotParams{
+ Region: kernel.BrowserComputerCaptureScreenshotParamsRegion{
+ X: 0,
+ Y: 0,
+ Width: 800,
+ Height: 600,
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ imageData, err = io.ReadAll(response.Body)
+ closeErr = response.Body.Close()
+ if err != nil {
+ panic(err)
+ }
+ if closeErr != nil {
+ panic(closeErr)
+ }
+ if err := os.WriteFile("region.png", imageData, 0644); err != nil {
+ panic(err)
+ }
+}
+```
+
```bash CLI
# Take a full screenshot
kernel browsers computer screenshot --to screenshot.png
@@ -297,6 +444,40 @@ kernel.browsers.computer.type_text(
)
```
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ // Type literal text
+ if err := client.Browsers.Computer.TypeText(ctx, kernelBrowser.SessionID, kernel.BrowserComputerTypeTextParams{
+ Text: "The quick brown fox jumps over the lazy dog.",
+ }); err != nil {
+ panic(err)
+ }
+
+ // Fixed delay between keystrokes
+ if err := client.Browsers.Computer.TypeText(ctx, kernelBrowser.SessionID, kernel.BrowserComputerTypeTextParams{
+ Text: "Slow typing...",
+ Delay: kernel.Int(100),
+ }); err != nil {
+ panic(err)
+ }
+}
+```
+
```bash CLI
# Human-like smooth typing (default)
kernel browsers computer type --text "The quick brown fox"
@@ -363,6 +544,41 @@ kernel.browsers.computer.press_key(
)
```
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ // Tap a key combination
+ if err := client.Browsers.Computer.PressKey(ctx, kernelBrowser.SessionID, kernel.BrowserComputerPressKeyParams{
+ Keys: []string{"Ctrl+t"},
+ }); err != nil {
+ panic(err)
+ }
+
+ // Hold keys for 250ms while also holding Alt
+ if err := client.Browsers.Computer.PressKey(ctx, kernelBrowser.SessionID, kernel.BrowserComputerPressKeyParams{
+ Keys: []string{"Ctrl+Shift+Tab"},
+ Duration: kernel.Int(250),
+ HoldKeys: []string{"Alt"},
+ }); err != nil {
+ panic(err)
+ }
+}
+```
+
```bash CLI
# Press one or more keys (repeatable --key)
kernel browsers computer press-key --key Ctrl+t
@@ -406,6 +622,34 @@ kernel.browsers.computer.scroll(
)
```
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ if err := client.Browsers.Computer.Scroll(ctx, kernelBrowser.SessionID, kernel.BrowserComputerScrollParams{
+ X: 300,
+ Y: 400,
+ DeltaX: kernel.Int(0),
+ DeltaY: kernel.Int(120),
+ }); err != nil {
+ panic(err)
+ }
+}
+```
+
```bash CLI
# Scroll at a position
kernel browsers computer scroll --x 300 --y 400 --delta-y 120
@@ -504,6 +748,63 @@ kernel.browsers.computer.drag_mouse(
)
```
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ // Human-like smooth drag (default)
+ if err := client.Browsers.Computer.DragMouse(ctx, kernelBrowser.SessionID, kernel.BrowserComputerDragMouseParams{
+ Path: [][]int64{
+ {100, 200},
+ {400, 350},
+ {700, 200},
+ },
+ }); err != nil {
+ panic(err)
+ }
+
+ // Smooth drag with custom duration
+ if err := client.Browsers.Computer.DragMouse(ctx, kernelBrowser.SessionID, kernel.BrowserComputerDragMouseParams{
+ Path: [][]int64{
+ {100, 200},
+ {400, 350},
+ {700, 200},
+ },
+ Smooth: kernel.Bool(true),
+ DurationMs: kernel.Int(2000),
+ }); err != nil {
+ panic(err)
+ }
+
+ // Linear interpolation drag (legacy behavior)
+ if err := client.Browsers.Computer.DragMouse(ctx, kernelBrowser.SessionID, kernel.BrowserComputerDragMouseParams{
+ Path: [][]int64{
+ {100, 200},
+ {400, 350},
+ {700, 200},
+ },
+ Smooth: kernel.Bool(false),
+ StepsPerSegment: kernel.Int(10),
+ StepDelayMs: kernel.Int(50),
+ }); err != nil {
+ panic(err)
+ }
+}
+```
+
```bash CLI
# Smooth drag (default)
kernel browsers computer drag-mouse \
diff --git a/browsers/curl.mdx b/browsers/curl.mdx
index bb42a03..af810c8 100644
--- a/browsers/curl.mdx
+++ b/browsers/curl.mdx
@@ -49,6 +49,45 @@ browser = client.browsers.create()
response: httpx.Response = client.browsers.request(browser.session_id, "GET", "https://example.com")
print("status", response.status_code)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+ "io"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ httpClient, err := client.Browsers.HTTPClient(browser.SessionID)
+ if err != nil {
+ panic(err)
+ }
+
+ response, err := httpClient.Get("https://example.com")
+ if err != nil {
+ panic(err)
+ }
+ defer response.Body.Close()
+
+ body, err := io.ReadAll(response.Body)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println("body", string(body))
+}
+```
## Buffered browser curl
@@ -82,6 +121,36 @@ browser = client.browsers.create()
buffered = client.browsers.curl(browser.session_id, url="https://example.com", method="GET")
print("body", buffered.body)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ buffered, err := client.Browsers.Curl(ctx, browser.SessionID, kernel.BrowserCurlParams{
+ URL: "https://example.com",
+ Method: kernel.BrowserCurlParamsMethodGet,
+ })
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println("body", buffered.Body)
+}
+```
## Concurrency limits
diff --git a/browsers/extensions.mdx b/browsers/extensions.mdx
index 736997c..1c9da35 100644
--- a/browsers/extensions.mdx
+++ b/browsers/extensions.mdx
@@ -70,6 +70,32 @@ kernel = Kernel()
kernel_browser = kernel.browsers.create(extensions=[{"name": "my-extension"}])
```
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+ "github.com/kernel/kernel-go-sdk/shared"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Extensions: []shared.BrowserExtensionParam{
+ {Name: kernel.String("my-extension")},
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = kernelBrowser
+}
+```
+
```bash CLI
kernel browsers create --extension my-extension
```
diff --git a/browsers/gpu-acceleration.mdx b/browsers/gpu-acceleration.mdx
index 638d2ab..e9381e0 100644
--- a/browsers/gpu-acceleration.mdx
+++ b/browsers/gpu-acceleration.mdx
@@ -32,6 +32,29 @@ kernel_browser = kernel.browsers.create(
gpu=True
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ GPU: kernel.Bool(true),
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = kernelBrowser
+}
+```
You can also enable GPU acceleration in the dashboard when deploying a browser under **Advanced Configuration**.
diff --git a/browsers/headless.mdx b/browsers/headless.mdx
index ae8b239..b2bb1d9 100644
--- a/browsers/headless.mdx
+++ b/browsers/headless.mdx
@@ -27,6 +27,29 @@ kernel = Kernel()
kernel_browser = kernel.browsers.create(headless=True)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Headless: kernel.Bool(true),
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = kernelBrowser
+}
+```
diff --git a/browsers/live-view.mdx b/browsers/live-view.mdx
index 788379f..c111407 100644
--- a/browsers/live-view.mdx
+++ b/browsers/live-view.mdx
@@ -24,6 +24,29 @@ kernel = Kernel()
browser = kernel.browsers.create()
print(browser.browser_live_view_url)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(browser.BrowserLiveViewURL)
+}
+```
@@ -82,6 +105,16 @@ kernel_browser = kernel.browsers.create(
)
```
+```go Go
+browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ KioskMode: kernel.Bool(true),
+})
+if err != nil {
+ panic(err)
+}
+_ = browser
+```
+
## URL lifetime
diff --git a/browsers/playwright-execution.mdx b/browsers/playwright-execution.mdx
index 9b28602..fd05c76 100644
--- a/browsers/playwright-execution.mdx
+++ b/browsers/playwright-execution.mdx
@@ -60,6 +60,41 @@ response = kernel.browsers.playwright.execute(
print(response.result) # "Example Domain"
```
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ // Create a browser
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ // Execute Playwright code
+ response, err := client.Browsers.Playwright.Execute(ctx, kernelBrowser.SessionID, kernel.BrowserPlaywrightExecuteParams{
+ Code: `
+ await page.goto('https://example.com');
+ return await page.title();
+ `,
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(response.Result) // "Example Domain"
+}
+```
+
```bash CLI
kernel browsers playwright execute 'await page.goto("https://www.onkernel.com"); return page.title();'
```
@@ -107,6 +142,22 @@ response = kernel.browsers.playwright.execute(
print(response.result) # {'title': 'Example Domain', 'url': 'https://example.com'}
```
+
+```go Go
+response, err := client.Browsers.Playwright.Execute(ctx, sessionID, kernel.BrowserPlaywrightExecuteParams{
+ Code: `
+ await page.goto('https://example.com');
+ const title = await page.title();
+ const url = page.url();
+ return { title, url };
+ `,
+})
+if err != nil {
+ panic(err)
+}
+
+fmt.Println(response.Result) // map[title:Example Domain url:https://example.com]
+```
## Timeout configuration
@@ -137,6 +188,20 @@ response = kernel.browsers.playwright.execute(
timeout_sec=120
)
```
+
+```go Go
+response, err := client.Browsers.Playwright.Execute(ctx, sessionID, kernel.BrowserPlaywrightExecuteParams{
+ Code: `
+ await page.goto('https://example.com');
+ return await page.title();
+ `,
+ TimeoutSec: kernel.Int(120),
+})
+if err != nil {
+ panic(err)
+}
+_ = response
+```
## Error handling
@@ -174,6 +239,23 @@ if not response.success:
print('Error:', response.error)
print('Stderr:', response.stderr)
```
+
+```go Go
+response, err := client.Browsers.Playwright.Execute(ctx, sessionID, kernel.BrowserPlaywrightExecuteParams{
+ Code: `
+ await page.goto('https://invalid-url');
+ return await page.title();
+ `,
+})
+if err != nil {
+ panic(err)
+}
+
+if !response.Success {
+ fmt.Println("Error:", response.Error)
+ fmt.Println("Stderr:", response.Stderr)
+}
+```
## Use cases
diff --git a/browsers/pools/overview.mdx b/browsers/pools/overview.mdx
index bec0d85..d3ffd1c 100644
--- a/browsers/pools/overview.mdx
+++ b/browsers/pools/overview.mdx
@@ -82,6 +82,41 @@ pool = kernel.browser_pools.create(
print(pool.id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+ "github.com/kernel/kernel-go-sdk/shared"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ pool, err := client.BrowserPools.New(ctx, kernel.BrowserPoolNewParams{
+ Name: kernel.String("my-pool"),
+ Size: 10,
+ Stealth: kernel.Bool(true),
+ Headless: kernel.Bool(false),
+ TimeoutSeconds: kernel.Int(600),
+ StartURL: kernel.String("https://example.com"),
+ Viewport: shared.BrowserViewportParam{
+ Width: 1280,
+ Height: 800,
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(pool.ID)
+}
+```
### Pool configuration options
@@ -111,6 +146,18 @@ browser = kernel.browser_pools.acquire(
print(browser.session_id)
print(browser.cdp_ws_url)
```
+
+```go Go
+browser, err := client.BrowserPools.Acquire(ctx, "my-pool", kernel.BrowserPoolAcquireParams{
+ AcquireTimeoutSeconds: kernel.Int(30),
+})
+if err != nil {
+ panic(err)
+}
+
+fmt.Println(browser.SessionID)
+fmt.Println(browser.CdpWsURL)
+```
The acquired browser includes all the same properties as a regular browser session, including `cdp_ws_url` for CDP connections and `browser_live_view_url` for live viewing.
@@ -138,6 +185,15 @@ kernel.browser_pools.release(
reuse=True,
)
```
+
+```go Go
+if err := client.BrowserPools.Release(ctx, "my-pool", kernel.BrowserPoolReleaseParams{
+ SessionID: browser.SessionID,
+ Reuse: kernel.Bool(true),
+}); err != nil {
+ panic(err)
+}
+```
## Update a pool
@@ -159,6 +215,17 @@ updated_pool = kernel.browser_pools.update(
stealth=True,
)
```
+
+```go Go
+updatedPool, err := client.BrowserPools.Update(ctx, "my-pool", kernel.BrowserPoolUpdateParams{
+ Size: 20,
+ Stealth: kernel.Bool(true),
+})
+if err != nil {
+ panic(err)
+}
+_ = updatedPool
+```
@@ -179,6 +246,12 @@ await kernel.browserPools.flush("my-pool");
```python Python
kernel.browser_pools.flush("my-pool")
```
+
+```go Go
+if err := client.BrowserPools.Flush(ctx, "my-pool"); err != nil {
+ panic(err)
+}
+```
## Get pool details
@@ -199,6 +272,16 @@ pool = kernel.browser_pools.retrieve("my-pool")
print(pool.available_count)
print(pool.acquired_count)
```
+
+```go Go
+pool, err := client.BrowserPools.Get(ctx, "my-pool")
+if err != nil {
+ panic(err)
+}
+
+fmt.Println(pool.AvailableCount)
+fmt.Println(pool.AcquiredCount)
+```
## List pools
@@ -220,6 +303,17 @@ pools = kernel.browser_pools.list()
for pool in pools:
print(pool.name, pool.available_count)
```
+
+```go Go
+pools, err := client.BrowserPools.List(ctx)
+if err != nil {
+ panic(err)
+}
+
+for _, pool := range *pools {
+ fmt.Println(pool.Name, pool.AvailableCount)
+}
+```
## Delete a pool
@@ -242,6 +336,20 @@ kernel.browser_pools.delete("my-pool")
# Force delete even if browsers are acquired
kernel.browser_pools.delete("my-pool", force=True)
```
+
+```go Go
+// Delete a pool (fails if browsers are acquired)
+if err := client.BrowserPools.Delete(ctx, "my-pool", kernel.BrowserPoolDeleteParams{}); err != nil {
+ panic(err)
+}
+
+// Force delete even if browsers are acquired
+if err := client.BrowserPools.Delete(ctx, "my-pool", kernel.BrowserPoolDeleteParams{
+ Force: kernel.Bool(true),
+}); err != nil {
+ panic(err)
+}
+```
## Full example
@@ -305,6 +413,49 @@ async def main():
asyncio.run(main())
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ // Acquire a browser from an existing pool
+ kernelBrowser, err := client.BrowserPools.Acquire(ctx, "my-pool", kernel.BrowserPoolAcquireParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ defer func() {
+ // Release back to pool for reuse
+ if err := client.BrowserPools.Release(ctx, "my-pool", kernel.BrowserPoolReleaseParams{
+ SessionID: kernelBrowser.SessionID,
+ }); err != nil {
+ panic(err)
+ }
+ }()
+
+ response, err := client.Browsers.Playwright.Execute(ctx, kernelBrowser.SessionID, kernel.BrowserPlaywrightExecuteParams{
+ Code: `
+ await page.goto('https://example.com');
+ return await page.title();
+ `,
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(response.Result)
+}
+```
## API reference
diff --git a/browsers/pools/policy-json.mdx b/browsers/pools/policy-json.mdx
index 1bd9c0d..3957b32 100644
--- a/browsers/pools/policy-json.mdx
+++ b/browsers/pools/policy-json.mdx
@@ -1,5 +1,5 @@
---
-title: "custom chrome policies"
+title: "Custom Chrome Policies"
description: "Customize Chrome behavior in reserved browser pools using Chrome policies"
---
@@ -77,6 +77,53 @@ pool = kernel.browser_pools.create(
}
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ pool, err := client.BrowserPools.New(ctx, kernel.BrowserPoolNewParams{
+ Name: kernel.String("my-configured-pool"),
+ Size: 5,
+ ChromePolicy: map[string]any{
+ "HomepageLocation": "https://kernel.sh",
+ "HomepageIsNewTabPage": false,
+ "ShowHomeButton": true,
+ "NewTabPageLocation": "https://kernel.sh/docs",
+ "RestoreOnStartup": 4,
+ "RestoreOnStartupURLs": []string{"https://kernel.sh"},
+ "BookmarkBarEnabled": true,
+ "ManagedBookmarks": []map[string]any{
+ {"toplevel_name": "Company Resources"},
+ {"name": "Dashboard", "url": "https://example.com/dashboard"},
+ {"name": "Documentation", "url": "https://example.com/docs"},
+ {
+ "name": "Tools",
+ "children": []map[string]string{
+ {"name": "Jira Board", "url": "https://example.com/jira"},
+ {"name": "Slack", "url": "https://example.com/slack"},
+ {"name": "GitHub PRs", "url": "https://example.com/github"},
+ {"name": "Runbooks", "url": "https://example.com/runbooks"},
+ },
+ },
+ },
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = pool
+}
+```
## Updating policies on an existing pool
diff --git a/browsers/replays.mdx b/browsers/replays.mdx
index a9964dd..751bf89 100644
--- a/browsers/replays.mdx
+++ b/browsers/replays.mdx
@@ -39,6 +39,42 @@ print(f"Recording started with ID: {replay.replay_id}")
kernel.browsers.replays.stop(replay_id=replay.replay_id, id=kernel_browser.session_id)
print("Recording stopped and processing")
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ replay, err := client.Browsers.Replays.Start(ctx, kernelBrowser.SessionID, kernel.BrowserReplayStartParams{})
+ if err != nil {
+ panic(err)
+ }
+ fmt.Printf("Recording started with ID: %s\n", replay.ReplayID)
+
+ // Perform some automation...
+
+ if err := client.Browsers.Replays.Stop(ctx, replay.ReplayID, kernel.BrowserReplayStopParams{
+ ID: kernelBrowser.SessionID,
+ }); err != nil {
+ panic(err)
+ }
+ fmt.Println("Recording stopped and processing")
+}
+```
## Multiple recordings per session
@@ -65,6 +101,30 @@ replay2 = kernel.browsers.replays.start(kernel_browser.session_id)
# Perform different automation...
kernel.browsers.replays.stop(replay_id=replay2.replay_id, id=kernel_browser.session_id)
```
+
+```go Go
+replay1, err := client.Browsers.Replays.Start(ctx, kernelBrowser.SessionID, kernel.BrowserReplayStartParams{})
+if err != nil {
+ panic(err)
+}
+// Perform some automation...
+if err := client.Browsers.Replays.Stop(ctx, replay1.ReplayID, kernel.BrowserReplayStopParams{
+ ID: kernelBrowser.SessionID,
+}); err != nil {
+ panic(err)
+}
+
+replay2, err := client.Browsers.Replays.Start(ctx, kernelBrowser.SessionID, kernel.BrowserReplayStartParams{})
+if err != nil {
+ panic(err)
+}
+// Perform different automation...
+if err := client.Browsers.Replays.Stop(ctx, replay2.ReplayID, kernel.BrowserReplayStopParams{
+ ID: kernelBrowser.SessionID,
+}); err != nil {
+ panic(err)
+}
+```
## Downloading all replays
@@ -117,4 +177,63 @@ for replay in replays:
print(f"Saved replay to {filename}")
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "os"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ sessionID := "brw_01jwv4tn5m8k3q2v7x9p0a1bc2"
+
+ replays, err := client.Browsers.Replays.List(ctx, sessionID)
+ if err != nil {
+ panic(err)
+ }
+
+ for _, replay := range *replays {
+ fmt.Printf("Replay ID: %s\n", replay.ReplayID)
+ fmt.Printf("View URL: %s\n", replay.ReplayViewURL)
+
+ videoData, err := client.Browsers.Replays.Download(ctx, replay.ReplayID, kernel.BrowserReplayDownloadParams{
+ ID: sessionID,
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ filename := fmt.Sprintf("replay-%s-%s.mp4", replay.ReplayID, sessionID)
+ file, err := os.Create(filename)
+ if err != nil {
+ videoData.Body.Close()
+ panic(err)
+ }
+
+ _, copyErr := io.Copy(file, videoData.Body)
+ closeErr := videoData.Body.Close()
+ fileErr := file.Close()
+ if copyErr != nil {
+ panic(copyErr)
+ }
+ if closeErr != nil {
+ panic(closeErr)
+ }
+ if fileErr != nil {
+ panic(fileErr)
+ }
+
+ fmt.Printf("Saved replay to %s\n", filename)
+ }
+}
+```
diff --git a/browsers/termination.mdx b/browsers/termination.mdx
index 79e2f22..add3c18 100644
--- a/browsers/termination.mdx
+++ b/browsers/termination.mdx
@@ -27,6 +27,25 @@ from kernel import Kernel
kernel = Kernel()
kernel.browsers.delete_by_id("htzv5orfit78e1m2biiifpbv")
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ if err := client.Browsers.DeleteByID(ctx, "htzv5orfit78e1m2biiifpbv"); err != nil {
+ panic(err)
+ }
+}
+```
## Automatic deletion via timeout
@@ -53,4 +72,29 @@ kernel = Kernel()
browser = kernel.browsers.create(timeout_seconds=300)
print(browser.session_id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ TimeoutSeconds: kernel.Int(300),
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(browser.SessionID)
+}
+```
diff --git a/browsers/viewport.mdx b/browsers/viewport.mdx
index 37799ca..0c2d83b 100644
--- a/browsers/viewport.mdx
+++ b/browsers/viewport.mdx
@@ -21,6 +21,15 @@ const defaultViewport = await kernel.browsers.create();
default_viewport = kernel.browsers.create()
```
+```go Go
+// Uses default viewport (1920x1080@25Hz)
+defaultViewport, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+if err != nil {
+ panic(err)
+}
+_ = defaultViewport
+```
+
## Setting viewport configuration
@@ -79,6 +88,47 @@ kernel_browser_auto = kernel.browsers.create(
)
```
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+ "github.com/kernel/kernel-go-sdk/shared"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ // Explicitly specify refresh rate
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Viewport: shared.BrowserViewportParam{
+ Width: 1920,
+ Height: 1080,
+ RefreshRate: kernel.Int(25),
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = kernelBrowser
+
+ // Auto-determine refresh rate from dimensions (25Hz for 1920x1080)
+ kernelBrowserAuto, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Viewport: shared.BrowserViewportParam{
+ Width: 1920,
+ Height: 1080,
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = kernelBrowserAuto
+}
+```
+
@@ -200,6 +250,71 @@ wuxga = kernel.browsers.create(
)
```
+```go Go
+// Full HD (1920x1080) at 25Hz - explicit refresh rate
+fullHD, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Viewport: shared.BrowserViewportParam{
+ Width: 1920,
+ Height: 1080,
+ RefreshRate: kernel.Int(25),
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = fullHD
+
+// Full HD (1920x1080) - auto-determined 25Hz (Default configuration)
+fullHDAuto, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Viewport: shared.BrowserViewportParam{
+ Width: 1920,
+ Height: 1080,
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = fullHDAuto
+
+// QHD (2560x1440) - auto-determined 10Hz
+// Note: May affect live view responsiveness
+qhd, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Viewport: shared.BrowserViewportParam{
+ Width: 2560,
+ Height: 1440,
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = qhd
+
+// XGA (1024x768) - auto-determined 60Hz
+xga, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Viewport: shared.BrowserViewportParam{
+ Width: 1024,
+ Height: 768,
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = xga
+
+// WUXGA (1920x1200) at 25Hz - explicit refresh rate
+wuxga, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Viewport: shared.BrowserViewportParam{
+ Width: 1920,
+ Height: 1200,
+ RefreshRate: kernel.Int(25),
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = wuxga
+```
+
## Dynamically changing the viewport
@@ -227,6 +342,27 @@ kernel_browser = await kernel.browsers.create()
# Later, change the viewport
await kernel.browsers.update(kernel_browser.session_id, viewport={"width": 1024, "height": 768})
```
+
+```go Go
+// Create a browser with default viewport
+kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+if err != nil {
+ panic(err)
+}
+
+// Later, change the viewport
+_, err = client.Browsers.Update(ctx, kernelBrowser.SessionID, kernel.BrowserUpdateParams{
+ Viewport: kernel.BrowserUpdateParamsViewport{
+ BrowserViewportParam: shared.BrowserViewportParam{
+ Width: 1024,
+ Height: 768,
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+```
@@ -256,6 +392,21 @@ await kernel.browsers.update(
viewport={"width": 1024, "height": 768, "force": True}
)
```
+
+```go Go
+_, err := client.Browsers.Update(ctx, kernelBrowser.SessionID, kernel.BrowserUpdateParams{
+ Viewport: kernel.BrowserUpdateParamsViewport{
+ BrowserViewportParam: shared.BrowserViewportParam{
+ Width: 1024,
+ Height: 768,
+ },
+ Force: kernel.Bool(true),
+ },
+})
+if err != nil {
+ panic(err)
+}
+```
## Considerations
diff --git a/info/api-keys.mdx b/info/api-keys.mdx
index 20194ed..1f3b741 100644
--- a/info/api-keys.mdx
+++ b/info/api-keys.mdx
@@ -58,6 +58,34 @@ api_key = client.api_keys.create(
print(api_key.key) # Save this value now. Kernel won't show it again.
print(api_key.id, api_key.masked_key)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ apiKey, err := client.APIKeys.New(ctx, kernel.APIKeyNewParams{
+ Name: "staging-ci",
+ DaysToExpire: kernel.Int(30),
+ ProjectID: kernel.String("proj_staging_9f3k"),
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(apiKey.Key) // Save this value now. Kernel won't show it again.
+ fmt.Println(apiKey.ID, apiKey.MaskedKey)
+}
+```
## List and inspect API keys
@@ -86,6 +114,40 @@ for api_key in client.api_keys.list(limit=20):
api_key = client.api_keys.retrieve("key_01jwv4tn5m8k3q2v7x9p0a1bc2")
print(api_key.project_id, api_key.expires_at)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ pager := client.APIKeys.ListAutoPaging(ctx, kernel.APIKeyListParams{
+ Limit: kernel.Int(20),
+ })
+ for pager.Next() {
+ apiKey := pager.Current()
+ fmt.Println(apiKey.ID, apiKey.Name, apiKey.MaskedKey)
+ }
+ if err := pager.Err(); err != nil {
+ panic(err)
+ }
+
+ apiKey, err := client.APIKeys.Get(ctx, "key_01jwv4tn5m8k3q2v7x9p0a1bc2")
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(apiKey.ProjectID, apiKey.ExpiresAt)
+}
+```
## Rename or delete an API key
@@ -114,6 +176,38 @@ client.api_keys.update(
client.api_keys.delete("key_01jwv4tn5m8k3q2v7x9p0a1bc2")
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ apiKey, err := client.APIKeys.Update(
+ ctx,
+ "key_01jwv4tn5m8k3q2v7x9p0a1bc2",
+ kernel.APIKeyUpdateParams{
+ Name: "staging-ci-rotated",
+ },
+ )
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println(apiKey.ID, apiKey.Name)
+
+ if err := client.APIKeys.Delete(ctx, "key_01jwv4tn5m8k3q2v7x9p0a1bc2"); err != nil {
+ panic(err)
+ }
+}
+```
## Rotate a key
diff --git a/info/projects.mdx b/info/projects.mdx
index 9693db7..0a6764e 100644
--- a/info/projects.mdx
+++ b/info/projects.mdx
@@ -70,6 +70,43 @@ other = kernel.browsers.create(
extra_headers={"X-Kernel-Project-Id": "proj_def456"},
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+ "github.com/kernel/kernel-go-sdk/option"
+)
+
+func main() {
+ ctx := context.Background()
+
+ // Scope the whole client to a project.
+ client := kernel.NewClient(
+ option.WithHeader("X-Kernel-Project-Id", "proj_abc123"),
+ )
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+ _ = browser
+
+ // Or override per-request.
+ other, err := client.Browsers.New(
+ ctx,
+ kernel.BrowserNewParams{},
+ option.WithHeader("X-Kernel-Project-Id", "proj_def456"),
+ )
+ if err != nil {
+ panic(err)
+ }
+ _ = other
+}
+```
## Authentication and Project Scope
@@ -143,6 +180,33 @@ kernel = Kernel()
project = kernel.projects.create(name="staging")
print(project.id) # proj_abc123
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ project, err := client.Projects.New(ctx, kernel.ProjectNewParams{
+ CreateProjectRequest: kernel.CreateProjectRequestParam{
+ Name: "staging",
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(project.ID) // proj_abc123
+}
+```
### List projects
@@ -158,6 +222,17 @@ for await (const project of kernel.projects.list()) {
for project in kernel.projects.list():
print(project.id, project.name, project.status)
```
+
+```go Go
+pager := client.Projects.ListAutoPaging(ctx, kernel.ProjectListParams{})
+for pager.Next() {
+ project := pager.Current()
+ fmt.Println(project.ID, project.Name, project.Status)
+}
+if err := pager.Err(); err != nil {
+ panic(err)
+}
+```
### Update a project
@@ -170,6 +245,22 @@ await kernel.projects.update('proj_abc123', { name: 'production' });
```python Python
kernel.projects.update("proj_abc123", name="production")
```
+
+```go Go
+project, err := client.Projects.Update(
+ ctx,
+ "proj_abc123",
+ kernel.ProjectUpdateParams{
+ UpdateProjectRequest: kernel.UpdateProjectRequestParam{
+ Name: kernel.String("production"),
+ },
+ },
+)
+if err != nil {
+ panic(err)
+}
+_ = project
+```
### Delete a project
@@ -182,6 +273,12 @@ await kernel.projects.delete('proj_abc123');
```python Python
kernel.projects.delete("proj_abc123")
```
+
+```go Go
+if err := client.Projects.Delete(ctx, "proj_abc123"); err != nil {
+ panic(err)
+}
+```
diff --git a/integrations/1password.mdx b/integrations/1password.mdx
index ea809e4..e93775b 100644
--- a/integrations/1password.mdx
+++ b/integrations/1password.mdx
@@ -69,6 +69,44 @@ auth = await kernel.auth.connections.create(
login = await kernel.auth.connections.login(auth.id)
```
+
+```go Go
+// Option 1: Auto-lookup by domain
+auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "github.com",
+ ProfileName: "my-github-profile",
+ Credential: kernel.ManagedAuthCreateRequestCredentialParam{
+ Provider: kernel.String("my-1p"),
+ Auto: kernel.Bool(true),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+
+// Option 2: Explicit item path (VaultName/ItemName)
+auth, err = client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
+ ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
+ Domain: "github.com",
+ ProfileName: "my-github-profile",
+ Credential: kernel.ManagedAuthCreateRequestCredentialParam{
+ Provider: kernel.String("my-1p"),
+ Path: kernel.String("Engineering/github-login"),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+if err != nil {
+ panic(err)
+}
+_ = login
+```
diff --git a/introduction/control.mdx b/introduction/control.mdx
index 820efc9..9c4e6a7 100644
--- a/introduction/control.mdx
+++ b/introduction/control.mdx
@@ -47,6 +47,57 @@ Kernel browsers expose four ways to drive a session. For agents, we recommend [c
text="kernel cloud browsers",
)
```
+
+ ```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ screenshot, err := client.Browsers.Computer.CaptureScreenshot(
+ ctx,
+ kernelBrowser.SessionID,
+ kernel.BrowserComputerCaptureScreenshotParams{},
+ )
+ if err != nil {
+ panic(err)
+ }
+ defer screenshot.Body.Close()
+
+ if err := client.Browsers.Computer.ClickMouse(
+ ctx,
+ kernelBrowser.SessionID,
+ kernel.BrowserComputerClickMouseParams{
+ X: 420,
+ Y: 280,
+ },
+ ); err != nil {
+ panic(err)
+ }
+
+ if err := client.Browsers.Computer.TypeText(
+ ctx,
+ kernelBrowser.SessionID,
+ kernel.BrowserComputerTypeTextParams{
+ Text: "kernel cloud browsers",
+ },
+ ); err != nil {
+ panic(err)
+ }
+}
+ ```
@@ -78,6 +129,24 @@ Kernel browsers expose four ways to drive a session. For agents, we recommend [c
print(response.result)
```
+
+ ```go Go
+response, err := client.Browsers.Playwright.Execute(
+ ctx,
+ kernelBrowser.SessionID,
+ kernel.BrowserPlaywrightExecuteParams{
+ Code: `
+ await page.goto('https://example.com');
+ return await page.title();
+ `,
+ },
+)
+if err != nil {
+ panic(err)
+}
+
+fmt.Println(response.Result)
+ ```
@@ -193,6 +262,26 @@ response = kernel.browsers.playwright.execute(
print(response.result)
```
+
+```go Go
+response, err := client.Browsers.Playwright.Execute(
+ ctx,
+ kernelBrowser.SessionID,
+ kernel.BrowserPlaywrightExecuteParams{
+ Code: `
+ const rows = await page.$$eval('table tr', (trs) =>
+ trs.map((tr) => Array.from(tr.querySelectorAll('td')).map((td) => td.textContent))
+ );
+ return rows;
+ `,
+ },
+)
+if err != nil {
+ panic(err)
+}
+
+fmt.Println(response.Result)
+```
## Going deeper
diff --git a/introduction/create.mdx b/introduction/create.mdx
index 78c01fe..beaf91c 100644
--- a/introduction/create.mdx
+++ b/introduction/create.mdx
@@ -11,6 +11,7 @@ Kernel browsers are sandboxed Chromium instances that boot in under 30ms. Your a
Install the Kernel SDK first:
- Typescript/Javascript: `npm install @onkernel/sdk`
- Python: `pip install kernel`
+ - Go: `go get github.com/kernel/kernel-go-sdk`
@@ -32,6 +33,29 @@ kernel_browser = kernel.browsers.create()
print(kernel_browser.session_id)
```
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(kernelBrowser.SessionID)
+}
+```
+
```bash CLI
kernel browsers create
@@ -76,6 +100,12 @@ await kernel.browsers.deleteByID(kernelBrowser.session_id);
kernel.browsers.delete_by_id(kernel_browser.session_id)
```
+```go Go
+if err := client.Browsers.DeleteByID(ctx, kernelBrowser.SessionID); err != nil {
+ panic(err)
+}
+```
+
```bash CLI
kernel browsers delete
```
@@ -134,6 +164,48 @@ except Exception as e:
finally:
kernel.browsers.delete_by_id(kernel_browser.session_id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+ defer func() {
+ if err := client.Browsers.DeleteByID(ctx, kernelBrowser.SessionID); err != nil {
+ panic(err)
+ }
+ }()
+
+ response, err := client.Browsers.Playwright.Execute(
+ ctx,
+ kernelBrowser.SessionID,
+ kernel.BrowserPlaywrightExecuteParams{
+ Code: `
+ await page.goto('https://www.onkernel.com');
+ return await page.title();
+ `,
+ },
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(response.Result)
+}
+```
## What's next
diff --git a/introduction/observe.mdx b/introduction/observe.mdx
index fba6a8f..4f22a6e 100644
--- a/introduction/observe.mdx
+++ b/introduction/observe.mdx
@@ -28,6 +28,29 @@ kernel_browser = kernel.browsers.create()
print(kernel_browser.browser_live_view_url)
```
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(kernelBrowser.BrowserLiveViewURL)
+}
+```
+
```bash CLI
kernel browsers view
```
@@ -63,6 +86,23 @@ kernel.browsers.replays.stop(
)
```
+```go Go
+replay, err := client.Browsers.Replays.Start(ctx, kernelBrowser.SessionID, kernel.BrowserReplayStartParams{})
+if err != nil {
+ panic(err)
+}
+
+// ...run the agent...
+
+if err := client.Browsers.Replays.Stop(
+ ctx,
+ replay.ReplayID,
+ kernel.BrowserReplayStopParams{ID: kernelBrowser.SessionID},
+); err != nil {
+ panic(err)
+}
+```
+
```bash CLI
# Start recording
kernel browsers replays start
@@ -94,6 +134,18 @@ screenshot = kernel.browsers.computer.capture_screenshot(
)
```
+```go Go
+screenshot, err := client.Browsers.Computer.CaptureScreenshot(
+ ctx,
+ kernelBrowser.SessionID,
+ kernel.BrowserComputerCaptureScreenshotParams{},
+)
+if err != nil {
+ panic(err)
+}
+defer screenshot.Body.Close()
+```
+
```bash CLI
kernel browsers computer screenshot --to screenshot.png
```
@@ -120,6 +172,22 @@ logs = kernel.invocations.follow(invocation_id)
for event in logs:
print(event)
```
+
+```go Go
+stream := client.Invocations.FollowStreaming(
+ ctx,
+ invocationID,
+ kernel.InvocationFollowParams{},
+)
+defer stream.Close()
+
+for stream.Next() {
+ fmt.Println(stream.Current())
+}
+if err := stream.Err(); err != nil {
+ panic(err)
+}
+```
Full reference: [Logs](/apps/logs).
diff --git a/proxies/custom.mdx b/proxies/custom.mdx
index 029bdfc..ae7f5ae 100644
--- a/proxies/custom.mdx
+++ b/proxies/custom.mdx
@@ -54,6 +54,46 @@ proxy = kernel.proxies.create(
browser = kernel.browsers.create(proxy_id=proxy.id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeCustom,
+ Name: kernel.String("my-private-proxy"),
+ Protocol: kernel.ProxyNewParamsProtocolHTTPS,
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigCreateCustomProxyConfig: &kernel.ProxyNewParamsConfigCreateCustomProxyConfig{
+ Host: "proxy.example.com",
+ Port: 443,
+ Username: kernel.String("user123"),
+ Password: kernel.String("secure_password"),
+ },
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ ProxyID: kernel.String(proxy.ID),
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = browser
+}
+```
## Configuration Parameters
@@ -118,6 +158,44 @@ proxy = kernel.proxies.create(
]
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeCustom,
+ Name: kernel.String("custom-with-bypass"),
+ Protocol: kernel.ProxyNewParamsProtocolHTTPS,
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigCreateCustomProxyConfig: &kernel.ProxyNewParamsConfigCreateCustomProxyConfig{
+ Host: "proxy.example.com",
+ Port: 443,
+ Username: kernel.String("user123"),
+ Password: kernel.String("secure_password"),
+ },
+ },
+ BypassHosts: []string{
+ "localhost",
+ "internal.service.local",
+ "*.trusted-domain.com",
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = proxy
+}
+```
This is useful for accessing internal services or metadata endpoints without routing through your proxy. See the [overview](/proxies/overview#bypass-hosts) for full bypass host rules.
diff --git a/proxies/datacenter.mdx b/proxies/datacenter.mdx
index 21a9a96..24f1aab 100644
--- a/proxies/datacenter.mdx
+++ b/proxies/datacenter.mdx
@@ -48,6 +48,42 @@ proxy = kernel.proxies.create(
browser = kernel.browsers.create(proxy_id=proxy.id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeDatacenter,
+ Name: kernel.String("my-us-datacenter"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigDatacenterProxyConfig: &kernel.ProxyNewParamsConfigDatacenterProxyConfig{
+ Country: kernel.String("US"),
+ },
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ ProxyID: kernel.String(proxy.ID),
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = browser
+}
+```
## Configuration Parameters
@@ -97,6 +133,40 @@ proxy = kernel.proxies.create(
]
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeDatacenter,
+ Name: kernel.String("datacenter-with-bypass"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigDatacenterProxyConfig: &kernel.ProxyNewParamsConfigDatacenterProxyConfig{
+ Country: kernel.String("US"),
+ },
+ },
+ BypassHosts: []string{
+ "localhost",
+ "internal.service.local",
+ "*.amazonaws.com",
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = proxy
+}
+```
Bypass hosts support exact hostnames and wildcard subdomains (`*.example.com`). See the [overview](/proxies/overview#bypass-hosts) for full details.
diff --git a/proxies/isp.mdx b/proxies/isp.mdx
index b667cc8..45c4fef 100644
--- a/proxies/isp.mdx
+++ b/proxies/isp.mdx
@@ -42,6 +42,37 @@ proxy = kernel.proxies.create(
browser = kernel.browsers.create(proxy_id=proxy.id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeIsp,
+ Name: kernel.String("my-isp-proxy"),
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ ProxyID: kernel.String(proxy.ID),
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = browser
+}
+```
## Configuration Parameters
@@ -84,6 +115,35 @@ proxy = kernel.proxies.create(
]
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeIsp,
+ Name: kernel.String("isp-with-bypass"),
+ BypassHosts: []string{
+ "localhost",
+ "internal.service.local",
+ "*.amazonaws.com",
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = proxy
+}
+```
-See the [overview](/proxies/overview#bypass-hosts) for full bypass host rules and examples.
\ No newline at end of file
+See the [overview](/proxies/overview#bypass-hosts) for full bypass host rules and examples.
diff --git a/proxies/overview.mdx b/proxies/overview.mdx
index 52a4dee..276dd1a 100644
--- a/proxies/overview.mdx
+++ b/proxies/overview.mdx
@@ -43,6 +43,30 @@ kernel = Kernel()
proxy = kernel.proxies.create(type="datacenter")
print(proxy.id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeDatacenter,
+ })
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println(proxy.ID)
+}
+```
@@ -68,6 +92,28 @@ kernel = Kernel()
proxies = kernel.proxies.list()
print(proxies)
```
+
+```go Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxies, err := client.Proxies.List(ctx)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println(proxies)
+}
+```
@@ -109,6 +155,42 @@ proxy = kernel.proxies.create(
browser = kernel.browsers.create(proxy_id=proxy.id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeResidential,
+ Name: kernel.String("my-us-residential"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigResidentialProxyConfig: &kernel.ProxyNewParamsConfigResidentialProxyConfig{
+ Country: kernel.String("US"),
+ },
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ ProxyID: kernel.String(proxy.ID),
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = browser
+}
+```
## Bypass hosts
@@ -155,6 +237,41 @@ proxy = kernel.proxies.create(
]
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeDatacenter,
+ Name: kernel.String("proxy-with-bypass"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigDatacenterProxyConfig: &kernel.ProxyNewParamsConfigDatacenterProxyConfig{
+ Country: kernel.String("US"),
+ },
+ },
+ BypassHosts: []string{
+ "localhost",
+ "internal.company.local",
+ "metadata.google.internal",
+ "*.amazonaws.com",
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = proxy
+}
+```
### Bypass host rules
@@ -249,6 +366,70 @@ kernel.browsers.update(
proxy_id="",
)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ // Create two proxy configurations
+ proxyA, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeIsp,
+ Name: kernel.String("proxy-a"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigIspProxyConfig: &kernel.ProxyNewParamsConfigIspProxyConfig{
+ Country: kernel.String("US"),
+ },
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ proxyB, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeResidential,
+ Name: kernel.String("proxy-b"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigResidentialProxyConfig: &kernel.ProxyNewParamsConfigResidentialProxyConfig{
+ Country: kernel.String("DE"),
+ },
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ // Launch a browser with the first proxy
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ ProxyID: kernel.String(proxyA.ID),
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ // Hot-swap to a different proxy
+ if _, err := client.Browsers.Update(ctx, browser.SessionID, kernel.BrowserUpdateParams{
+ ProxyID: kernel.String(proxyB.ID),
+ }); err != nil {
+ panic(err)
+ }
+
+ // Remove the proxy entirely (route directly to the internet)
+ if _, err := client.Browsers.Update(ctx, browser.SessionID, kernel.BrowserUpdateParams{
+ ProxyID: kernel.String(""),
+ }); err != nil {
+ panic(err)
+ }
+}
+```
The update is synchronous — when the call returns, the proxy swap is fully applied and all new browser traffic routes through the updated proxy. The swap typically completes in 2–3 seconds.
@@ -275,6 +456,17 @@ browser = kernel.browsers.create(
proxy_id=my_proxy.id,
)
```
+
+```go Go
+browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Stealth: kernel.Bool(false),
+ ProxyID: kernel.String(myProxy.ID),
+})
+if err != nil {
+ panic(err)
+}
+_ = browser
+```
### Disable default proxy on stealth browsers
@@ -294,6 +486,14 @@ kernel.browsers.update(
disable_default_proxy=True,
)
```
+
+```go Go
+if _, err := client.Browsers.Update(ctx, browser.SessionID, kernel.BrowserUpdateParams{
+ DisableDefaultProxy: kernel.Bool(true),
+}); err != nil {
+ panic(err)
+}
+```
@@ -319,6 +519,25 @@ from kernel import Kernel
kernel = Kernel()
kernel.proxies.delete("id")
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ if err := client.Proxies.Delete(ctx, "id"); err != nil {
+ panic(err)
+ }
+}
+```
diff --git a/proxies/residential.mdx b/proxies/residential.mdx
index dfde748..a04fee9 100644
--- a/proxies/residential.mdx
+++ b/proxies/residential.mdx
@@ -56,6 +56,42 @@ proxy = kernel.proxies.create(
browser = kernel.browsers.create(proxy_id=proxy.id)
```
+
+```go Go
+package main
+
+import (
+ "context"
+
+ "github.com/kernel/kernel-go-sdk"
+)
+
+func main() {
+ ctx := context.Background()
+ client := kernel.NewClient()
+
+ proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeResidential,
+ Name: kernel.String("my-us-residential"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigResidentialProxyConfig: &kernel.ProxyNewParamsConfigResidentialProxyConfig{
+ Country: kernel.String("US"),
+ },
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ ProxyID: kernel.String(proxy.ID),
+ })
+ if err != nil {
+ panic(err)
+ }
+ _ = browser
+}
+```
## Configuration Parameters
@@ -101,6 +137,24 @@ proxy = kernel.proxies.create(
)
```
+```go Go
+proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeResidential,
+ Name: kernel.String("la-residential"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigResidentialProxyConfig: &kernel.ProxyNewParamsConfigResidentialProxyConfig{
+ Country: kernel.String("US"),
+ State: kernel.String("CA"),
+ City: kernel.String("los_angeles"),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = proxy
+```
+
@@ -135,6 +189,23 @@ proxy = kernel.proxies.create(
)
```
+```go Go
+proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeResidential,
+ Name: kernel.String("ny-residential"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigResidentialProxyConfig: &kernel.ProxyNewParamsConfigResidentialProxyConfig{
+ Country: kernel.String("US"),
+ State: kernel.String("NY"),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = proxy
+```
+
@@ -169,6 +240,23 @@ proxy = kernel.proxies.create(
)
```
+```go Go
+proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeResidential,
+ Name: kernel.String("comcast-residential"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigResidentialProxyConfig: &kernel.ProxyNewParamsConfigResidentialProxyConfig{
+ Country: kernel.String("US"),
+ Asn: kernel.String("AS7922"),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = proxy
+```
+
@@ -203,6 +291,23 @@ proxy = kernel.proxies.create(
)
```
+```go Go
+proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeResidential,
+ Name: kernel.String("nyc-residential"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigResidentialProxyConfig: &kernel.ProxyNewParamsConfigResidentialProxyConfig{
+ Country: kernel.String("US"),
+ Zip: kernel.String("10001"),
+ },
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = proxy
+```
+
@@ -247,6 +352,27 @@ proxy = kernel.proxies.create(
]
)
```
+
+```go Go
+proxy, err := client.Proxies.New(ctx, kernel.ProxyNewParams{
+ Type: kernel.ProxyNewParamsTypeResidential,
+ Name: kernel.String("residential-with-bypass"),
+ Config: kernel.ProxyNewParamsConfigUnion{
+ OfProxyNewsConfigResidentialProxyConfig: &kernel.ProxyNewParamsConfigResidentialProxyConfig{
+ Country: kernel.String("US"),
+ },
+ },
+ BypassHosts: []string{
+ "localhost",
+ "metadata.google.internal",
+ "*.internal.company.com",
+ },
+})
+if err != nil {
+ panic(err)
+}
+_ = proxy
+```
See the [overview](/proxies/overview#bypass-hosts) for full bypass host rules and examples.