Skill 77 · Instrument Feature Flags
Subchapter 77.23
references/rust.mdMarkdown7 KBView on GitHub
AI agents: this is one page from PostHog’s docs. Full index of Markdown docs for LLMs: https://posthog.com/llms.txt (opens in a new tab)
Install the posthog-rs crate by adding it to your Cargo.toml.
Cargo.toml
[dependencies]
posthog-rs = "0.14"Next, set up the client with your PostHog project key.
Rust
let client = posthog_rs::client("<ph_project_token>").await;Our Rust SDK supports both blocking and async clients. The async client is the default and is recommended for most use cases.
If you need to use a synchronous client instead – like we do in our CLI (opens in a new tab) –, you can opt into it by disabling the asynchronous feature on your Cargo.toml file.
toml
[dependencies]
posthog-rs = { version = "0.14", default-features = false }With the blocking client, the same methods are available without .await. Either way, capture is non-blocking: it hands the event to a background worker that batches and sends it, so it returns immediately instead of waiting on the network. Because delivery happens in the background, call flush() or shutdown() before your program exits, or buffered events may be lost.
There are two steps to implement feature flags in Rust:
Call client.evaluate_flags() once for the user, then read values from the returned snapshot.
Rust
use posthog_rs::EvaluateFlagsOptions;
let flags = client.evaluate_flags(
"distinct_id_of_your_user",
EvaluateFlagsOptions::default(),
).await.unwrap();
if flags.is_enabled("flag-key") {
// Do something differently for this user
// Optional: fetch the payload
let matched_flag_payload = flags.get_flag_payload("flag-key");
}Rust
use posthog_rs::{EvaluateFlagsOptions, FlagValue};
let flags = client.evaluate_flags(
"distinct_id_of_your_user",
EvaluateFlagsOptions::default(),
).await.unwrap();
match flags.get_flag("flag-key") {
Some(FlagValue::String(variant)) if variant == "variant-key" => {
// Do something differently for this user
// Optional: fetch the payload
let matched_flag_payload = flags.get_flag_payload("flag-key");
}
_ => {}
}flags.get_flag() returns Some(FlagValue::String(...)) for multivariate flags, Some(FlagValue::Boolean(true)) for enabled boolean flags, Some(FlagValue::Boolean(false)) for disabled flags, and None when the flag wasn’t returned by the evaluation.
Note:
client.is_feature_enabled(),client.get_feature_flag(),client.get_feature_flag_payload(), andclient.get_feature_flags()still work during the migration period, but they’re deprecated. Preferevaluate_flags()for new code.
If you want use your feature flag to breakdown or filter events in your insights (opens in a new tab), you’ll need to include feature flag information in those events. This ensures that the feature flag value is attributed correctly to the event.
Note: This step is only required for events captured using our server-side SDKs or API (opens in a new tab).
There are two methods you can use to include feature flag information in your events:
Pass the same flags object that you used for branching. This attaches the exact flag values from that evaluation and doesn’t make another /flags request.
Rust
use posthog_rs::{EvaluateFlagsOptions, Event};
let flags = client.evaluate_flags(
"distinct_id_of_your_user",
EvaluateFlagsOptions::default(),
).await.unwrap();
if flags.is_enabled("flag-key") {
// Do something differently for this user
}
let mut event = Event::new("event_name", "distinct_id_of_your_user");
event.with_flags(&flags);
client.capture(event);By default, this attaches every flag in the snapshot using $feature/<flag-key> properties and $active_feature_flags.
To reduce event property bloat, pass a filtered snapshot:
Rust
// Attach only flags accessed with is_enabled() or get_flag() before this call
let mut event = Event::new("event_name", "distinct_id_of_your_user");
event.with_flags(&flags.only_accessed());
client.capture(event);
// Attach only specific flags
let mut event = Event::new("event_name", "distinct_id_of_your_user");
event.with_flags(&flags.only(&["checkout-flow", "new-dashboard"]));
client.capture(event);only_accessed() is order-dependent. If you call it before accessing any flags with is_enabled() or get_flag(), no feature flag properties are attached.
In the event properties, include $feature/feature_flag_name: variant_key:
Rust
use posthog_rs::Event;
let mut event = Event::new("event_name", "distinct_id_of_your_user");
event.insert_prop("$feature/feature-flag-key", "variant-key").unwrap();
client.capture(event);By default, evaluate_flags() evaluates every flag for the user. If you only need a few flags, pass flag_keys to request only those flags:
Rust
use posthog_rs::EvaluateFlagsOptions;
let flags = client.evaluate_flags(
"distinct_id_of_your_user",
EvaluateFlagsOptions {
flag_keys: Some(vec!["checkout-flow".to_string(), "new-dashboard".to_string()]),
..Default::default()
},
).await.unwrap();Capturing $feature_flag_called events enables PostHog to know when a flag was accessed by a user and provide analytics and insights (opens in a new tab) on the flag. With evaluate_flags(), the SDK sends this event when you call flags.is_enabled() or flags.get_flag() for a flag.
The SDK deduplicates these events per (distinct_id, flag, value) in a local cache. If you reinitialize the PostHog client, the cache resets and $feature_flag_called events may be sent again. PostHog handles duplicates, so duplicate $feature_flag_called events don’t affect your analytics.
flags.get_flag_payload() doesn’t send $feature_flag_called events and doesn’t count as an access for only_accessed().
If you’re using the blocking client (with default-features = false), the API is the same but without .await:
Rust
use posthog_rs::EvaluateFlagsOptions;
let flags = client.evaluate_flags(
"distinct_id_of_your_user",
EvaluateFlagsOptions::default(),
).unwrap();
if flags.is_enabled("flag-key") {
// Do something differently for this user
}Now that you’re evaluating flags, continue with the resources below to learn what else Feature Flags enables within the PostHog platform.
| Resource | Description |
|---|---|
| Creating a feature flag (opens in a new tab) | How to create a feature flag in PostHog |
| Adding feature flag code (opens in a new tab) | How to check flags in your code for all platforms |
| Framework-specific guides (opens in a new tab) | Setup guides for React Native, Next.js, Flutter, and other frameworks |
| How to do a phased rollout (opens in a new tab) | Gradually roll out features to minimize risk |
| More tutorials (opens in a new tab) | Other real-world examples and use cases |
Ask PostHog AI
HelpfulCould be better