statsig-client

Crates.iostatsig-client
lib.rsstatsig-client
version0.1.0
created_at2025-12-15 06:24:23.22465+00
updated_at2025-12-15 06:24:23.22465+00
descriptionA Rust client library for Statsig feature flag and experimentation platform
homepagehttps://github.com/quangio/statsig-client
repositoryhttps://github.com/quangio/statsig-client
max_upload_size
id1985639
size149,682
Quang Luong (quangIO)

documentation

https://docs.rs/statsig-client

README

statsig-client

A Rust client for Statsig's feature flag and experimentation platform. Built for production use with proper error handling, caching, and batch processing.

Why this client?

A reliable, type-safe Rust client for Statsig designed for client-side applications. Perfect for:

  • Desktop and mobile apps

  • Edge functions and middleware

  • Anywhere you need client-side feature flags

  • Works with client keys (like the JS SDK)

  • Handles network failures gracefully with retries

  • Caches responses to reduce API calls and latency

  • Validates inputs before they hit the wire

  • Supports batch operations for better performance

  • Uses builder patterns for clean, readable code

Installation

[dependencies]
statsig-client = "0.1.0"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

Getting Started

use statsig_client::{StatsigClient, User};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create the client with your Statsig client key
    let client = StatsigClient::new("your-client-key").await?;
    
    // Define your user
    let user = User::builder()
        .user_id("user-123")
        .email("user@example.com")
        .country("US")
        .build()?;
    
    // Check if a feature is enabled for this user
    if client.check_gate("new-dashboard", &user).await? {
        println!("User gets the new dashboard!");
    }
    
    Ok(())
}

Configuration

Tweak the client behavior to fit your needs:

use statsig_client::{StatsigClient, StatsigClientConfig};
use std::time::Duration;

let config = StatsigClientConfig::builder()
    .api_key("your-client-key")
    .timeout(Duration::from_secs(10))           // Request timeout
    .cache_ttl(Duration::from_secs(300))        // Cache for 5 minutes
    .cache_max_capacity(1000)                   // Max cached items
    .retry_attempts(3)                          // Retry failed requests
    .retry_delay(Duration::from_millis(500))    // Delay between retries
    .build();

let client = StatsigClient::with_config(config).await?;

Rich User Context

Add custom data to target your features better:

let user = User::builder()
    .user_id("user-123")
    .email("user@example.com")
    .country("US")
    .custom([
        ("subscription_plan", serde_json::json!("premium")),
        ("account_age_days", serde_json::json!(45)),
        ("last_login", serde_json::json!("2024-01-15")),
    ])
    .private_attributes([("internal_id", serde_json::json!("internal-123"))])
    .build()?;

Dynamic Configs

Fetch configuration values:

let config = client.get_config("ui-settings", &user).await?;
let theme = config.get("theme").and_then(|v| v.as_str()).unwrap_or("light");
let max_items = config.get("max_items").and_then(|v| v.as_u64()).unwrap_or(10);

println!("Theme: {}, Max items: {}", theme, max_items);

Event Tracking

Log user actions for analytics:

// Simple event
client.log_event("button_click", &user).await?;

// Event with metadata
use std::collections::HashMap;
let mut metadata = HashMap::new();
metadata.insert("button_id".to_string(), "submit_form".to_string());
metadata.insert("page".to_string(), "checkout".to_string());

client.log_event_with_metadata("form_submit", &user, metadata).await?;

Batch Operations

Check multiple flags at once to reduce API calls:

let gates = client.check_gates(vec![
    "new-dashboard".to_string(),
    "beta-features".to_string(),
    "advanced-analytics".to_string(),
], &user).await?;

for (gate_name, enabled) in gates {
    if enabled {
        println!("{} is enabled for this user", gate_name);
    }
}

Error Handling

Things go wrong. Here's how to handle it:

match client.check_gate("new-feature", &user).await {
    Ok(enabled) => println!("Feature enabled: {}", enabled),
    Err(StatsigError::Network(msg)) => {
        eprintln!("Network issue: {}. Using fallback.", msg);
        // Fall back to default behavior
    },
    Err(StatsigError::Api { status, message }) => {
        eprintln!("Statsig API error {}: {}", status, message);
        // Log the error and continue
    },
    Err(StatsigError::Validation(msg)) => {
        eprintln!("Invalid input: {}", msg);
        // Fix the input and retry
    },
    Err(e) => eprintln!("Unexpected error: {}", e),
}

What Gets Cached?

The client caches responses to reduce latency and API costs:

  • Feature gate results (default: 5 minutes)
  • Dynamic config values (default: 5 minutes)
  • Cache keys include user hash + entity name
  • Automatic cache invalidation on errors

Performance Tips

  1. Batch your checks - Use check_gates() instead of multiple check_gate() calls
  2. Reuse the client - Create one client and share it across your app
  3. Adjust cache TTL - Longer TTLs reduce API calls but may delay updates
  4. Set appropriate timeouts - Balance between reliability and responsiveness

License

MIT OR Apache-2.0 - pick whichever works for you.

Contributing

Found a bug or want to add something? Open an issue or send a PR.

Commit count: 0

cargo fmt