Evaluate flags in Node, Go, or Python

Evaluating a flag is, underneath, just an HTTP call. But you don’t want to hand-roll that call in every service: the auth header, the JSON body, the timeout, the retry, the careful handling of what happens when the network has a bad day. So we wrote clients that do it for you. Today there are three, for Node, Go, and Python, and they all speak the same REST contract, so the shape of your code barely changes between them.
Pick your language
You configure a client with one thing: an environment API key. The host is fixed to the production API, so there’s no base URL to remember. Here’s the same flag check in each language.
import { RedPennonClient } from "@redpennon/node-sdk";
const client = new RedPennonClient({ apiKey: process.env.RP_API_KEY });
const showBanner = await client.variableValue("show-banner", false, {
user: { id: "user-123" },
});c := redpennon.NewClient(os.Getenv("RP_API_KEY"))
show, _ := c.VariableValue(ctx, "show-banner", false, &redpennon.UserContext{
ID: "user-123",
})from redpennon import Client, UserContext
with Client(api_key=RP_API_KEY) as client:
show_banner = client.variable_value(
"show-banner",
default=False,
user=UserContext(id="user-123"),
)Three ways to ask
Every SDK gives you the same three methods, named to fit each language’s conventions:
variableValuewhen you just want the value or a fallback. Pass the key and a default, get back the served value or your default. This is the one you’ll reach for most.variablewhen you want the full result: the value plus the variation that was served, the reason it was served, and an evaluation trace you can forward when you track events.variableswhen you need several flags at once. It resolves them in a single round-trip instead of one request per key.
Fail open, on purpose
Here’s the design decision that matters most. variableValue returns your default whenever the variable is unknown, nothing is served, or a transport or governance error gets in the way. The Go client mirrors this exactly: its returned error is always nil, so the value-or-default path never makes you handle one. A hiccup talking to the flag service should never be the thing that takes your app down. If you do want to see the underlying error, call variable directly and inspect it.
Measure what you shipped
Flags are more useful when you can tie them to outcomes. Evaluate first to capture the evaluation trace, then send an event and forward that trace so the attribution is verified rather than guessed.
const result = await client.variable("checkout-flow", { user: { id: "user-123" } });
await client.trackEvents([{
event: "purchase",
variable: "checkout-flow",
variation: result.variation,
value: 49.99,
evaluation_trace: result.evaluation_trace,
}]);Or skip the SDK entirely
The SDKs are a convenience, not a gate. Because they all sit on the same REST contract, any language that can make an HTTP request can evaluate a flag. curl works, your favourite HTTP library works, and the request and response shapes are exactly what the SDKs use under the hood.
Full method signatures, types, and error classes for each language are in the SDK docs.