Keep Server Secret Keys private. If you expose one, you can disable and recreate it in the Statsig console.
An optional options parameter accepts a StatsigOptions object to customize the SDK.
rust
use statsig_rust::{Statsig, StatsigOptions};use std::sync::Arc;// Simple initializationlet statsig = Statsig::new("server-secret-key", None);statsig.initialize().await?;// Or with StatsigOptionslet mut options = StatsigOptions::default();options.environment = Some("development".to_string());let statsig = Statsig::new("server-secret-key", Some(Arc::new(options)));statsig.initialize().await?;// Don't forget to shutdown when donestatsig.shutdown().await?;
initialize performs a network request. After initialize completes, virtually all SDK operations are synchronous (refer to Evaluating Feature Gates in the Statsig SDK). The SDK fetches updates from Statsig in the background independently of API calls.
Working with the SDK
Checking a Feature Flag/Gate
After the SDK is initialized, you can fetch a Feature Gate. Feature Gates create logic branches in code that you can roll out to different users from the Statsig Console. Gates are always CLOSED or OFF (equivalent to return false;) by default.All APIs require you to specify the user (refer to Statsig user) associated with the request. For example:
rust
use statsig_rust::{Statsig, StatsigUserBuilder};let user = StatsigUserBuilder::new_with_user_id("a-user".to_string()).build();if statsig.check_gate(&user, "a_gate") { // Gate is on, enable new feature} else { // Gate is off}
Reading a Dynamic Config
Feature Gates are useful for simple on/off switches with optional user targeting. To send a different set of values (strings, numbers, and similar types) to clients based on user attributes such as country, use Dynamic Configs. The API is similar to Feature Gates, but returns a full JSON object configurable on the server from which you can fetch typed parameters.
rust
use statsig_rust::{Statsig, StatsigUserBuilder, DynamicConfigEvaluationOptions};use std::sync::Arc;// Get a dynamic config for a specific userlet user = StatsigUserBuilder::new_with_user_id("my_user".to_string()).build();let config = statsig.get_dynamic_config(&user, "a_config");// Access config values with type-safe getters and fallback valueslet product_name = config.get_string("product_name", "Awesome Product v1"); // returns Stringlet price = config.get_double("price", 10.0); // returns f64let should_discount = config.get_bool("discount", false); // returns boollet quantity = config.get_int("quantity", 1); // returns i64// Advanced Usage:// You can disable exposure logging for this specific checklet mut options = DynamicConfigEvaluationOptions::default();options.disable_exposure_logging = Some(true);let config = statsig.get_dynamic_config_with_options(&user, "a_config", &options);// The config object also provides metadata about the evaluationprintln!("{}", config.rule_id); // The ID of the rule that served this configprintln!("{}", config.id_type); // The type of the evaluation (experiment, config, etc)
Getting a Layer/Experiment
Use Layers/Experiments to run A/B/n experiments. Two APIs are available. Statsig recommends Layers because they make parameters reusable and support mutually exclusive experiments.
rust
use statsig_rust::{Statsig, StatsigUserBuilder};// Values via get_layerlet user = StatsigUserBuilder::new_with_user_id("my_user".to_string()).build();let layer = statsig.get_layer(&user, "user_promo_experiments");let title = layer.get_string("title", "Welcome to Statsig!");let discount = layer.get_double("discount", 0.1);// Via get_experimentlet title_exp = statsig.get_experiment(&user, "new_user_promo_title");let price_exp = statsig.get_experiment(&user, "new_user_promo_price");let title = title_exp.get_string("title", "Welcome to Statsig!");let discount = price_exp.get_double("discount", 0.1);
Parameter Stores
Use Parameter Stores when you want to define a parameter without deciding whether it should be a Feature Gate, Experiment, or Dynamic Config. Parameter Stores let you change the parameter type at any point in the Statsig console without a new deployment. Parameter Stores are optional, but parameterizing your application provides future flexibility and allows non-technical Statsig users to turn parameters into experiments.
jsx
let param_store = statsig.get_parameter_store("my_parameters");let param_store_value = param_store.get(&user, "my_parameter_value", false); //false is fallback valueprintln!("param_store_value: {}", param_store_value);
Logging an Event
To track custom events, call the Log Event API. Specify the user, event name, and an optional value or metadata object:
rust
use statsig_rust::{Statsig, StatsigUserBuilder};use std::collections::HashMap;use crate::evaluation::dynamic_value::DynamicValue;// Create a userlet user = StatsigUserBuilder::new_with_user_id("user_id".to_string()).build();// Create metadata hashmaplet mut metadata = HashMap::new();metadata.insert("price".to_string(), "9.99".into());metadata.insert("item_name".to_string(), "diet_coke_48_pack".into());// Log the eventstatsig.log_event( &user, "add_to_cart", Some("SKU_12345".into()), // value as DynamicValue Some(metadata));
Learn more about identifying users, group analytics, and best practices for logging events in the logging events guide.
Retrieving Feature Gate Metadata
In certain scenarios, you may need more information about a gate evaluation than just a boolean value. For additional metadata about the evaluation, use the Get Feature Gate API, which returns a FeatureGate object:
rust
use statsig_rust::{Statsig, StatsigUserBuilder};// Create a userlet user = StatsigUserBuilder::new_with_user_id("user_id".to_string()).build();// Get a feature gatelet gate = statsig.get_feature_gate(&user, "example_gate");// Access gate propertiesprintln!("{}", gate.rule_id);println!("{}", gate.value); // Boolean value of the gate
Using shared instance
To create a single Statsig instance accessible globally throughout your codebase, use the shared instance functionality, which provides a singleton pattern:
rust
// Create a shared instance that can be accessed globallylet statsig = Statsig::new_shared("server-secret-key", None).unwrap();statsig.initialize().await?;// Access the shared instance from anywhere in your codelet shared_statsig = Statsig::shared();let is_feature_enabled = shared_statsig.check_gate(&user, "feature_name");// Check if a shared instance existsif Statsig::has_shared_instance() { // Use the shared instance}// Remove the shared instance when no longer neededStatsig::remove_shared();
The shared instance lets a single Statsig instance be created and accessed globally throughout your application. This is useful when multiple parts of the codebase need Statsig without passing an instance around.
Statsig::new_shared(sdk_key, options): Creates a new shared instance of Statsig that can be accessed globally
Statsig::shared(): Returns the shared instance
Statsig::has_shared_instance(): Checks if a shared instance exists (useful when the shared instance may not be ready yet)
Statsig::remove_shared(): Removes the shared instance (useful when you want to switch to a new shared instance)
has_shared_instance() and remove_shared() are helpful in specific scenarios but aren't required in most use cases where the shared instance is set up near the top of your application.
Also note that only one shared instance can exist at a time. Attempting to create a second shared instance will result in an error.
Manual exposures
By default, the SDK automatically logs an exposure event when you check a gate, get a config, get an experiment, or call get() on a parameter in a layer. To delay exposure logging (for example, to log only after the user actually uses the feature), use manual exposures.
All main SDK functions (check_gate, get_dynamic_config, get_experiment, get_layer) accept an options parameter with a disable_exposure_logging field. When set to true, the SDK doesn't automatically log an exposure. You can then log the exposure manually at a later time:
rust
result = statsig.check_gate_with_options(&user, 'a_gate_name', FeatureGateEvaluationOptions {disable_exposure_logging: true});
The StatsigUser object represents a user in Statsig. You must provide a userID or at least one of the customIDs to identify the user.
When calling APIs that require a user, pass as much information as possible to take advantage of advanced gate and config conditions (like country or OS/browser level checks) and to correctly measure the impact of experiments on metrics and events. As explained here, at least one identifier (userID or customID) is required to provide a consistent experience for a given user.
In addition to userID, the top-level fields on StatsigUser are: email, ip, userAgent, country, locale, and appVersion. You can also pass any key-value pairs in an object or dictionary to the custom field and create targeting based on them.
Private Attributes
Private attributes are user attributes that Statsig uses for evaluation but doesn't forward to any integrations. They are useful for PII or sensitive data that you don't want to send to third-party services.
rust
use statsig_rust::StatsigUserBuilder;use std::collections::HashMap;// Create a user with just a user IDlet user = StatsigUserBuilder::new_with_user_id("user-123".to_string()) .build();// Or create a user with custom IDslet mut custom_ids = HashMap::new();custom_ids.insert("employee_id".to_string(), "emp-456".to_string());let user_with_custom_ids = StatsigUserBuilder::new_with_custom_ids(custom_ids) .build();// Create a user with several propertieslet mut custom_fields = HashMap::new();custom_fields.insert("plan".to_string(), "premium".into());custom_fields.insert("age".to_string(), 25.into());let user = StatsigUserBuilder::new_with_user_id("user-123".to_string()) .email(Some("user@example.com".to_string())) .ip(Some("192.168.1.1".to_string())) .user_agent(Some("Mozilla/5.0...".to_string())) .country(Some("US".to_string())) .locale(Some("en-US".to_string())) .app_version(Some("1.0.0".to_string())) .custom(Some(custom_fields)) .build();// Private Attributes (not forwarded to integrations)let mut private_attrs = HashMap::new();private_attrs.insert("internal_id".to_string(), "emp-123".into());let user_with_private = StatsigUserBuilder::new_with_user_id("user-123".to_string()) .email(Some("user@example.com".to_string())) .private_attributes(Some(private_attrs)) .build();
Statsig Options
You can pass an optional options parameter in addition to sdkKey during initialization to customize the Statsig client.
Proxy and Custom Network Routing
Use proxy_config if your service needs a standard outbound HTTP proxy. If you need to route config sync through Statsig Forward Proxy or another custom source, use spec_adapters_config or specs_url instead. Set ca_cert_path when your environment requires a custom PEM CA bundle for outbound TLS.
Shutting Statsig down
Statsig batches and periodically flushes events. To ensure all logged events are flushed before shutdown, call shutdown() before your app or server shuts down:
rust
statsig.shutdown().await?;
Alternatively, you can manually flush events without shutting down:
rust
// Manually flush events to the serverstatsig.flush_events().await;
SDK Event Subscriptions
The Statsig SDK provides an event subscription system that lets you listen for evaluation events and lifecycle events in real time. This is useful for debugging, analytics, custom logging, and integration with external systems.
Supported Events
The SDK supports subscribing to the following evaluation events:
gate_evaluated - Fired when a feature gate is evaluated for a user
dynamic_config_evaluated - Fired when a dynamic config is retrieved for a user
experiment_evaluated - Fired when an experiment is evaluated for a user
layer_evaluated - Fired when a layer is evaluated for a user
specs_updated - Fired when the SDK updates its cached specs, including where the specs were loaded from
"*" - Subscribe to all evaluation events
SDK Event Data
Each event includes relevant context about the evaluation:
Gate Evaluated Events include: gate_name, value (boolean), rule_id, reason
Dynamic Config Events include: the full dynamic_config object with values and metadata
Experiment Events include: the full experiment object with variant assignment and parameters
Layer Events include: the full layer object with allocated experiment and parameters
Specs Updated Events include source, source_api, and values metadata, where values.time is the timestamp of the last update to the project in the Statsig console
Use Cases
Event subscriptions are particularly useful for:
Debugging: Monitor which features are being evaluated and their results
Analytics: Track feature usage patterns and user segments
Custom Logging: Send evaluation data to your own logging systems
Integration: Forward events to external analytics or monitoring tools
Testing: Verify that features are being evaluated as expected
Best Practices
Clean up subscriptions: Always unsubscribe when you no longer need to listen for events to prevent memory leaks
Handle event data carefully: Event objects may contain sensitive user information depending on your configuration
Use specific event types: Subscribe to specific events rather than "*" when possible for better performance
Avoid heavy processing: Keep event handlers lightweight to avoid impacting SDK performance
rust
use statsig_rust::{Statsig, StatsigUserBuilder, sdk_event_emitter::SdkEvent};let statsig = Statsig::new("server-secret-key", None)?;statsig.initialize().await?;// Subscribe to gate evaluation eventslet gate_sub_id = statsig.subscribe(SdkEvent::GATE_EVALUATED, |event| { if let SdkEvent::GateEvaluated { gate_name, value, rule_id, reason } = event { println!("Gate evaluated: {} = {}, rule: {}, reason: {}", gate_name, value, rule_id, reason); }});// Subscribe to dynamic config evaluation eventslet config_sub_id = statsig.subscribe(SdkEvent::DYNAMIC_CONFIG_EVALUATED, |event| { if let SdkEvent::DynamicConfigEvaluated { dynamic_config } = event { println!("Config evaluated: {}", dynamic_config.name); }});// Subscribe to experiment evaluation eventslet experiment_sub_id = statsig.subscribe(SdkEvent::EXPERIMENT_EVALUATED, |event| { if let SdkEvent::ExperimentEvaluated { experiment } = event { println!("Experiment evaluated: {} -> {}", experiment.name, experiment.group_name); }});// Subscribe to layer evaluation eventslet layer_sub_id = statsig.subscribe(SdkEvent::LAYER_EVALUATED, |event| { if let SdkEvent::LayerEvaluated { layer } = event { println!("Layer evaluated: {}", layer.name); }});let specs_updated_sub_id = statsig.subscribe(SdkEvent::SPECS_UPDATED, |event| { if let SdkEvent::SpecsUpdated { source, source_api, values, } = event { println!( "Specs updated from {} via {} (project last edited at {})", source, source_api, values.time ); }});// Subscribe to all eventslet all_events_sub_id = statsig.subscribe(SdkEvent::ALL, |event| { println!("Event received: {}", event.get_name());});// Unsubscribe from specific event typesstatsig.unsubscribe(SdkEvent::GATE_EVALUATED);statsig.unsubscribe(SdkEvent::SPECS_UPDATED);// Unsubscribe using subscription IDstatsig.unsubscribe_by_id(&config_sub_id);// Unsubscribe from all eventsstatsig.unsubscribe_all();
Local overrides
Local Overrides let you override the values of gates, configs, experiments, and layers for testing. This is useful for local development or testing when you want to force a specific value without changing the configuration in the Statsig console.
Rust
// Overrides the given gate to the specified valuestatsig.override_gate("test_gate", true, None);// Overrides the given dynamic config to the provided valuestatsig.override_dynamic_config("test_1", my_map.clone(), None); //my_map is HashMap<String, Value>// Overrides the given experiment to the provided valuestatsig.override_experiment("test_xp_1", my_map.clone(), None); //my_map is HashMap<String, Value>// Overrides the given experiment to a particular groupname, available for experiments onlystatsig.override_experiment_by_group_name("test_xp_1", "a_group_name", None);// Overrides the given layer to the provided valuestatsig.override_layer("user_promo_experiments", my_map.clone(), None); //my_map is HashMap<String, Value>//Alternatively, get the Experiment object for a given groupNamelet group_exp = statsig.get_experiment_by_group_name("pricing_experiment", "premium_group");let premium_price = group_exp.get_double("price", 9.99);
Persistent storage
The Persistent Storage interface lets you implement custom storage for user-specific configurations. This enables you to persist user assignments across sessions, ensuring consistent experiment groups when a user returns. This is useful for client-side A/B testing where users must always receive the same variant.
The Data Store interface lets you implement custom storage for Statsig configurations, enabling advanced caching strategies and integration with your preferred storage systems.
The Output Logger interface lets you customize how the SDK logs messages, enabling integration with your own logging system and control over log verbosity.
The Observability Client interface lets you monitor the health of the SDK by integrating with your own observability systems. This enables you to track metrics, errors, and performance data. For more information on the metrics emitted by Statsig SDKs, refer to the Monitoring documentation.
This is available for Enterprise contracts. Reach out to our support team, your sales contact, or through our Slack community if you want this enabled.
These methods return an array of strings representing the user fields referenced in the targeting rules or conditions of the specified feature. Use them to understand which user properties influence a particular feature's behavior.
rust
// Get fields needed for a gatelet fields_needed: Vec<String> = statsig.get_fields_needed_for_gate("gate_name");// Get fields needed for a dynamic configlet fields_needed: Vec<String> = statsig.get_fields_needed_for_dynamic_config("config_name");// Get fields needed for an experimentlet fields_needed: Vec<String> = statsig.get_fields_needed_for_experiment("experiment_name");// Get fields needed for a layerlet fields_needed: Vec<String> = statsig.get_fields_needed_for_layer("layer_name");
Field Mapping
The fields returned by these methods correspond to the following user properties:
rust
// Field mapping between user properties and internal field nameslet field_mapping = std::collections::HashMap::from([ ("userID", "u"), ("email", "e"), ("ip", "i"), ("userAgent", "ua"), ("country", "c"), ("locale", "l"), ("appVersion", "a"), ("time", "t"), ("stableID", "s"), ("environment", "en"), ("targetApp", "ta"),]);// Custom fields are prefixed with "cf:"// Example: fields.add("cf:" + field_name);
FAQ
Reference
Fields Needed Methods (Enterprise Only)
rust
// Get user fields needed for a gate evaluationpub fn get_fields_needed_for_gate(&self, gate_name: &str) -> Vec<String>// Get user fields needed for a dynamic config evaluationpub fn get_fields_needed_for_dynamic_config(&self, config_name: &str) -> Vec<String>// Get user fields needed for an experiment evaluationpub fn get_fields_needed_for_experiment(&self, experiment_name: &str) -> Vec<String>// Get user fields needed for a layer evaluationpub fn get_fields_needed_for_layer(&self, layer_name: &str) -> Vec<String>
This is available for Enterprise contracts. Reach out to our support team, your sales contact, or through our Slack community if you want this enabled.
Field Mapping
The fields returned by these methods correspond to the following user properties:
plaintext
// Field mapping between user properties and internal field namesconst fieldMapping = { userID: 'u', email: 'e', ip: 'i', userAgent: 'ua', country: 'c', locale: 'l', appVersion: 'a', time: 't', stableID: 's', environment: 'en', targetApp: 'ta',};// Custom fields are prefixed with "cf:"// Example: fields.add('cf:' + field);