Arcjet Go SDK reference
The Arcjet Go SDK protects net/http handlers and non-HTTP operations such as
AI tool calls, MCP handlers, queue workers, and background jobs. It works with
the standard library and routers that expose *http.Request.
Caution: The Go SDK is pre-release and its API may change. Version 0.1.0 requires Go 1.25 or later.
Install
Section titled “Install”Use Go tooling so the project records a compatible version in go.mod:
go get github.com/arcjet/arcjet-go@latestSet ARCJET_KEY in the environment. Retrieve it from the
Arcjet Console, the
Arcjet CLI, or the
MCP server.
Choose an API
Section titled “Choose an API”| API | Use it for |
|---|---|
arcjet.NewClient and Protect | HTTP handlers with a *http.Request |
arcjet.NewGuardClient and Guard | Tool calls, MCP handlers, queues, background jobs, and other operations without an HTTP request |
Create either client once at package scope and reuse it. Do not create a new client for every request or operation.
Protect HTTP handlers
Section titled “Protect HTTP handlers”Configure shared rules on an arcjet.Client, then call Protect once inside
each handler:
package main
import ( "log" "net/http" "os" "time"
"github.com/arcjet/arcjet-go")
var aj = must(arcjet.NewClient(arcjet.Config{ Key: os.Getenv("ARCJET_KEY"), Rules: []arcjet.Rule{ arcjet.Shield(arcjet.ShieldOptions{Mode: arcjet.ModeLive}), arcjet.DetectBot(arcjet.BotOptions{ Mode: arcjet.ModeLive, Allow: []string{}, }), arcjet.TokenBucket(arcjet.TokenBucketOptions{ Mode: arcjet.ModeLive, Characteristics: []string{"userId"}, RefillRate: 10, Interval: time.Minute, Capacity: 10, }), },}))
func handler(w http.ResponseWriter, r *http.Request) { userID := "user_123" // Replace with the authenticated user ID.
decision, err := aj.Protect( r.Context(), r, arcjet.WithCharacteristics(map[string]string{"userId": userID}), arcjet.WithRequested(1), ) if err != nil { // Arcjet fails open. Log the error and apply your fallback policy. log.Printf("arcjet: %v", err) } else if decision.IsDenied() { status := http.StatusForbidden if decision.Reason.IsRateLimit() { status = http.StatusTooManyRequests } http.Error(w, "denied", status) return }
w.WriteHeader(http.StatusNoContent)}
func must[T any](value T, err error) T { if err != nil { panic(err) } return value}Use client.WithRule(...) to derive a client with an additional route-specific
rule. Pass dynamic inputs with Protect options, including:
WithCharacteristics(...)for rate-limit keys such as a user or tenant ID.WithRequested(...)for the number of tokens a token bucket should consume.WithDetectPromptInjectionMessage(...)for untrusted text.WithSensitiveInfoValue(...)for text to scan for sensitive information.WithCorrelationId(...)to correlate a request decision with related work.
If the application is behind a trusted reverse proxy, configure Config.Proxies
with the trusted proxy addresses or CIDRs so Arcjet receives the correct client
IP.
Guard non-HTTP operations
Section titled “Guard non-HTTP operations”Use Guard where no *http.Request exists. Configure the client and reusable
rules at package scope, then pass the inputs at the operation boundary:
package main
import ( "context" "fmt" "os" "time"
"github.com/arcjet/arcjet-go")
var guard = must(arcjet.NewGuardClient(arcjet.GuardConfig{ Key: os.Getenv("ARCJET_KEY"),}))
var userLimit = must(arcjet.GuardTokenBucket(arcjet.GuardTokenBucketOptions{ Mode: arcjet.ModeLive, Label: "tools.weather.limit", Bucket: "tools-weather", RefillRate: 10, Interval: time.Minute, Capacity: 10,}))
var promptScan = must(arcjet.GuardPromptInjection( arcjet.GuardPromptInjectionOptions{Mode: arcjet.ModeLive},))
func getWeather(ctx context.Context, userID, prompt string) error { decision, err := guard.Guard(ctx, arcjet.GuardRequest{ Label: "tools.get-weather", CorrelationId: "trace_123", Metadata: map[string]string{"user_id": userID}, Rules: []arcjet.GuardRuleInput{ userLimit.Key(userID, 1), promptScan.Text(prompt), }, }) if err != nil { return err } if decision.IsDenied() { return fmt.Errorf("blocked: %s", decision.Reason) } return nil}
func must[T any](value T, err error) T { if err != nil { panic(err) } return value}Guard labels and rate-limit buckets are slugs: lowercase letters, digits, dashes, and dots, starting and ending with a letter or digit. Use a stable, hardcoded label for each operation and an explicit rate-limit key such as a user ID, session ID, or API key.
Available Guard rules include rate limiting, prompt injection detection,
sensitive information detection, and custom local rules. Content moderation
is available as the experimental ExperimentalGuardModerateContent rule; its
API and result shape may change.
Errors and warnings
Section titled “Errors and warnings”Guard separates enforcement decisions from processing problems:
decision.IsDenied()reports a policy denial.decision.HasFailedOpen()reports that an error caused the decision to allow.decision.ErrorResults()returns errored rule results.- A configured rule’s
ErrorResult(decision)attributes an error to that rule. decision.Warningscontains diagnostics that do not change the conclusion.
Choose an explicit fallback policy for sensitive operations. Arcjet fails open by default so a service issue does not block all work.
Outbound proxy
Section titled “Outbound proxy”The SDK honors the standard HTTP_PROXY, HTTPS_PROXY, and NO_PROXY
environment variables for Arcjet API calls. Proxy URLs may contain credentials,
so do not log them.