Skip to content

How to Use Evaluation Context for Targeting

Pass user or segment attributes to your flag provider for personalized variant resolution.

Goal

Enable context-aware flag dispatch: resolve different variants based on user ID, plan, locale, or other attributes.

Prerequisites

  • FlagZen basics: @Feature, @Variant, FeatureDispatcher
  • A flag provider that supports context-aware resolution (e.g., OpenFeature, custom provider)

Steps

1. Build an EvaluationContext

Create a context with a targeting key and attributes:

EvaluationContext context = EvaluationContext.builder()
    .targetingKey("user-7291")
    .attribute("plan", "enterprise")
    .attribute("locale", "en-US")
    .attribute("country", "US")
    .build();
  • targetingKey: Primary identifier (user ID, account ID, etc.)
  • attribute: Arbitrary targeting metadata

2. Resolve flags using the context

Pass the context to your flag provider:

FlagProvider provider = new OpenFeatureFlagProvider(client);
Optional<String> value = provider.getString("checkout-flow", context);

The provider can now use the context to decide which variant to activate based on user attributes.

3. Use FlagContext for thread-scoped context (optional)

For request-scoped targeting in web applications, use FlagContext.run():

@RestController
public class CheckoutController {
    @Autowired
    private CheckoutFlow checkoutFlow;

    @PostMapping("/checkout")
    public String checkout(@RequestParam String userId) {
        EvaluationContext context = EvaluationContext.builder()
            .targetingKey(userId)
            .attribute("plan", getUserPlan(userId))
            .build();

        return FlagContext.run(context, () -> {
            // All flag resolutions within this block use the context
            return checkoutFlow.execute();
        });
    }
}

FlagContext.run() sets the context in thread-local storage for the duration of the block.

4. Access context from within your flag provider

If you implement a custom provider, retrieve the context:

public class MyFlagProvider implements FlagProvider {
    @Override
    public Optional<String> getString(String key, EvaluationContext context) {
        String userId = context.targetingKey();
        String plan = (String) context.attributes().get("plan");

        // Use userId and plan to decide variant
        if ("enterprise".equals(plan)) {
            return Optional.of("PREMIUM");
        }
        return Optional.of("STANDARD");
    }
}

5. (Optional) Use with Spring Boot

Combine with Spring auto-configuration for dependency injection:

@Service
public class OrderService {
    @Autowired
    private CheckoutFlow checkoutFlow;

    @Autowired
    private UserRepository users;

    public String processOrder(String userId) {
        User user = users.findById(userId).orElseThrow();

        EvaluationContext context = EvaluationContext.builder()
            .targetingKey(userId)
            .attribute("plan", user.getPlan())
            .attribute("signup-date", user.getCreatedAt())
            .build();

        return FlagContext.run(context, () -> {
            return checkoutFlow.execute();
        });
    }
}

6. (Optional) Use with nested context blocks

Stack contexts for hierarchical resolution:

EvaluationContext userContext = EvaluationContext.builder()
    .targetingKey("user-123")
    .attribute("plan", "enterprise")
    .build();

EvaluationContext requestContext = EvaluationContext.builder()
    .targetingKey("request-456")
    .attribute("region", "eu")
    .build();

FlagContext.run(userContext, () -> {
    // user-123, enterprise plan applies here

    FlagContext.run(requestContext, () -> {
        // requestContext overwrites userContext
        // This block sees request-456, eu region
    });

    // Back to userContext (user-123, enterprise)
});

Result

Flag resolution respects user attributes and context, enabling personalized feature rollouts, A/B testing, and segment-based feature control.

See Also