Skip to content

Client SDK Guide

Frontend integration guide for Better Auth Feature Flags.

Installation

Install the client SDK with your package manager:

bash
bun add better-auth better-auth-feature-flags
bash
npm install better-auth better-auth-feature-flags
bash
pnpm add better-auth better-auth-feature-flags

Basic Setup

Initialize the Client

typescript
import { createAuthClient } from "better-auth/client";
import { featureFlagsClient } from "better-auth-feature-flags/client";

const authClient = createAuthClient({
  baseURL: "https://api.example.com", // Your API URL
  plugins: [
    featureFlagsClient({
      // Client options (optional)
    }),
  ],
});

Client Options

typescript
featureFlagsClient({
  // Cache configuration
  cache: {
    enabled: true, // Cache flag values (default: true)
    ttl: 60000, // Time to live in milliseconds (default: 60000)
    storage: "memory", // or "localStorage", "sessionStorage"
    keyPrefix: "ff_", // Cache key prefix (default: "ff_")
    version: "v1", // Cache version for invalidation
    include: ["critical-flag"], // Only cache these flags
    exclude: ["dynamic-flag"], // Never cache these flags
  },

  // Smart polling with exponential backoff
  polling: {
    enabled: false, // Poll for flag changes
    interval: 30000, // Base interval: 30 seconds (backs off on errors)
  },

  // Default values
  defaults: {
    "feature-1": false,
    "feature-2": "default",
  },

  // Debug mode
  debug: true, // Enable debug logging

  // Error handling
  onError: (error) => {
    console.error("Feature flag error:", error);
  },

  // Evaluation callback
  onEvaluation: (flag, result) => {
    console.log(`Flag ${flag} evaluated to:`, result);
  },
});

Cache Architecture

The client SDK includes an intelligent caching system with several key features:

Session-Aware Caching

The cache automatically invalidates when user sessions change:

  • Automatic Detection: Integrates with Better Auth's session management
  • Complete Invalidation: Clears all cached flags on login/logout
  • Session Binding: Cache entries are associated with session IDs
  • Zero Configuration: Works automatically without setup

Memory Management

Prevents memory leaks with built-in limits:

  • LRU Eviction: Automatically removes least recently used entries
  • Max Entries: Limited to 100 cached flags by default
  • Access Tracking: Maintains usage order for intelligent eviction

Storage Quota Handling

Gracefully handles browser storage limitations:

  • Quota Detection: Catches QuotaExceededError exceptions
  • Automatic Cleanup: Removes oldest entries when storage is full
  • Fallback Strategy: Continues with memory-only cache if storage fails
  • Silent Recovery: No disruption to user experience

Cache Versioning

Supports cache busting for schema changes:

typescript
featureFlagsClient({
  cache: {
    version: "v2", // Changing version clears old cache
  },
});

When the version changes, all previous cache entries are automatically cleared on initialization.

Core Methods

Check if Enabled

typescript
// Simple boolean check
const isEnabled = await authClient.featureFlags.isEnabled("dark-mode");

// With default value
const isEnabled = await authClient.featureFlags.isEnabled(
  "new-feature",
  false // Default if flag not found
);

Get Flag Value

typescript
// Get typed value
const theme = await authClient.featureFlags.getValue<string>(
  "theme-name",
  "light" // Default value
);

// Complex object
interface Config {
  layout: string;
  color: string;
}

const config = await authClient.featureFlags.getValue<Config>("ui-config", {
  layout: "grid",
  color: "blue",
});

Get Variant

typescript
// Get A/B test variant
const variant = await authClient.featureFlags.getVariant("checkout-test");

if (variant) {
  console.log(variant.key); // "control" or "variant-a"
  console.log(variant.value); // Variant configuration
  console.log(variant.percentage); // Optional percentage allocation
}

Get All Flags

typescript
// Get all evaluated flags
const flags = await authClient.featureFlags.getAllFlags();

console.log(flags);
// {
//   "feature-1": true,
//   "feature-2": "value",
//   "feature-3": { complex: "object" }
// }

Batch Evaluation

typescript
// Evaluate multiple flags at once for better performance
const results = await authClient.featureFlags.evaluateBatch([
  "feature-1",
  "feature-2",
  "feature-3",
]);

console.log(results);
// {
//   "feature-1": { value: true, reason: "rule_match" },
//   "feature-2": { value: "variant-a", variant: {...}, reason: "percentage" },
//   "feature-3": { value: false, reason: "default" }
// }

Track Events

typescript
// Track conversion with numeric value
await authClient.featureFlags.track(
  "checkout-test",
  "purchase",
  99.99 // Optional numeric value
);

// Track with metadata
await authClient.featureFlags.track(
  "onboarding-flow",
  "step-completed",
  { step: 3, time: 45 } // Optional metadata object
);

// Track simple event
await authClient.featureFlags.track("feature-used", "click");

Context Management

typescript
// Set evaluation context
authClient.featureFlags.setContext({
  userId: "user-123",
  organizationId: "org-456",
  attributes: {
    plan: "premium",
    country: "US",
  },
  device: "mobile",
  browser: "chrome",
  version: "1.2.3",
});

// Get current context
const context = authClient.featureFlags.getContext();

Context Security

The SDK automatically sanitizes context data to prevent PII leakage:

Default Behavior:

  • Removes sensitive fields (passwords, tokens, credit cards, SSN)
  • Enforces size limits (2KB for URLs, 10KB for POST bodies)
  • Whitelists safe fields only (strict mode by default)
  • Warns about dropped fields in development

Allowed Fields (Default):

typescript
// These fields are allowed by default
const safeContext = {
  // User identifiers
  userId,
  organizationId,
  teamId,
  role,
  plan,
  subscription,

  // Device/environment
  device,
  browser,
  os,
  platform,
  version,
  locale,
  timezone,

  // Application state
  page,
  route,
  feature,
  experiment,

  // Business attributes
  country,
  region,
  environment,
  buildVersion,
};

Configuration:

typescript
featureFlagsClient({
  contextSanitization: {
    enabled: true, // Enable/disable sanitization (default: true)
    strict: true, // Only allow whitelisted fields (default: true)
    allowedFields: ["customField1", "customField2"], // Additional allowed fields
    maxUrlSize: 2048, // Max size for GET requests (default: 2KB)
    maxBodySize: 10240, // Max size for POST requests (default: 10KB)
    warnOnDrop: true, // Log warnings when fields are dropped
  },
});

Security Best Practices:

typescript
// ❌ NEVER include sensitive data
authClient.featureFlags.setContext({
  userId: "user-123",
  password: "secret", // Will be removed
  apiKey: "key-123", // Will be removed
  creditCard: "4111-1111-1111-1111", // Will be removed
});

// ✅ Use safe, non-sensitive data
authClient.featureFlags.setContext({
  userId: "user-123",
  role: "admin",
  plan: "premium",
  device: "mobile",
});

// ✅ For custom fields, add them to allowlist
featureFlagsClient({
  contextSanitization: {
    allowedFields: ["departmentId", "projectId"],
  },
});

Cache Management

typescript
// Prefetch critical flags on app load
await authClient.featureFlags.prefetch(["critical-flag-1", "critical-flag-2"]);

// Clear cache when needed
authClient.featureFlags.clearCache();

// Refresh all flags
await authClient.featureFlags.refresh();

Local Overrides (Development)

Security Warning

Overrides are automatically disabled in production to prevent debug features from being exposed. Never use allowInProduction: true unless absolutely necessary.

typescript
// ✅ SAFE: Overrides blocked in production by default
authClient.featureFlags.setOverride("new-feature", true);

// ⚠️ DANGEROUS: Explicitly allowing production overrides
featureFlagsClient({
  overrides: {
    allowInProduction: true, // Never do this!
  },
});

Override Configuration

typescript
featureFlagsClient({
  overrides: {
    ttl: 3600000, // Expire after 1 hour (default)
    persist: true, // Save to localStorage (default: false)
    keyPrefix: "my-app", // Storage key prefix
    // allowInProduction: false, // Keep this false!
  },
});

Security Features

  • Automatic Expiration: Overrides expire after 1 hour by default
  • Environment Detection: Disabled in production unless explicitly allowed
  • Session Isolation: Overrides are client-specific, not shared
  • Cleanup on Dispose: Overrides cleared when component unmounts
typescript
// Override flag values for testing (dev only)
if (process.env.NODE_ENV === "development") {
  authClient.featureFlags.setOverride("new-feature", true);
  authClient.featureFlags.setOverride("test-variant", {
    key: "variant-b",
    value: { color: "green" },
  });
}

// Clear all overrides
authClient.featureFlags.clearOverrides();

Real-time Updates

typescript
// Subscribe to flag changes
const unsubscribe = authClient.featureFlags.subscribe((flags) => {
  console.log("Flags updated:", flags);
  // Update UI based on new flags
});

// Cleanup
unsubscribe();

Smart Polling

The SDK includes intelligent polling that prevents server overload:

  • Jitter: Adds 0-25% random delay to prevent synchronized requests
  • Exponential Backoff: On errors, intervals increase: 30s → 60s → 120s → 240s
  • Auto-Recovery: Returns to normal interval after successful poll
  • Maximum Backoff: Capped at 10x base interval or 5 minutes
typescript
featureFlagsClient({
  polling: {
    enabled: true,
    interval: 30000, // Base: 30 seconds
  },
  onError: (error) => {
    // Polling automatically backs off on errors
    console.error("Polling error (will retry with backoff):", error);
  },
});

React Integration

Provider Setup

Wrap your app with the feature flags provider:

tsx
import { FeatureFlagsProvider } from "better-auth-feature-flags/react";
import { authClient } from "./auth-client";

function App() {
  return (
    <FeatureFlagsProvider client={authClient}>
      <YourApp />
    </FeatureFlagsProvider>
  );
}

React Hooks

useFeatureFlag()

Check if a single flag is enabled:

tsx
import { useFeatureFlag } from "better-auth-feature-flags/react";

function Component() {
  // Returns boolean with optional default value
  const isDarkMode = useFeatureFlag("dark-mode", false);

  return (
    <div className={isDarkMode ? "dark" : "light"}>{/* Your content */}</div>
  );
}

useFeatureFlags()

Get all flags:

tsx
import { useFeatureFlags } from "better-auth-feature-flags/react";

function Dashboard() {
  const flags = useFeatureFlags();
  const showNewUI = flags["new-dashboard"];

  return showNewUI ? <NewDashboard /> : <OldDashboard />;
}

useTrackEvent()

Track analytics events:

tsx
import { useTrackEvent } from "better-auth-feature-flags/react";

function CheckoutButton() {
  const track = useTrackEvent();

  const handlePurchase = async (amount: number) => {
    // Track conversion event
    await track("checkout-test", "purchase", amount);
    // Process purchase...
  };

  return <button onClick={() => handlePurchase(99.99)}>Buy Now</button>;
}

useFeatureFlagsState()

Get loading and error states:

tsx
import { useFeatureFlagsState } from "better-auth-feature-flags/react";

function FeatureStatus() {
  const { loading, error, refresh } = useFeatureFlagsState();

  if (loading) return <Spinner />;
  if (error) return <ErrorMessage error={error} />;

  return <button onClick={refresh}>Refresh Flags</button>;
}

useFeatureFlagsCacheInfo()

Monitor cache state for debugging (development only):

tsx
import { useFeatureFlagsCacheInfo } from "better-auth-feature-flags/react";

function DebugPanel() {
  const cacheInfo = useFeatureFlagsCacheInfo();

  if (process.env.NODE_ENV !== "development") return null;

  return (
    <div className="debug-panel">
      <p>Cache Enabled: {cacheInfo.cacheEnabled ? "Yes" : "No"}</p>
      <p>Cached Flags: {cacheInfo.flagCount}</p>
    </div>
  );
}

useVariant()

Get A/B test variant:

tsx
import { useVariant } from "better-auth-feature-flags/react";

function CheckoutButton() {
  const variant = useVariant("checkout-test");

  const buttonProps = variant?.value || {
    text: "Buy Now",
    color: "blue",
  };

  return (
    <button style={{ backgroundColor: buttonProps.color }}>
      {buttonProps.text}
    </button>
  );
}

useFeatureFlagValue()

Get typed flag value:

tsx
import { useFeatureFlagValue } from "better-auth-feature-flags/react";

function Settings() {
  const maxItems = useFeatureFlagValue<number>("max-items", 10);

  return <ItemList maxItems={maxItems} />;
}

Feature Component

Conditionally render based on flag:

tsx
import { Feature } from "better-auth-feature-flags/react";

function App() {
  return (
    <>
      {/* Simple feature gate */}
      <Feature flag="new-header">
        <NewHeader />
      </Feature>

      {/* With fallback */}
      <Feature flag="beta-feature" fallback={<ComingSoon />}>
        <BetaFeature />
      </Feature>

      {/* With additional validation */}
      <Feature
        flag="premium-feature"
        validateAccess={(flags) => flags["subscription"] === "premium"}
        fallback={<UpgradePrompt />}
      >
        <PremiumContent />
      </Feature>
    </>
  );
}

Variant Component

Render different variants for A/B testing:

tsx
import { Variant } from "better-auth-feature-flags/react";

function HomePage() {
  return (
    <Variant flag="homepage-test">
      <Variant.Case variant="control">
        <ClassicHomepage />
      </Variant.Case>

      <Variant.Case variant="variant-a">
        <ModernHomepage />
      </Variant.Case>

      <Variant.Case variant="variant-b">
        <ExperimentalHomepage />
      </Variant.Case>

      <Variant.Default>
        <DefaultHomepage />
      </Variant.Default>
    </Variant>
  );
}

Error Boundary

Handle feature flag errors gracefully:

tsx
import { FeatureFlagErrorBoundary } from "better-auth-feature-flags/react";

function App() {
  return (
    <FeatureFlagErrorBoundary
      fallback={<SafeFallbackUI />}
      onError={(error) => {
        // Log to error tracking service
        console.error("Feature flag error:", error);
      }}
    >
      <FeatureGatedContent />
    </FeatureFlagErrorBoundary>
  );
}

Higher-Order Components

For class components or additional flexibility:

tsx
import {
  withFeatureFlags,
  withFeatureFlag,
} from "better-auth-feature-flags/react";

// Inject all flags as props
const EnhancedComponent = withFeatureFlags(({ featureFlags }) => {
  return <div>Dark mode: {featureFlags["dark-mode"] ? "On" : "Off"}</div>;
});

// Conditionally render based on flag
const PremiumFeature = withFeatureFlag(
  "premium-feature",
  FallbackComponent // Optional fallback
)(PremiumComponent);

Vue Integration

Plugin Setup

typescript
import { createApp } from "vue";
import { featureFlagsPlugin } from "better-auth-feature-flags/vue";

const app = createApp(App);
app.use(featureFlagsPlugin, {
  client: authClient,
});

Composition API

vue
<script setup>
import { useFeatureFlag, useFeatureFlags } from "better-auth-feature-flags/vue";

const isDarkMode = useFeatureFlag("dark-mode", false);
const flags = useFeatureFlags();

// Reactive computed
const showNewUI = computed(() => flags.value["new-dashboard"]);
</script>

<template>
  <div :class="{ dark: isDarkMode }">
    <NewDashboard v-if="showNewUI" />
    <OldDashboard v-else />
  </div>
</template>

Feature Directive

vue
<template>
  <!-- Show/hide based on flag -->
  <div v-feature="'new-feature'">
    This is only visible when new-feature is enabled
  </div>

  <!-- With fallback -->
  <div v-feature:else="'beta-feature'">
    <BetaFeature v-feature />
    <ComingSoon v-else />
  </div>
</template>

Next.js Integration

App Router

Server Component

tsx
// app/page.tsx
import { auth } from "@/lib/auth";

export default async function Page() {
  const session = await auth.api.getSession();
  const flags = await auth.api.featureFlags.evaluateAll({
    userId: session?.user?.id,
  });

  return <div>{flags["new-feature"] && <NewFeature />}</div>;
}

Client Component

tsx
// app/components/interactive.tsx
"use client";

import { useFeatureFlag } from "better-auth-feature-flags/react";

export function InteractiveComponent() {
  const isEnabled = useFeatureFlag("interactive-feature");

  return isEnabled ? <NewVersion /> : <OldVersion />;
}

Streaming with Suspense

tsx
// app/dashboard/page.tsx
import { Suspense } from "react";
import { FeatureFlags } from "./feature-flags";

export default function Dashboard() {
  return (
    <Suspense fallback={<Loading />}>
      <FeatureFlags>
        <DashboardContent />
      </FeatureFlags>
    </Suspense>
  );
}

Pages Router

getServerSideProps

tsx
// pages/index.tsx
import { auth } from "@/lib/auth";

export async function getServerSideProps(ctx) {
  const session = await auth.api.getSession(ctx.req);
  const flags = await auth.api.featureFlags.evaluateAll({
    userId: session?.user?.id,
    context: { headers: ctx.req.headers },
  });

  return {
    props: { flags },
  };
}

export default function Page({ flags }) {
  return flags["new-feature"] ? <NewFeature /> : <OldFeature />;
}

getStaticProps

tsx
// pages/marketing.tsx
export async function getStaticProps() {
  // Evaluate flags without user context
  const flags = await auth.api.featureFlags.evaluateAll({
    attributes: { page: "marketing" },
  });

  return {
    props: { flags },
    revalidate: 60, // Revalidate every minute
  };
}

Middleware Integration

typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { auth } from "@/lib/auth";

export async function middleware(request: NextRequest) {
  const session = await auth.api.getSession(request);
  const flags = await auth.api.featureFlags.evaluateAll({
    userId: session?.user?.id,
  });

  // Add flags to headers
  const response = NextResponse.next();
  response.headers.set("x-feature-flags", JSON.stringify(flags));

  // Or redirect based on flag
  if (!flags["maintenance-mode"]) {
    return NextResponse.redirect(new URL("/maintenance", request.url));
  }

  return response;
}

Advanced Patterns

Prefetching Flags

Prefetch flags for better performance:

typescript
// Prefetch on app load
await authClient.featureFlags.prefetch(["critical-flag-1", "critical-flag-2"]);

// Prefetch on route change
router.beforeEach(async (to) => {
  if (to.name === "dashboard") {
    await authClient.featureFlags.prefetch(["dashboard-features"]);
  }
});

Local Overrides

Production Safety

Overrides are automatically disabled in production environments. The SDK detects production through:

  • NODE_ENV === 'production'
  • Non-localhost host names
  • Build-time environment variables

Override flags for testing:

typescript
// ✅ Safe: Automatic production detection
authClient.featureFlags.setOverride("new-feature", true);
// Returns false in production, true in development

// ✅ Safe: Conditional override
if (process.env.NODE_ENV === "development") {
  authClient.featureFlags.setOverride("new-feature", true);
  authClient.featureFlags.setOverride("variant-test", {
    key: "variant-b",
    value: { color: "green" },
  });
}

// Clear overrides
authClient.featureFlags.clearOverrides();

// Configure override behavior
const client = featureFlagsClient({
  overrides: {
    ttl: 600000, // 10 minutes
    persist: false, // Don't save to localStorage
  },
});

Context Providers

Add custom context for evaluation:

typescript
// Set global context
authClient.featureFlags.setContext({
  device: "mobile",
  browser: "chrome",
  version: "1.2.3",
  attributes: {
    page: "checkout",
    cartValue: 99.99,
  },
});

// Context is automatically included in all evaluations
const isEnabled = await authClient.featureFlags.isEnabled("feature");

Error Boundaries

Handle feature flag errors gracefully:

tsx
import { FeatureFlagErrorBoundary } from "better-auth-feature-flags/react";

function App() {
  return (
    <FeatureFlagErrorBoundary
      fallback={<DefaultExperience />}
      onError={(error) => {
        // Log to error tracking
        console.error("Feature flag error:", error);
      }}
    >
      <FeatureGatedContent />
    </FeatureFlagErrorBoundary>
  );
}

TypeScript Support

Type-Safe Flags

typescript
// Define your flag types
interface MyFlags {
  "dark-mode": boolean;
  "api-version": number;
  "theme-config": {
    primaryColor: string;
    layout: "grid" | "list";
  };
}

// Create typed client
const client = createAuthClient<MyFlags>({
  plugins: [featureFlagsClient()],
});

// Now fully typed
const isDark = await client.featureFlags.isEnabled("dark-mode");
//    ^? boolean

const config = await client.featureFlags.getValue("theme-config");
//    ^? { primaryColor: string; layout: "grid" | "list" }

Typed Hooks

tsx
// Type your hooks with generics
interface ThemeConfig {
  primaryColor: string;
  layout: "grid" | "list";
}

const isDarkMode = useFeatureFlag("dark-mode", false);
const config = useFeatureFlagValue<ThemeConfig>("theme-config", {
  primaryColor: "blue",
  layout: "grid",
});

// Values are properly typed
if (config.layout === "grid") {
  // TypeScript knows config.layout is "grid" | "list"
}

Performance Optimization

Caching Strategy

typescript
featureFlagsClient({
  cache: {
    enabled: true,
    ttl: 60000, // 1 minute
    storage: "localStorage", // Persist across sessions

    // Cache key strategy
    keyPrefix: "ff_",
    version: "v1", // Bust cache on version change

    // Selective caching
    include: ["static-flag"], // Only cache these
    exclude: ["dynamic-flag"], // Never cache these
  },
});

Batch Requests

typescript
// Instead of multiple requests
const flag1 = await client.featureFlags.isEnabled("flag1");
const flag2 = await client.featureFlags.isEnabled("flag2");
const flag3 = await client.featureFlags.isEnabled("flag3");

// Use batch evaluation
const flags = await client.featureFlags.evaluateBatch([
  "flag1",
  "flag2",
  "flag3",
]);

Lazy Loading

typescript
// Lazy load flags when needed
const LazyFeature = lazy(async () => {
  const flags = await client.featureFlags.getAllFlags();
  return flags["new-feature"] ? import("./NewFeature") : import("./OldFeature");
});

Testing

Mock Client

typescript
import { createMockClient } from "better-auth-feature-flags/testing";

const mockClient = createMockClient({
  flags: {
    "test-feature": true,
    "variant-test": {
      key: "variant-a",
      value: { color: "red" }
    }
  }
});

// Use in tests
describe("Feature", () => {
  it("shows new UI when enabled", () => {
    render(
      <FeatureFlagsProvider client={mockClient}>
        <Component />
      </FeatureFlagsProvider>
    );

    expect(screen.getByText("New UI")).toBeInTheDocument();
  });
});

Testing Utilities

typescript
import { mockFeatureFlag, clearMocks } from "better-auth-feature-flags/testing";

beforeEach(() => {
  mockFeatureFlag("test-feature", true);
});

afterEach(() => {
  clearMocks();
});

Debugging

Debug Mode

typescript
featureFlagsClient({
  debug: true, // Enable debug logging

  onEvaluation: (flag, result) => {
    console.log(`Flag ${flag} evaluated to:`, result);
  },
});

DevTools Extension

typescript
// Enable DevTools integration
if (process.env.NODE_ENV === "development") {
  window.__FEATURE_FLAGS_DEVTOOLS__ = {
    client: authClient,
    flags: await authClient.featureFlags.getAllFlags(),
  };
}

Console Helpers

javascript
// In browser console
featureFlags.getAll(); // List all flags
featureFlags.enable("flag-key"); // Enable flag locally
featureFlags.disable("flag-key"); // Disable flag locally
featureFlags.reset(); // Reset to server values

Migration Guide

From LaunchDarkly

typescript
// LaunchDarkly client
const ldValue = ldClient.variation("flag-key", false);

// Better Auth equivalent
const value = await authClient.featureFlags.isEnabled("flag-key", false);

From Unleash

typescript
// Unleash client
const isEnabled = unleash.isEnabled("flag-key");

// Better Auth equivalent
const isEnabled = await authClient.featureFlags.isEnabled("flag-key");

From Split.io

typescript
// Split client
const treatment = splitClient.getTreatment("flag-key");

// Better Auth equivalent
const variant = await authClient.featureFlags.getVariant("flag-key");

Security Best Practices

Critical Security Guidelines

Feature flags can control access to sensitive features. Follow these security practices to prevent unauthorized access.

Override Security

  1. Never Enable Production Overrides - Keep allowInProduction: false (default)
  2. Use Expiration - Overrides auto-expire after 1 hour by default
  3. Avoid Persistence - Don't persist overrides to localStorage in production
  4. Environment Detection - SDK automatically detects and blocks production overrides
  5. Audit Override Usage - Monitor when overrides are used in development
typescript
// ❌ DANGEROUS: Never do this
featureFlagsClient({
  overrides: {
    allowInProduction: true, // Security vulnerability!
    persist: true, // Persists debug state!
  },
});

// ✅ SAFE: Default configuration
featureFlagsClient({
  // Overrides automatically disabled in production
  // No persistence by default
  // 1-hour expiration by default
});

Context Data Protection

See the Context Security section for PII protection details.

Best Practices

Client SDK Best Practices

  1. Cache Appropriately - Use caching to reduce API calls
  2. Set Defaults - Always provide default values
  3. Handle Errors - Gracefully handle network failures
  4. Batch Requests - Evaluate multiple flags together
  5. Use TypeScript - Leverage type safety for flags
  6. Prefetch Critical Flags - Load important flags early
  7. Monitor Performance - Track evaluation latency
  8. Test Thoroughly - Use mock client for testing
  9. Use Smart Polling - Enable polling with appropriate intervals
  10. Session Management - Cache automatically handles session changes
  11. Secure Overrides - Never enable overrides in production
  12. Protect Context Data - Use sanitization to prevent PII leakage :::

Browser Support

The client SDK supports:

  • Chrome 90+
  • Firefox 88+
  • Safari 14+
  • Edge 90+
  • Opera 76+

For older browsers, use polyfills:

html
<!-- Polyfill for older browsers -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=Promise,fetch"></script>

Bundle Size

Minimal impact on bundle size:

PackageSize (minified + gzipped)
Core client~3KB
React integration~2KB
Vue integration~2KB
Full bundle~5KB

Support