Skip to main content
User segments and test cells allow you to deliver personalized search results and recommendations based on user attributes, behavior, and A/B test assignments. These features enable you to tailor the Constructor.io experience for different user cohorts.

Overview

Constructor.io supports two types of user-level customization:
  1. Segments - Named user groups for personalization (e.g., “VIP”, “mobile_user”, “returning_customer”)
  2. Test Cells - A/B test variant assignments (e.g., {"search_algorithm": "variant_b"})
Both are sent with every request to Constructor.io and influence search ranking, recommendations, and analytics.

User Segments

Segments are array of strings that categorize users into groups. Constructor.io uses segments to:
  • Personalize search results and recommendations
  • Filter and boost products for specific user groups
  • Segment analytics and reports
  • Enable targeted merchandising campaigns

Setting Segments

Define segments during client initialization:
import ConstructorIO from '@constructor-io/constructorio-client-javascript';

const constructorClient = new ConstructorIO({
  apiKey: 'YOUR_API_KEY',
  segments: ['VIP', 'mobile_user', 'returning_customer']
});

Common Segment Examples

Differentiate experiences by customer value:
segments: ['VIP']           // Premium customers
segments: ['gold_member']   // Mid-tier customers
segments: ['free_tier']     // Free or trial users
Optimize experiences by device:
segments: ['mobile_user']   // Mobile device users
segments: ['tablet_user']   // Tablet users
segments: ['desktop_user']  // Desktop users
segments: ['ios_app']       // iOS app users
segments: ['android_app']   // Android app users
Target users by behavior patterns:
segments: ['returning_customer']  // Has purchased before
segments: ['high_intent']         // Frequently searches/views
segments: ['cart_abandoner']      // Has items in cart
segments: ['discount_seeker']     // Often uses promo codes
Personalize by location:
segments: ['us_west']      // West coast users
segments: ['europe']       // European users
segments: ['urban']        // Urban areas
segments: ['international']// Non-domestic users
Target specific demographics:
segments: ['mens']         // Male shoppers
segments: ['womens']       // Female shoppers
segments: ['youth']        // Younger demographic
segments: ['seniors']      // Older demographic

Dynamic Segment Assignment

Segments can be determined dynamically based on user data:
function getUserSegments(user) {
  const segments = [];
  
  // Add tier segment
  if (user.lifetimeValue > 10000) {
    segments.push('VIP');
  } else if (user.lifetimeValue > 1000) {
    segments.push('premium');
  }
  
  // Add device segment
  if (user.isMobile) {
    segments.push('mobile_user');
  }
  
  // Add behavioral segment
  if (user.orderCount > 0) {
    segments.push('returning_customer');
  }
  
  // Add geographic segment
  if (user.country !== 'US') {
    segments.push('international');
  }
  
  return segments;
}

const constructorClient = new ConstructorIO({
  apiKey: 'YOUR_API_KEY',
  segments: getUserSegments(currentUser)
});

Updating Segments at Runtime

Change segments for a user session using setClientOptions:
// User signs in - update segments
function onUserLogin(user) {
  constructorClient.setClientOptions({
    userId: user.id,
    segments: getUserSegments(user)
  });
}

// User upgrades to premium - add VIP segment
function onUserUpgrade(user) {
  const currentSegments = getUserSegments(user);
  currentSegments.push('VIP');
  
  constructorClient.setClientOptions({
    segments: currentSegments
  });
}

How Segments Affect Results

When segments are set, Constructor.io includes them in all API requests as the us parameter:
// Request URL will include: ?us=VIP&us=mobile_user&us=returning_customer
await constructorClient.search.getSearchResults('shoes');
You can configure segment-specific behavior in your Constructor.io dashboard:
  • Boost or bury products for specific segments
  • Create segment-specific merchandising rules
  • Filter products by segment availability
  • Analyze performance by segment

Test Cells

Test cells assign users to A/B test variants. Each test cell is a key-value pair where:
  • Key - The experiment name (e.g., "search_algorithm")
  • Value - The variant assigned to the user (e.g., "variant_b")

Setting Test Cells

Define test cells during client initialization:
const constructorClient = new ConstructorIO({
  apiKey: 'YOUR_API_KEY',
  testCells: {
    'search_algorithm': 'variant_b',
    'ui_layout': 'control',
    'recommendation_strategy': 'personalized_v2'
  }
});

Test Cell Validation

The SDK automatically validates test cells using helpers.toValidTestCells(). Invalid entries are filtered out:
// Valid test cells
testCells: {
  'experiment_1': 'variant_a',  // ✓ Valid
  'test_2': 'control'            // ✓ Valid
}

// Invalid test cells (automatically removed)
testCells: {
  'test': null,                  // ✗ Null value
  'test': undefined,             // ✗ Undefined value
  'test': '',                    // ✗ Empty string
  'test': 123                    // ✗ Non-string value (may be coerced)
}

Common Test Cell Examples

Test different ranking algorithms:
testCells: {
  'search_algorithm': 'ml_based',    // Machine learning ranking
  'search_algorithm': 'popularity',  // Popularity-based ranking
  'search_algorithm': 'control'      // Default ranking
}
Test interface variations:
testCells: {
  'search_layout': 'grid_view',        // Grid vs. list layout
  'filter_position': 'sidebar_left',   // Filter placement
  'autocomplete_style': 'dropdown_v2'  // Autocomplete UI
}
Test recommendation approaches:
testCells: {
  'recs_strategy': 'collaborative',    // Collaborative filtering
  'recs_strategy': 'content_based',    // Content-based filtering
  'recs_strategy': 'hybrid'            // Hybrid approach
}
Test merchandising tactics:
testCells: {
  'sponsored_placement': 'top',        // Ad placement
  'promotion_display': 'banner',       // Promotion style
  'badge_visibility': 'visible'        // Product badges
}

Test Cell Assignment

Typically, you’ll use an A/B testing platform to assign variants, then pass them to Constructor.io:
// Using Optimizely
const experimentVariant = window.optimizely.get('state').getVariationMap();

const constructorClient = new ConstructorIO({
  apiKey: 'YOUR_API_KEY',
  testCells: {
    'search_experiment': experimentVariant['search_experiment'] || 'control'
  }
});
// Using custom A/B testing logic
function assignTestCell(userId, experimentName) {
  // Deterministic hash-based assignment
  const hash = simpleHash(userId + experimentName);
  return hash % 2 === 0 ? 'variant_a' : 'variant_b';
}

const constructorClient = new ConstructorIO({
  apiKey: 'YOUR_API_KEY',
  userId: 'user_123',
  testCells: {
    'search_test': assignTestCell('user_123', 'search_test'),
    'recs_test': assignTestCell('user_123', 'recs_test')
  }
});

Updating Test Cells at Runtime

Modify test cell assignments using setClientOptions:
// Update test cell when user is assigned to new experiment
function assignUserToExperiment(experimentName, variant) {
  const currentTestCells = { ...currentUser.testCells };
  currentTestCells[experimentName] = variant;
  
  constructorClient.setClientOptions({
    testCells: currentTestCells
  });
}

assignUserToExperiment('new_search_ui', 'variant_b');

How Test Cells Affect Results

Test cells are sent with every Constructor.io request as ef-{key} parameters:
// Request URL will include: ?ef-search_algorithm=variant_b&ef-ui_layout=control
await constructorClient.search.getSearchResults('shoes');
Use Constructor.io’s dashboard to:
  • Configure experiment-specific ranking rules
  • Analyze experiment performance
  • Compare conversion rates across variants
  • Determine winning variants

Combining Segments and Test Cells

Use both segments and test cells together for advanced personalization:
const constructorClient = new ConstructorIO({
  apiKey: 'YOUR_API_KEY',
  
  // Segments for user categorization
  segments: ['VIP', 'mobile_user', 'returning_customer'],
  
  // Test cells for experiments
  testCells: {
    'search_algorithm': 'variant_b',
    'recommendation_strategy': 'personalized',
    'ui_layout': 'control'
  }
});
This configuration:
  1. Personalizes results for VIP mobile users who are returning customers
  2. Applies experiment variant variant_b for search ranking
  3. Uses personalized recommendation strategy
  4. Shows control UI layout

Best Practices

1. Use Meaningful Segment Names

Choose descriptive, consistent segment names:
// Good - Clear and descriptive
segments: ['VIP', 'mobile_user', 'cart_abandoner']

// Bad - Vague or inconsistent
segments: ['seg1', 'Mobile', 'cart-abandoner']

2. Limit the Number of Segments

Avoid creating too many granular segments:
// Good - 3-5 meaningful segments
segments: ['premium', 'mobile', 'us_west']

// Bad - Too many segments
segments: ['vip', 'gold', 'silver', 'bronze', 'mobile', 'tablet', 
           'desktop', 'ios', 'android', 'us', 'canada', 'returning',
           'new', 'high_intent', 'low_intent'] // Too granular!

3. Keep Test Cell Keys Descriptive

Use experiment names that describe what’s being tested:
// Good - Describes the test
testCells: {
  'search_ranking_algorithm': 'ml_v2',
  'autocomplete_suggestion_count': '10_suggestions'
}

// Bad - Unclear names
testCells: {
  'test1': 'a',
  'exp': 'v2'
}

4. Document Segment and Test Cell Usage

Maintain documentation for your segments and test cells:
/**
 * User Segments:
 * - VIP: Users with lifetime value > $10,000
 * - premium: Users with lifetime value > $1,000
 * - mobile_user: Users on mobile devices
 * - returning_customer: Users with at least one previous order
 * 
 * Active Test Cells:
 * - search_algorithm: Testing ML-based ranking (variant_b) vs. default (control)
 * - recommendation_strategy: Testing personalized recs (personalized) vs. popularity (control)
 */
const constructorClient = new ConstructorIO({
  apiKey: 'YOUR_API_KEY',
  segments: getUserSegments(user),
  testCells: getActiveExperiments(user)
});

5. Update Segments When User State Changes

Ensure segments reflect current user state:
// When user signs in
function onUserLogin(user) {
  constructorClient.setClientOptions({
    userId: user.id,
    segments: getUserSegments(user),
    testCells: getUserTestCells(user)
  });
}

// When user adds item to cart
function onAddToCart() {
  const segments = getUserSegments(currentUser);
  
  if (!segments.includes('cart_active')) {
    segments.push('cart_active');
    constructorClient.setClientOptions({ segments });
  }
}

// When user completes purchase
function onPurchaseComplete() {
  const segments = getUserSegments(currentUser);
  const index = segments.indexOf('cart_active');
  
  if (index > -1) {
    segments.splice(index, 1);
  }
  
  if (!segments.includes('returning_customer')) {
    segments.push('returning_customer');
  }
  
  constructorClient.setClientOptions({ segments });
}

6. Validate Test Cell Values

Ensure test cell values are strings:
// The SDK validates automatically, but be explicit:
function getValidTestCells(experiments) {
  const testCells = {};
  
  Object.keys(experiments).forEach(key => {
    const value = experiments[key];
    
    // Only include valid string values
    if (value && typeof value === 'string') {
      testCells[key] = value;
    }
  });
  
  return testCells;
}

const constructorClient = new ConstructorIO({
  apiKey: 'YOUR_API_KEY',
  testCells: getValidTestCells(userExperiments)
});

Server-Side Usage

Segments and test cells work identically in server-side (Node.js) environments:
// Server-side initialization
const ConstructorIO = require('@constructor-io/constructorio-client-javascript');

function createConstructorClient(req) {
  return new ConstructorIO({
    apiKey: process.env.CONSTRUCTOR_API_KEY,
    clientId: req.session.clientId,
    sessionId: req.session.sessionId,
    userId: req.user?.id,
    segments: getUserSegments(req.user),
    testCells: getUserTestCells(req.user)
  });
}

// Use in request handler
app.get('/search', async (req, res) => {
  const client = createConstructorClient(req);
  const results = await client.search.getSearchResults(req.query.q);
  res.json(results);
});

Analytics and Reporting

Segments and test cells appear in Constructor.io analytics, allowing you to:
  • Compare search performance across segments
  • Measure conversion rates by segment
  • Analyze A/B test results
  • Identify high-performing user cohorts
  • Optimize merchandising by segment
Access segment and test cell analytics in the Constructor.io dashboard under Analytics → Segments and Analytics → Experiments.

Troubleshooting

  1. Verify segments are set during client initialization
  2. Check that sendTrackingEvents: true is enabled
  3. Ensure segment names match those configured in Constructor.io dashboard
  4. Look for segments in request URLs as us parameters
  1. Confirm test cells are configured in Constructor.io dashboard
  2. Check request URLs for ef-{key}={value} parameters
  3. Verify test cell values are strings (not null/undefined)
  4. Ensure experiment is active in Constructor.io
  1. Verify setClientOptions is called with new segments
  2. Check that subsequent requests include updated segments
  3. Ensure you’re not creating a new client instance (reuse the same instance)

Build docs developers (and LLMs) love