Best Tools for Remote Team A/B Testing
Remote product teams lose coordination velocity when experiments require deploys. A proper feature flagging system lets engineers ship code that’s dark by default, PMs turn experiments on without engineering intervention, and data teams analyze results from a dashboard rather than a Slack thread.
What to Look For
- SDK support for your stack (Node, Python, React, Go, iOS, Android)
- Self-hosted option if you have data residency requirements
- Targeting rules (by user ID, cohort, region, email domain)
- Audit log so you know who turned what on
- Metrics integration so results tie back to your analytics warehouse
Option 1: GrowthBook (Best Open Source)
GrowthBook is open source, self-hostable, and has native integration with Snowflake, BigQuery, Redshift, and Mixpanel for statistical analysis.
Self-hosted deploy:
version: "3.8"
services:
growthbook:
image: growthbook/growthbook:latest
ports:
- "3100:3100"
- "3000:3000"
environment:
MONGODB_URI: mongodb://mongo:27017/growthbook
APP_ORIGIN: https://experiments.yourcompany.internal
API_HOST: https://experiments.yourcompany.internal:3100
JWT_SECRET: "${GROWTHBOOK_JWT_SECRET}"
ENCRYPTION_KEY: "${GROWTHBOOK_ENCRYPTION_KEY}"
depends_on:
- mongo
restart: unless-stopped
mongo:
image: mongo:6
volumes:
- mongo-data:/data/db
volumes:
mongo-data:
JavaScript SDK:
import { GrowthBook } from "@growthbook/growthbook";
const gb = new GrowthBook({
apiHost: "https://experiments.yourcompany.internal:3100",
clientKey: "sdk-your-client-key",
enableDevMode: process.env.NODE_ENV !== "production",
trackingCallback: (experiment, result) => {
analytics.track("Experiment Viewed", {
experimentId: experiment.key,
variationId: result.variationId,
});
},
});
gb.setAttributes({
id: user.id,
email: user.email,
plan: user.plan,
country: user.country,
});
await gb.loadFeatures();
const newCheckout = gb.isOn("new-checkout-flow");
const buttonColor = gb.getFeatureValue("cta-button-color", "blue");
Python SDK:
from growthbook import GrowthBook
gb = GrowthBook(
api_host="https://experiments.yourcompany.internal:3100",
client_key="sdk-your-client-key",
attributes={"id": user_id, "email": user_email, "plan": user_plan},
)
gb.load_features()
if gb.is_on("new-pricing-page"):
return render_template("pricing_v2.html")
else:
return render_template("pricing.html")
Option 2: Flagsmith
Flagsmith separates feature flags from A/B experiments, supports remote config values, and has a generous free tier.
curl -L https://raw.githubusercontent.com/Flagsmith/flagsmith/main/docker/docker-compose.yml \
-o flagsmith-compose.yml
docker-compose -f flagsmith-compose.yml up -d
Node.js SDK:
const Flagsmith = require("flagsmith-nodejs");
const flagsmith = new Flagsmith({
environmentKey: process.env.FLAGSMITH_ENV_KEY,
apiUrl: "https://flags.yourcompany.internal/api/v1/",
enableLocalEvaluation: true,
environmentRefreshIntervalSeconds: 60,
});
const flags = await flagsmith.getIdentityFlags(user.id, {
email: user.email,
plan: user.plan,
});
const showNewNav = flags.isFeatureEnabled("new_navigation");
const checkoutVersion = flags.getFeatureValue("checkout_version", "v1");
Option 3: Unleash (Enterprise Open Source)
Unleash’s gradual rollout strategies (percentile, userId hash, IP, hostname) are the most flexible of any open source option.
apiVersion: apps/v1
kind: Deployment
metadata:
name: unleash
spec:
replicas: 2
selector:
matchLabels:
app: unleash
template:
spec:
containers:
- name: unleash
image: unleashorg/unleash-server:latest
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: unleash-secrets
key: database-url
Node.js SDK:
const { initialize } = require("unleash-client");
const unleash = initialize({
url: "https://unleash.yourcompany.internal/api/",
appName: "myapp",
customHeaders: { Authorization: process.env.UNLEASH_API_TOKEN },
});
await new Promise(resolve => unleash.on("synchronized", resolve));
const userId = String(user.id);
if (unleash.isEnabled("new-dashboard", { userId })) {
return renderNewDashboard();
}
Option 4: LaunchDarkly (Best SaaS Option)
LaunchDarkly is the fastest to set up and has the richest targeting UI.
const LaunchDarkly = require("@launchdarkly/node-server-sdk");
const ldClient = LaunchDarkly.init(process.env.LAUNCHDARKLY_SDK_KEY);
await ldClient.waitForInitialization();
const context = {
kind: "user",
key: user.id,
email: user.email,
plan: user.plan,
};
const showBeta = await ldClient.variation("beta-features", context, false);
const pricingLayout = await ldClient.variation("pricing-page-layout", context, "control");
Comparison
| Tool | Self-Hosted | Statistics | SDK Count | Free Tier |
|---|---|---|---|---|
| GrowthBook | Yes | Bayesian + Frequentist | 15+ | Yes |
| Flagsmith | Yes | Basic | 10+ | 50k requests/mo |
| Unleash | Yes | None | 15+ | Open source |
| LaunchDarkly | No | Built-in | 20+ | Developer plan |
Experiment Discipline for Remote Teams
Write a hypothesis before enabling a flag:
## Experiment: new-checkout-flow
Hypothesis: Simplifying checkout from 4 steps to 2 will increase
completion rate by 15% for users on mobile.
Primary metric: checkout_completed / checkout_started (mobile only)
Secondary: average_order_value
Guardrail: checkout_error_rate must not increase
Sample size: 2,400 per variant (80% power, alpha=0.05)
Duration: 14 days minimum
Owner: @product-manager
Clean up old flags monthly. A flag at 100% rollout for 60 days should be removed from code.
Related Reading
- Best Tools for Remote Team Sprint Velocity
- Best Tools for Remote Team Post-Mortems
- Best Tools for Remote Team Changelog Review
Built by theluckystrike — More at zovo.one