featbit

featbit-javascript-client-sdk

3
0
# Install this skill:
npx skills add featbit/featbit-skills --skill "featbit-javascript-client-sdk"

Install specific skill from multi-skill repository

# Description

Expert guidance for integrating FeatBit JavaScript Client SDK in web applications (browser-only). Use when users work with vanilla JavaScript in browsers, need client-side feature flags, or ask about JS client SDK integration.

# SKILL.md


name: featbit-javascript-client-sdk
description: Expert guidance for integrating FeatBit JavaScript Client SDK in web applications (browser-only). Use when users work with vanilla JavaScript in browsers, need client-side feature flags, or ask about JS client SDK integration.
appliesTo:
- "/*.html"
- "
/.js"
- "
/index.js"
- "
*/app.js"


FeatBit JavaScript Client SDK Expert

Expert knowledge for integrating FeatBit JavaScript Client SDK in web browsers.

Source: https://github.com/featbit/featbit-js-client-sdk

⚠️ Important: This is a client-side SDK for single-user browser environments only. Not suitable for Node.js server applications (use @featbit/node-server-sdk instead).

Installation

npm install --save @featbit/js-client-sdk

Prerequisites

Before using, obtain:
- Environment Secret (SDK Key): How to get
- SDK URLs: How to get

Quick Start

import { FbClientBuilder, UserBuilder } from "@featbit/js-client-sdk";

// Create user
const bob = new UserBuilder('a-unique-key-of-user')
    .name('bob')
    .custom('age', '18')
    .custom('country', 'FR')
    .build();

// Setup SDK client with WebSocket streaming
const fbClient = new FbClientBuilder()
    .sdkKey("your_sdk_key")
    .streamingUri('wss://app-eval.featbit.co')
    .eventsUri("https://app-eval.featbit.co")
    .user(bob)
    .build();

(async () => {
  // Wait for initialization
  try {
    await fbClient.waitForInitialization();
  } catch(err) {
    console.log("Failed to initialize SDK:", err);
  }

  // Evaluate feature flag
  const flagKey = "game-runner";
  const isEnabled = await fbClient.boolVariation(flagKey, false);

  console.log(`Feature ${flagKey}: ${isEnabled}`);

  // Switch user
  const alice = new UserBuilder('another-unique-key-of-user')
      .name('alice')
      .custom('country', 'UK')
      .custom('age', 36)
      .build();

  await fbClient.identify(alice);
})();

Building User Context

import { UserBuilder } from "@featbit/js-client-sdk";

// Basic user
const user = new UserBuilder('user-key-123')
    .name('John Doe')
    .build();

// User with custom properties
const userWithProps = new UserBuilder('user-key-456')
    .name('Jane Smith')
    .custom('age', 25)
    .custom('country', 'US')
    .custom('subscription', 'premium')
    .custom('role', 'admin')
    .build();

Client Configuration

const fbClient = new FbClientBuilder()
    .sdkKey("your_sdk_key")
    .streamingUri('wss://app-eval.featbit.co')
    .eventsUri("https://app-eval.featbit.co")
    .user(user)
    .build();

Using HTTP Polling

const fbClient = new FbClientBuilder()
    .sdkKey("your_sdk_key")
    .eventsUri("https://app-eval.featbit.co")
    .pollingUri("https://app-eval.featbit.co")
    .pollingInterval(3000) // 3 seconds
    .user(user)
    .build();

Flag Evaluation

Boolean Flags

const isEnabled = await fbClient.boolVariation('feature-key', false);
if (isEnabled) {
  // Feature is enabled
}

String Flags

const theme = await fbClient.variation('theme-key', 'default');
console.log(`Current theme: ${theme}`);

Numeric Flags

const maxItems = await fbClient.variation('max-items', 10);

JSON Flags

const config = await fbClient.variation('config-key', '{}');
const configObject = JSON.parse(config);

With Evaluation Details

const detail = await fbClient.boolVariationDetail('feature-key', false);
console.log(`Value: ${detail.value}`);
console.log(`Reason: ${detail.reason}`);
console.log(`Kind: ${detail.kind}`);

User Identification & Switching

Identify New User

const newUser = new UserBuilder('new-user-key')
    .name('New User')
    .custom('role', 'viewer')
    .build();

await fbClient.identify(newUser);

Anonymous Users

// Use session ID or generate unique ID
const sessionId = sessionStorage.getItem('sessionId') || crypto.randomUUID();
const anonymousUser = new UserBuilder(sessionId)
    .custom('anonymous', true)
    .build();

Event Tracking

Track Custom Events

// Simple event
fbClient.trackMetric('button-clicked');

// Event with numeric value
fbClient.trackMetric('purchase-completed', 99.99);

// For A/B testing
fbClient.trackMetric('conversion-event');

Flush Events Manually

await fbClient.flush();

Real-Time Flag Updates

Listen for Flag Changes

fbClient.on('ff_update', (changes) => {
  console.log('Flags updated:', changes);

  // Re-evaluate flags
  const isEnabled = fbClient.variation('feature-key', false);
  updateUI(isEnabled);
});

Listen for Specific Flag

fbClient.on('ff_update', (changes) => {
  if (changes.includes('feature-key')) {
    const newValue = fbClient.variation('feature-key', false);
    console.log(`Feature flag updated: ${newValue}`);
  }
});

Complete Web App Example

<!DOCTYPE html>
<html>
<head>
  <title>FeatBit Demo</title>
</head>
<body>
  <div id="app">
    <h1>Feature Flag Demo</h1>
    <div id="feature-content"></div>
    <button id="switch-user">Switch User</button>
  </div>

  <script type="module">
    import { FbClientBuilder, UserBuilder } from '@featbit/js-client-sdk';

    const users = [
      new UserBuilder('user-1').name('Alice').custom('role', 'admin').build(),
      new UserBuilder('user-2').name('Bob').custom('role', 'user').build()
    ];

    let currentUserIndex = 0;

    const fbClient = new FbClientBuilder()
      .sdkKey('your_sdk_key')
      .streamingUri('wss://app-eval.featbit.co')
      .eventsUri('https://app-eval.featbit.co')
      .user(users[0])
      .build();

    async function init() {
      try {
        await fbClient.waitForInitialization();
        updateFeatureDisplay();

        fbClient.on('ff_update', () => {
          updateFeatureDisplay();
        });
      } catch (err) {
        console.error('Failed to initialize:', err);
      }
    }

    function updateFeatureDisplay() {
      const isEnabled = fbClient.variation('new-feature', false);
      const content = document.getElementById('feature-content');

      if (isEnabled) {
        content.innerHTML = '<p>✅ New Feature Enabled</p>';
      } else {
        content.innerHTML = '<p>❌ New Feature Disabled</p>';
      }
    }

    document.getElementById('switch-user').onclick = async () => {
      currentUserIndex = (currentUserIndex + 1) % users.length;
      await fbClient.identify(users[currentUserIndex]);
      updateFeatureDisplay();
    };

    init();
  </script>
</body>
</html>

Configuration Options

const fbClient = new FbClientBuilder()
    // Required
    .sdkKey("your_sdk_key")
    .user(user)

    // Streaming (recommended)
    .streamingUri('wss://app-eval.featbit.co')

    // Or Polling
    .pollingUri('https://app-eval.featbit.co')
    .pollingInterval(3000)

    // Events
    .eventsUri('https://app-eval.featbit.co')

    // Optional
    .startWaitTime(3000) // Wait time for initialization in ms
    .enableDataSync(true) // Enable data synchronization

    .build();

Best Practices

1. Single Client Instance

// ✅ Good: Create once, reuse
const fbClient = createFbClient();

// ❌ Bad: Creating multiple instances
function checkFeature() {
  const client = createFbClient(); // Don't do this
}

2. Wait for Initialization

// ✅ Good: Wait for initialization
await fbClient.waitForInitialization();
const value = fbClient.variation('key', default);

// ❌ Bad: Don't wait
const value = fbClient.variation('key', default); // May return default

3. Error Handling

try {
  await fbClient.waitForInitialization();
  const isEnabled = fbClient.variation('feature', false);
  // Use feature
} catch (error) {
  console.error('SDK initialization failed:', error);
  // Fall back to default behavior
  const isEnabled = false;
}

4. User Context Best Practices

// ✅ Good: Use stable user IDs
const userId = getUserId(); // From auth system
const user = new UserBuilder(userId).build();

// ✅ Good: Add relevant properties for targeting
const user = new UserBuilder(userId)
    .name(userName)
    .custom('subscription', subscription)
    .custom('country', country)
    .build();

// ❌ Bad: Random IDs (user won't get consistent experience)
const user = new UserBuilder(Math.random().toString()).build();

5. Clean Up

// Close client when page unloads
window.addEventListener('beforeunload', async () => {
  await fbClient.close();
});

Common Use Cases

Progressive Rollout

// Enable feature for percentage of users
const isEnabled = await fbClient.boolVariation('new-checkout', false);

if (isEnabled) {
  renderNewCheckout();
} else {
  renderOldCheckout();
}

A/B Testing

const variant = await fbClient.variation('landing-page', 'A');

switch(variant) {
  case 'A':
    renderVariantA();
    break;
  case 'B':
    renderVariantB();
    break;
}

// Track conversion
if (userConverted) {
  fbClient.trackMetric('landing-page-conversion');
}

Feature Toggle

const showBetaFeature = await fbClient.boolVariation('beta-feature', false);

if (showBetaFeature) {
  document.getElementById('beta-section').style.display = 'block';
}

Remote Configuration

const config = await fbClient.variation('app-config', '{}');
const { apiUrl, timeout, retries } = JSON.parse(config);

// Use configuration
fetch(apiUrl, { timeout });

Troubleshooting

SDK Not Initializing

try {
  await fbClient.waitForInitialization();
} catch (err) {
  // Check:
  // 1. SDK key is correct
  // 2. Network connectivity
  // 3. CORS settings
  // 4. WebSocket/HTTP connection
  console.error('Initialization error:', err);
}

Flags Not Updating

// Check event listeners
fbClient.on('ff_update', (changes) => {
  console.log('Update received:', changes);
});

// Check WebSocket connection status
fbClient.on('ready', () => console.log('Connected'));
fbClient.on('error', (err) => console.error('Connection error:', err));

CORS Issues

Ensure FeatBit server allows your origin. Contact your FeatBit administrator to configure CORS settings.

Migration from LaunchDarkly

// LaunchDarkly
const ldClient = LDClient.initialize('sdk-key', user);
const flag = ldClient.variation('flag-key', false);

// FeatBit equivalent
const fbClient = new FbClientBuilder()
    .sdkKey('sdk-key')
    .streamingUri('wss://app-eval.featbit.co')
    .eventsUri('https://app-eval.featbit.co')
    .user(user)
    .build();

await fbClient.waitForInitialization();
const flag = fbClient.variation('flag-key', false);

Additional Resources

  • GitHub: https://github.com/featbit/featbit-js-client-sdk
  • NPM: https://www.npmjs.com/package/@featbit/js-client-sdk
  • Documentation: https://docs.featbit.co/sdk-docs/client-side-sdks/javascript
  • Examples: https://github.com/featbit/featbit-js-client-sdk/tree/main/examples
  • FAQ: https://docs.featbit.co/sdk/faq

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.