Skip to main content

Evaluation

Feature evaluation is local: the SDK downloads definitions and evaluates them in-process.

Filter types and parameters: Feature filters.

Context​

Evaluation takes a toggly.Context:

ctx := toggly.Context{
Identity: "user-123",
Groups: []string{"beta"},
Traits: map[string]any{
"country": "US",
"plan": "pro",
},
Claims: map[string]string{
"role": "admin",
},
Request: &toggly.RequestContext{
UserAgent: "Mozilla/5.0 ... Chrome/120.0.0.0 ...",
AcceptLanguage: "en-US,en;q=0.9",
Country: "US",
},
}
FieldUsed by
IdentityPercentage, Targeting, segment percentage gates
GroupsTargeting group rules
TraitsCustom filters you register
ClaimsUserClaims (Claim + Value exact match)
RequestHTTP segment filters (browser / language / country / device / OS)
EntityContextProperty (per-call domain object)

Identity, Groups, Traits, and Claims are user context. Do not put page-entity attributes there — use Entity instead. See Entity & page context.

Boolean evaluation​

enabled, err := client.IsEnabled(context.Background(), "MyFeature", ctx)

If a feature is not found:

  • returns false by default
  • returns true if EnableUndefinedOnDevelopment is set

HTTP segment filters + Request context​

Server-side Go evaluates these built-in filters against Context.Request and Context.Claims. HTTP helpers map request headers; your authentication layer supplies identity, groups, and claims:

Filter name(s)Reads fromMatch
BrowserFamilyRequest.UserAgentParsed browser name substring (case-insensitive); "Other" / empty UA → fail
BrowserLanguageRequest.AcceptLanguageSubstring of the Accept-Language value (case-insensitive)
Country, CountryFamilyRequest.CountryExact ISO country code (case-insensitive)
DeviceTypeRequest.UserAgentParsed device family substring; "Other" / empty UA → fail
OS, OperatingSystemRequest.UserAgentParsed OS family substring; "Other" / empty UA → fail
UserClaimsClaims[Claim]Exact string equality on claim type + value

Percentage is required on these Go segment filters (0–100). Missing Percentage or a value ≤0 fails closed (feature off). With a non-empty Identity, the gate is sticky via the same percentile hash as Percentage filters; without identity, a partial percentage (0 < Percentage < 100) uses a random draw. Percentage >= 100 always passes the gate.

Missing Request, empty required fields, or missing claims also fail closed for that filter.

Wiring headers in togglyhttp​

togglyhttp.Middleware, MiddlewareWith, and FeatureGate fill missing request metadata from headers. They do not infer an authenticated user or claims. Use the authentication callbacks in HTTP middleware, or combine an existing trusted context with request metadata:

// trustedUser comes from your authentication layer before the first evaluation.
func contextForRequest(r *http.Request, trustedUser toggly.Context) toggly.Context {
return togglyhttp.FromHttpRequest(r, trustedUser)
}

FromHttpRequest reads User-Agent, Accept-Language, and the first non-empty country header in this order: CF-IPCountry, X-Vercel-IP-Country, CloudFront-Viewer-Country. Header names are case-insensitive. A non-empty field in trustedUser.Request takes precedence; missing fields are filled individually. Only trust country headers set by your own proxy.

UserClaims reads Claims, not HTTP headers. Set it from your verified principal or JWT. Ordinary evaluation does not fetch definitions again when these per-request values change.

Ambient and per-call context​

client.IsEnabled(r.Context(), key, toggly.Context{}) uses context attached by the middleware. Per-call non-empty identity and non-nil groups, claims, traits, request, or entity override the corresponding ambient field. An empty identity inherits the ambient identity; an empty but non-nil collection replaces the ambient collection. A per-call Request pointer replaces the entire ambient Request; that merge is different from the field-by-field header filling above. Build a fresh context when you need an explicitly anonymous evaluation rather than reusing an authenticated request.

See Integrations for FeatureGate options.

Entity context​

Trusted Go servers evaluate full definitions and Context Property filters against a per-call entity on Context.Entity.

Register kinds once before creating the client so the dashboard Contexts page lists properties (PUT sdk/{appKey}/contexts). Opt out with DisableEntityContextRegistration: true. This registration is server-side schema setup, not request identity.

type Order struct {
ID string
Status string
Total float64
}

toggly.RegisterContext("Order", func(v any) toggly.EntityContext {
o := v.(Order)
return toggly.EntityContext{
Kind: "Order",
Key: o.ID,
Attributes: map[string]any{"Status": o.Status, "Total": o.Total},
}
}, &toggly.EntityContextSchemaRegistration{
KeyProperty: "Id",
Properties: []toggly.EntityContextPropertySchema{
{Name: "Id", Type: "string"},
{Name: "Status", Type: "string"},
{Name: "Total", Type: "number"},
},
})

order := Order{ID: "ord-1", Status: "paid", Total: 42.0}
userCtx := toggly.Context{
Identity: "user-123",
Entity: toggly.MapEntity("Order", order),
}
enabled, err := client.IsEnabled(context.Background(), "OrderBadge", userCtx)

You can also set Entity directly without MapEntity. An unregistered kind passed to MapEntity produces no entity; missing entities or required attributes fail closed. The evaluator checks attributes and does not enforce the filter's ContextKind against Entity.Kind. Supply the correct domain object yourself; a kind label is not a validation or authorization boundary.

Feature gates (Any / All)​

You can evaluate a gate over multiple features:

ok, err := client.EvaluateGate(
context.Background(),
[]string{"FeatureA", "FeatureB"},
toggly.RequirementAll,
ctx,
false,
)

Built-in filters​

The Go SDK includes built-in evaluators for:

  • AlwaysOn / AlwaysOff
  • Percentage (deterministic rollout based on Context.Identity only; requires Identity)
  • TimeWindow
  • Targeting (users, groups, and deterministic default rollout percentage per identity)
  • BrowserFamily, BrowserLanguage, Country / CountryFamily, DeviceType, OS / OperatingSystem, UserClaims (see HTTP segment filters)
  • ContextProperty (via Context.Entity)

Definitions serve the short names above — use those in configuration and docs.

Dashboard parameter names and semantics: Feature filters.

Per-SDK Local vs Worker vs fail-closed: SDK × filter matrix.