Go
Copy sdk/go/privcaptcha.go into your project. Standard library only.
Verify
client := privcaptcha.New(os.Getenv("PRIVCAPTCHA_SECRET"))
result, err := client.Verify(ctx, r.FormValue("privcaptcha-response"), r.RemoteAddr)
if err != nil || !result.Success {
http.Error(w, "captcha failed", http.StatusBadRequest)
return
}
type Client struct {
Secret string
Endpoint string // defaults to https://privcaptcha.com/api/v1/siteverify
HTTP *http.Client // defaults to a 10s timeout
}
func New(secret string) *Client
func (c *Client) Verify(ctx context.Context, response, remoteIP string) (*Result, error)
Result is {Success, ChallengeTS, Hostname, ErrorCodes}, decoded straight from the API
response.
Fail-closed behaviour
An unreachable verifier, a non-200 status or an undecodable body returns ErrUnavailable.
Treat it as a failure, never as a pass — "we could not check" must not resolve to "allowed".
Always test err != nil before reading result.
An empty response returns &Result{Success: false, ErrorCodes: ["missing-input-response"]}
with a nil error and no network call, so check Success as well as err.
Pass a request-scoped ctx so a slow verification cannot outlive the request that needs it.