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.WithIPSrc(...)to override the automatically detected client IP address.
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.
Override the client IP
Section titled “Override the client IP”Arcjet normally detects the client IP address from the request. If your
application has already determined the client IP from a trusted source, pass
WithIPSrc to Protect:
ipSrc := getClientIPFromTrustedSource(r)decision, err := aj.Protect(r.Context(), r, arcjet.WithIPSrc(ipSrc))A non-empty value takes precedence over automatic detection. An empty string
does not override the automatically detected IP. WithIPSrc is also supported
by ProtectDetails.
Caution: The SDK trusts the value without validating it. Validate the value and ensure it comes from a trusted source. Do not pass a client-controlled header directly; doing so could allow clients to choose the IP address used for fingerprinting, rate limiting, and other security checks.
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.