Official Go SDK for the CaptchaSonic CAPTCHA solving API — gRPC binary transport (fastest) + HTTP/REST fallback.
go get github.com/Captcha-Sonic/captchasonic-go@latestOr pinned to a specific version:
go get github.com/Captcha-Sonic/captchasonic-go@v1.0.0package main
import (
"context"
"fmt"
"log"
"os"
"github.com/Captcha-Sonic/captchasonic-go"
)
func main() {
// Create client — gRPC binary transport (default, fastest)
client, err := captchasonic.NewClient("sonic_your_api_key")
if err != nil {
log.Fatal(err)
}
defer client.Close()
ctx := context.Background()
// Check balance
balance, _ := client.GetBalance(ctx)
fmt.Printf("Balance: $%.4f\n", balance)
// Solve CAPTCHA — images sent as raw binary (zero base64 overhead)
imgBytes, _ := os.ReadFile("tile.png")
resp, err := client.SolvePopularCaptcha(ctx, [][]byte{imgBytes},
"Select all traffic lights", "objectClassify")
if err != nil {
log.Fatal(err)
}
fmt.Println("Solution:", resp.TypedSolution.GetGrid().GetObjects())
}| Transport | Default | Speed | Images |
|---|---|---|---|
| gRPC | ✅ yes | Fastest — binary, HTTP/2 | Raw []byte |
| HTTP | no | Good — JSON REST | Auto base64-encoded |
gRPC is the default. Pass
WithHTTP()only if you specifically need the REST transport.
// Production gRPC (default)
client, _ := captchasonic.NewClient("sonic_xxxx")
// HTTP/REST transport
client, _ := captchasonic.NewClient("sonic_xxxx", captchasonic.WithHTTP())
// Custom endpoint
client, _ := captchasonic.NewClient("sonic_xxxx",
captchasonic.WithEndpoint("api.captchasonic.com:443"))
// Local development (insecure gRPC)
client, _ := captchasonic.NewClient("sonic_xxxx",
captchasonic.WithEndpoint("localhost:50052"),
captchasonic.WithInsecure())
// Advanced options
captchasonic.WithTimeout(45 * time.Second)
captchasonic.WithGRPCMsgSize(100 * 1024 * 1024) // 100 MB max message
captchasonic.WithHTTPPool(200, 200, 90*time.Second)resp, err := client.SolvePopularCaptcha(ctx, images,
"Select all traffic lights", "objectClassify",
captchasonic.WithWebsite("https://example.com", "sitekey"))resp, err := client.SolveRecaptchaV2(ctx, images, "traffic lights",
captchasonic.WithQuestionType("split_33"),
captchasonic.WithWebsiteURL("https://example.com"))// MtCaptcha
resp, err := client.SolveOcr(ctx, images,
captchasonic.WithModule("mtcaptcha"),
captchasonic.WithLengthRange(4, 6))
// BLS (numeric)
resp, err := client.SolveOcr(ctx, images,
captchasonic.WithModule("bls"),
captchasonic.WithNumeric())// Nine-grid
resp, err := client.SolveGeetest(ctx, "nine", "the bear",
captchasonic.WithImages(tiles))
// Slide
resp, err := client.SolveGeetest(ctx, "slide", "",
captchasonic.WithImages(puzzle),
captchasonic.WithExamples(piece))
// Click
resp, err := client.SolveGeetest(ctx, "click", "the bear",
captchasonic.WithImages(tiles))resp, err := client.SolveTikTok(ctx, "whirl", "Rotate to match", images,
captchasonic.WithExamples(examples))
resp, err := client.SolveTikTok(ctx, "click", "Select shape", images)
resp, err := client.SolveTikTok(ctx, "slide", "", images)resp, err := client.SolveBinance(ctx, "grid", "Select the bicycle", images)
resp, err := client.SolveBinance(ctx, "slide", "", images)resp, err := client.SolveAwsWaf(ctx, images, "Select all squares",
captchasonic.WithWebsiteURL("https://example.com"))resp, err := client.SolveTurnstile(ctx, "https://example.com", "0x4AAAAAAA")// Cloudflare (proxy REQUIRED)
client.SolveCloudflare(ctx, url, key, "http://user:pass@host:1080")
// reCAPTCHA v2/v3 token
client.SolveRecaptchaV2Token(ctx, url, key, captchasonic.WithProxyless())
client.SolveRecaptchaV3Token(ctx, url, key, captchasonic.WithProxy("..."))
// PopularCaptcha token (PopularCaptcha browser automation)
client.SolvePopularCaptchaToken(ctx, url, key, captchasonic.WithProxyless())captchasonic.WithImages(imgs) // set images via option
captchasonic.WithExamples(exampleImages) // reference images
captchasonic.WithScreenshot() // enable screenshot
captchasonic.WithWebsite(url, key) // billing: websiteUrl + websiteKey
captchasonic.WithWebsiteURL(url) // billing: websiteUrl only
captchasonic.WithQuestionType(qt) // e.g. "objectDrag", "split_33"
captchasonic.WithProxy("http://...") // proxy for token tasks
captchasonic.WithProxyless() // proxyless variant
captchasonic.WithModule("bls") // OCR module
captchasonic.WithNumeric() // OCR: digits only
captchasonic.WithCaseSensitive() // OCR: case sensitive
captchasonic.WithLengthRange(3, 8) // OCR: min/max text length
captchasonic.WithGeetestVersion(4) // Geetest versionresp, err := client.GetBalance(ctx)
if err != nil {
if sonicErr, ok := err.(*captchasonic.SonicError); ok {
fmt.Printf("API error %d: %s\n", sonicErr.ErrorID, sonicErr.Message)
}
}Retries automatically on UNAVAILABLE, RESOURCE_EXHAUSTED, DEADLINE_EXCEEDED with exponential backoff (1s, 2s).
NewClient validates the API key format immediately — zero network calls:
- Must start with
"sonic_" - Minimum 12 characters
Per-task validation: images required/count/size, question required, proxy format.
- gRPC: Single
grpc.ClientConnmultiplexes all calls as HTTP/2 streams. Keep-alive pings every 10s. Create once, reuse across goroutines. - HTTP:
http.Transportwith configurableMaxConnsPerHost(default 100).
MIT — see LICENSE.