All posts

Evaluate flags in Node, Go, or Python

The RedPennon Team2 min read
Three dark code windows, one per language, linked by red lines that converge on a single RedPennon orbit mark representing one shared API.

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.

app.ts
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" },
});
main.go
c := redpennon.NewClient(os.Getenv("RP_API_KEY"))

show, _ := c.VariableValue(ctx, "show-banner", false, &redpennon.UserContext{
    ID: "user-123",
})
app.py
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:

  • variableValue when 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.
  • variable when 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.
  • variables when 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.

track.ts
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.

Share
RedPennonredpennon.dev
© 2026 RedPennon. All rights reserved.