Go SDK
Go clients for two Solari products. Browsers are a remote Chromium you drive with chromedp over CDP; sandboxes are headless microVMs for commands, code, files, and git. Two independent modules, both package solari. VMs (GUI desktops) are created with Kind: KindDesktop and expose a stream URL, but no GUI surface.
Installation
| Module | Product | Types |
|---|---|---|
github.com/solari-sdk/solari-browser-go | Cloud browsers | Client, Sessions, Connect() |
github.com/solari-sdk/solari-sandbox-go | Sandboxes (headless) | Client, Sandbox |
github.com/solari-sdk/solari-sandbox-go | VMs (GUI desktops) | Create plus lifecycle, StreamURL, core namespaces. No GUI type. |
go get github.com/solari-sdk/solari-browser-go # browsers
go get github.com/solari-sdk/solari-sandbox-go # sandboxes + VM lifecyclePublic modules — go get works
Both modules are public and
go get-able as shown above (resolved through the Go module proxy). They require Go 1.23+.Both modules are package solari
The module paths differ but the package name is
solari in both. Importing them into the same file requires an alias, e.g. browser "github.com/solari-sdk/solari-browser-go".Getting Started
Drive a browser
client, _ := solari.NewClient(solari.ClientOptions{APIKey: os.Getenv("SOLARI_API_KEY")})
sess, err := client.Sessions.Create(ctx, solari.CreateSessionOptions{
Stealth: true,
Proxy: solari.ProxyCountry("us"),
})
if err != nil {
log.Fatal(err)
}
defer client.Sessions.Release(context.Background(), sess.ID)
browserCtx, cancel, _ := solari.Connect(ctx, sess) // chromedp over raw CDP
defer cancel()
var title string
err = chromedp.Run(browserCtx,
chromedp.Navigate("https://example.com"),
chromedp.Title(&title))Create a sandbox
client, _ := solari.NewClient(solari.ClientOptions{
APIKey: os.Getenv("SOLARI_API_KEY"),
BaseURL: "https://api.getsolari.com",
})
sbx, err := client.Create(ctx, solari.CreateOptions{Template: "base"})
if err != nil {
log.Fatal(err)
}
defer sbx.Kill(ctx)
r, _ := sbx.Commands.Run(ctx, "echo", solari.CommandOptions{Args: []string{"hi"}})
fmt.Println(r.ExitCode, r.Stdout) // 0 "hi"Create a VM
// Same client. A VM is a session with Kind: KindDesktop.
vm, err := client.Create(ctx, solari.CreateOptions{
Template: "office",
Kind: solari.KindDesktop,
})
if err != nil {
log.Fatal(err)
}
defer vm.Kill(ctx)
fmt.Println(vm.StreamURL) // wss://.../stream/<id>, empty for a sandbox
// Commands / Files / Code / Git work on a VM. Mouse, keyboard, and
// screenshots do NOT exist in Go. See the VMs page.
r, _ := vm.Commands.Run(ctx, "xdotool", solari.CommandOptions{
Args: []string{"getactivewindow"},
})Configuration
Each NewClient takes one ClientOptions struct. The two modules declare their own. The fields are not interchangeable. APIKey is always required.
| Field | Type | Default | Module | Notes |
|---|---|---|---|---|
APIKey | string | required | both | Sent as Authorization: Bearer. NewClient errors if empty. |
BaseURL | string | see notes | both | browser: resolved from Region; setting it ignores Region. sandbox: required. |
Region | Region | RegionUSWest | browser | Only "us-west" today. An unknown region errors. |
HTTPClient | *http.Client | constructed | both | Override for tests. browser: setting it ignores TimeoutMs. |
TimeoutMs | int | 90000 | browser | Per attempt, not per call. |
MaxAttempts | int | 2 | browser | Total attempts, counting the first. 2 means one retry. |
BackoffMs | *int | 500 | browser | Fixed sleep between attempts, not exponential. A pointer so 0 (no wait) differs from unset. |
CallTimeoutMs | int | 300000 | sandbox | Per-RPC timeout on the control channel. |
MaxRetries | int | 5 | sandbox | Retries after the first try. Idempotent requests only. |
RetryDelayMs | *int | exponential | sandbox | When non-nil, replaces backoff with a fixed delay. 0 disables the wait. |
No environment variables are read
Neither
NewClient reads the environment. Pass APIKey (and BaseURL where required) explicitly. The os.Getenv calls above are your code, not the SDK’s.The two retry policies differ
browser: every request retries up to
MaxAttempts on transport errors and 502, 503, 504 only, with a fixed pause. sandbox: only idempotent requests (GET, DELETE, or one carrying an idempotency key, which Create sends) retry, on transport errors and any 5xx, with exponential backoff plus jitter. Neither retries 429.