Go SDK
kloakd-go — one API for everything, idiomatic Go client with full module coverage
4 min read
Install
go get github.com/kloakd/kloakd-go
Go 1.21+ | 71/71 tests | 82.7% coverage | zero dependencies (stdlib net/http)
Client
import kloakd "github.com/kloakd/kloakd-go"
client := kloakd.MustNew(kloakd.Config{
APIKey: os.Getenv("KLOAKD_API_KEY"),
OrganizationID: os.Getenv("KLOAKD_ORG_ID"),
Timeout: 30 * time.Second,
MaxRetries: 3,
})
Quickstart — one call does everything
result, _ := client.Crawl(ctx, "https://example.com",
&kloakd.CrawlOptions{
MaxPages: 50,
ExtractSchema: map[string]string{"title": "css:h1", "content": "css:article"},
})
for _, page := range result.Pages {
if page.Success {
fmt.Printf("%s → %v\n", page.URL, page.StructuredData)
}
}
That's it. Crawl() internally:
- Discovers all pages on the site (Webgrph BFS)
- Fetches each page through the 4-tier anti-bot engine (auto-escalates to headless browser for Cloudflare-protected sites — no
ForceBrowserneeded) - Extracts structured data from each page if
ExtractSchemais provided (Kolektr, using cached fetch artifacts — no second HTTP round-trip)
Per-page failures are caught and marked Success: false — the crawl never aborts on a single page error.
Primary method
client.Crawl()
result, _ := client.Crawl(ctx, "https://example.com",
&kloakd.CrawlOptions{
MaxDepth: 3,
MaxPages: 100,
ExtractSchema: map[string]string{"title": "css:h1", "price": "css:.price"},
})
fmt.Printf("Discovered: %d pages\n", result.TotalPagesDiscovered)
fmt.Printf("Fetched: %d\n", result.PagesFetched)
fmt.Printf("Failed: %d\n", result.PagesFailed)
for _, page := range result.Pages {
if page.Success {
fmt.Printf(" %s [tier %d] %v\n", page.URL, page.TierUsed, page.StructuredData)
} else {
fmt.Printf(" %s FAILED: %s\n", page.URL, *page.Error)
}
}
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| url | string | required | Seed URL to start crawling from |
| MaxDepth | int | 3 | Maximum BFS depth |
| MaxPages | int | 100 | Maximum pages to crawl |
| ExtractSchema | map[string]string | nil | CSS selector schema for structured extraction |
| IncludeExternalLinks | bool | false | Follow off-domain links |
| SessionArtifactID | string | "" | Reuse an authenticated session artifact (from Fetchyr) |
Returns: SiteCrawlResult
| Field | Type | Description |
|---|---|---|
| Success | bool | Whether the crawl completed |
| URL | string | Seed URL |
| TotalPagesDiscovered | int | Pages found during BFS |
| PagesFetched | int | Pages successfully fetched |
| PagesFailed | int | Pages that failed (included with Success: false) |
| Pages | []CrawlPage | All pages with HTML and optional structured data |
| CrawlArtifactID | *string | Artifact ID for the site hierarchy |
| Error | *string | Error message if crawl failed entirely |
client.CrawlStream() — streaming
For long-running crawls, use the streaming version to receive real-time progress events via a channel:
ch, _ := client.CrawlStream(ctx, "https://example.com",
&kloakd.CrawlStreamOptions{
MaxPages: 500,
ExtractSchema: map[string]string{"title": "css:h1"},
})
for event := range ch {
if event.Err != nil { break }
switch event.Type {
case "page_fetched":
fmt.Printf("[%d/%d] %s OK\n", event.Page, event.Total, event.URL)
case "page_failed":
fmt.Printf("[%d/%d] %s FAIL: %s\n", event.Page, event.Total, event.URL, event.Error)
case "crawl_complete":
fmt.Println("Done")
}
}
Event types
| Type | Description |
|---|---|
| discovery_started | Crawl discovery has begun |
| discovery_progress | Pages found during BFS (PagesFound field) |
| discovery_complete | Discovery finished, fetch phase starting |
| page_fetching | About to fetch page N of total |
| page_fetched | Page fetched successfully |
| page_failed | Page fetch failed (crawl continues) |
| crawl_complete | All pages processed |
Low-level methods
Need fine-grained control? The individual modules are still available:
Evadr.Fetch()
page, _ := client.Evadr.Fetch(ctx, "https://example.com", nil)
fmt.Printf("Status: %d, Tier: %d\n", page.StatusCode, page.TierUsed)
fmt.Printf("Artifact ID: %s\n", page.ArtifactID)
Webgrph.Crawl()
crawl, _ := client.Webgrph.Crawl(ctx, "https://example.com",
&kloakd.CrawlOptions{MaxDepth: 3, MaxPages: 100})
fmt.Printf("Crawl started: %s\n", crawl.CrawlID)
Kolektr.Page()
result, _ := client.Kolektr.Page(ctx, "https://example.com",
&kloakd.PageOptions{
Schema: map[string]string{"title": "css:h1", "price": "css:.price"},
})
for _, r := range result.Records {
fmt.Println(r)
}
Artifact chaining
Pass artifact IDs between low-level methods to skip redundant work:
page, _ := client.Evadr.Fetch(ctx, "https://example.com", nil)
data, _ := client.Kolektr.Page(ctx, "https://example.com",
&kloakd.PageOptions{
Schema: map[string]string{"title": "css:h1"},
FetchArtifactID: page.ArtifactID,
})
crawl, _ := client.Webgrph.Crawl(ctx, "https://example.com",
&kloakd.CrawlOptions{
MaxDepth: 2,
SessionArtifactID: page.ArtifactID,
})
Error handling
result, err := client.Crawl(ctx, "https://example.com", nil)
if err != nil {
if errors.Is(err, kloakd.ErrRateLimit) {
var rle *kloakd.RateLimitError
errors.As(err, &rle)
fmt.Printf("Rate limited. Retry after %ds\n", rle.RetryAfter)
} else if errors.Is(err, kloakd.ErrAuthentication) {
fmt.Println("Invalid API key")
} else {
fmt.Printf("Error: %v\n", err)
}
}
Advanced namespaces
client.Skanyr // API discovery
client.Nexus // AI strategy engine
client.Parlyr // Natural language queries
client.Fetchyr // RPA & authenticated scraping
Next steps
- Quickstart — get started in 5 minutes
- API reference — detailed endpoint docs
- Error reference — full error taxonomy
