Tuesday 09:14. Growth ships a checkout experiment in Statsig — gate new_payment_sheet, 8% exposure, funnel metrics wired to the warehouse. Same standup, the payments SRE reports processor latency spiking: they need failure_rate_threshold at 28, fraud.block_score at 79, and the Python embedding service needs worker_pool_size cut from 48 to 24 before GPUs OOM.
The growth lead asks:
"Statsig has dynamic config — put the circuit threshold in a config parameter. One SDK."
The principal engineer on authorization pushes back:
"Statsig is built for who enters the experiment and what we measure. Our auth path runs 14k evaluations per second for floats that change during incidents — not for cohort bucketing with event logging overhead."
Statsig is a strong product development platform — feature gates, A/B experiments, dynamic config, and analytics that tie flag exposure to business metrics. Kiponos.io is a live operational config hub — nested trees, WebSocket deltas, and local get*() reads in Java and Python on the money path. Mature teams use Statsig where product learns; Kiponos where production survives.
The problem — experiment SDK semantics on the authorization hot path
Typical Statsig integration for a product gate:
// Product path — correct use of Statsig
StatsigUser user = new StatsigUser.Builder()
.setUserID(customerId)
.setEmail(email)
.build();
boolean showNewSheet = Statsig.checkGate(user, "new_payment_sheet");
Teams then extend dynamic config for ops:
// Anti-pattern — ops float stuffed into experiment infrastructure
DynamicConfig resilience = Statsig.getConfig(user, "resilience_tuning");
int failureThreshold = resilience.getInt("failure_rate_threshold", 40);
if (rollingFailureRate > failureThreshold) {
return CircuitDecision.open();
}
Problems compound quickly:
- User context required — circuit breakers are system-bound, not identity-bound; fake system users are a smell
- Evaluation + exposure logging — optimized for product analytics, not bare-metal hot-path floats
-
Flat config namespaces —
fraud.block_score,resilience.payments.wait_ms, andml.pool_sizelack a shared ops tree across four services - Python workers and Java APIs — same dynamic config duplicated or synced through custom glue
Statsig dynamic config is legitimate for product-tunable parameters (onboarding copy variants, default tab selection). It is the wrong primitive for incident knobs on saturated authorization paths.
What teams believe vs production reality
| Belief | Production reality |
|---|---|
| "Statsig dynamic config replaces a config hub" | Built for parameter experiments, not nested ops trees |
| "One SDK simplifies architecture" | Product gates and fraud floats have different latency budgets |
| "Exposure events are free" | At 14k TPS, even lightweight logging adds up on the hot path |
| "Engineers can share one dashboard" | PM experiments and SRE incident keys collide in the same namespace |
| "We will use Redis for the rest" | Now you operate Statsig + Redis + YAML for one platform |
The Aha
Statsig decides which users see which product experiences and measures outcomes. Kiponos decides how hard production runs when processors degrade and fraud spikes. Keep new_payment_sheet in Statsig with full experiment analytics. Move failure_rate_threshold, block_score, and worker_pool_size to Kiponos — local reads, no per-transaction experiment evaluation.
What Kiponos.io is for Statsig-heavy product orgs
Kiponos is a real-time configuration hub. Java and Python SDKs connect once via WebSocket, hydrate a typed profile tree, and serve getInt(), getDouble(), and getBoolean() from in-process memory. Dashboard edits push single-key deltas — change fraud/thresholds/block_score from 85 to 79; every pod sees it without redeploy.
Profile path for this comparison:
['payments']['api']['prod']['live']
Product gates stay in Statsig. Operational knobs live beside them in Kiponos if you want one mental model for "live values" — but the read contract is always local cache lookup, not gate evaluation with user context.
Architecture — Statsig product plane vs Kiponos ops plane
Hybrid is the norm: Statsig owns identity-bound experiments; Kiponos owns system-bound thresholds both runtimes read.
Config tree — ops keys that do not belong in experiment config
fraud/
thresholds/
block_score: 79
review_score: 65
velocity_per_hour: 18
bin_attack_mode: true
resilience/
payments/
failure_rate_threshold: 28
wait_duration_open_ms: 22000
half_open_permitted_calls: 8
inventory/
failure_rate_threshold: 42
slow_call_threshold_ms: 3500
ml/
embedding/
worker_pool_size: 24
batch_size: 32
max_sequence_length: 512
oom_guard_enabled: true
limits/
partner_checkout/
rpm: 9500
burst: 1400
statsig_bridge/
# Optional: document which gates remain on Statsig
new_payment_sheet_gate: statsig_owned
onboarding_copy_experiment: statsig_owned
Java integration — authorization path stays local
@Configuration
public class KiponosConfig {
@Bean
public Kiponos kiponos(
@Value("${kiponos.team-id}") String teamId,
@Value("${kiponos.access-key}") String accessKey,
@Value("${kiponos.profile-path}") String profilePath) {
return Kiponos.builder()
.teamId(teamId)
.accessKey(accessKey)
.profilePath(profilePath)
.build();
}
}
@Service
public class PartnerCircuitEvaluator {
private final Kiponos kiponos;
public PartnerCircuitEvaluator(Kiponos kiponos) {
this.kiponos = kiponos;
}
public CircuitState evaluate(String partnerId, double rollingFailureRate) {
var resilience = kiponos.path("resilience", "payments");
int threshold = resilience.getInt("failure_rate_threshold");
long waitOpenMs = resilience.getLong("wait_duration_open_ms");
if (rollingFailureRate > threshold) {
return CircuitState.open(partnerId, waitOpenMs);
}
return CircuitState.closed();
}
}
Product gate — keep Statsig on the checkout path where analytics matter:
public boolean renderNewPaymentSheet(String customerId, String email) {
StatsigUser user = new StatsigUser.Builder()
.setUserID(customerId)
.setEmail(email)
.build();
return Statsig.checkGate(user, "new_payment_sheet");
// Do not route fraud.block_score through this SDK
}
Python integration — ML worker reads same ops tree
import os
from kiponos import Kiponos
os.environ["KIPONOS_PROFILE"] = "['payments']['api']['prod']['live']"
kiponos = Kiponos.create_for_current_team()
def current_pool_size() -> int:
return kiponos.path("ml", "embedding").get_int("worker_pool_size", 48)
def on_config_change(change):
if change.path.startswith("ml/embedding/worker_pool_size"):
resize_process_pool(int(change.new_value))
kiponos.after_value_changed(on_config_change)
Statsig has no first-class story for a Python GPU worker and a Java authorization cluster sharing ml/embedding/worker_pool_size with sub-second incident edits.
Real scenarios
| Event | Statsig alone | Statsig + Kiponos |
|---|---|---|
Launch new_payment_sheet gate at 8% |
Native gate + funnel metrics | Keep Statsig; unchanged |
| Processor brownout — open circuit faster | Dynamic config hack + system user |
resilience/payments/failure_rate_threshold live |
| BIN attack — lower block score | Wrong tool / awkward config param |
fraud/thresholds/block_score in seconds |
| GPU OOM — shrink embedding pool | Not the tool |
ml/embedding/worker_pool_size in Python |
| Cross-service saga timeout alignment | Flat config keys | Shared nested resilience/ tree |
| Measure experiment lift on checkout | Statsig analytics | Keep Statsig; ops keys in Kiponos audit log |
Performance — hot path economics on authorization
- Statsig gate check — user context, bucketing, exposure pipeline — right for product paths at human scale
- Statsig dynamic config on auth — per-evaluation config fetch semantics; not designed for 14k bare floats/sec
-
Kiponos
getInt()— in-memory tree lookup; no network on read path - Delta updates — incident changes one key; no full dynamic config document redeploy
- One WebSocket per JVM/worker — background sync; hot path never blocks on vendor RTT
- Polyglot parity — Java Spring Boot 3 and Python workers share one profile; Statsig SDK coverage varies by runtime role
Honest comparison table
| Criterion | Statsig | Kiponos | Honest verdict |
|---|---|---|---|
| Feature gates & exposure logging | Excellent | App-side bucketing possible | Statsig wins product gates |
| A/B experiments + funnel metrics | Core strength | Ops change log only | Statsig for measured experiments |
| Dynamic config for product params | Good | Good for ops trees | Statsig for copy/UX tuning |
| Numeric incident knobs (fraud, circuits) | Awkward fit | First-class | Kiponos on money path |
| Nested cross-service ops trees | Flat namespaces | Hierarchical paths | Kiponos for platform ops |
| Hot-path read at 14k TPS | Evaluation model | Local cache | Kiponos on authorization |
| Java + Python same hub | Partial / role-dependent | Both SDKs | Kiponos for polyglot ops |
| Product analytics warehouse tie-in | Built-in | Not a product analytics tool | Complementary |
| Pricing model | Event / MAU oriented | Team/hub pricing | Model your experiment vs ops split |
When not to use Kiponos
| Use case | Better tool |
|---|---|
| Gated rollouts with experiment lift measurement | Statsig |
| Funnel metrics tied to flag exposure | Statsig |
| Non-technical PM self-serve experiment creation | Statsig |
| Bootstrap secrets and API keys | Vault / cloud secret manager |
| Infrastructure desired state | GitOps / Terraform |
Getting started (15 minutes) — split product from ops
- Inventory every live key: mark product experiment (gate, A/B, UX param) vs operational knob (fraud, circuit, pool).
-
TeamPro at kiponos.io — profile
['payments']['api']['prod']['live']. - Migrate three ops keys off Statsig dynamic config:
block_score, onefailure_rate_threshold, oneworker_pool_size. - Wire Java
PartnerCircuitEvaluatorand Python embedding worker to the same profile. - Document RFC: "Statsig owns gates and experiments with analytics; Kiponos owns ops floats on hot paths."
Further reading
- Developer Quickstart
- Product tour
- GETTING-STARTED.md
- Feature flags vs config hub (architecture)
- Kiponos vs LaunchDarkly
- Fraud payment routing
- Rate limits & circuit breakers
- github.com/kiponos-io/kiponos-io
Kiponos.io — Statsig for which users see the experiment. Live hub for how hard production runs during the incident.

Top comments (0)