Targeting: Audiences

Audience Targeting with customParameters

Use customParameters to pass key–value pairs at render time so JOIN Studio Audiences can target and personalize content based on your app context (plan, locale, cohort, A/B group, etc.). Parameters are forwarded to the native SDK when the widget fetches its content, and Studio rules can reference these keys to select which stories to deliver.

  • Where available: BubbleWidget via BubbleConfiguration.customParameters, CardWidget via CardConfiguration.customParameters
  • Type: Map<String, String>
  • Default: null (no extra parameters sent)
  • When applied: On widget fetch (initial render and any subsequent refresh)

API surface

  • Bubble
    • BubbleConfiguration.customParameters: Map<String, String>? (default: null)
  • Card
    • CardConfiguration.customParameters: Map<String, String>? (default: null)

Quick start

// Example audience context  
final Map\<String, String> audienceParams = {  
  'plan': 'premium',  
  'locale': 'en_US',  
  'ab_group': 'B',  
  'cohort': '2025-10',  
};

BubbleWidget(  
  alias: 'homepage-stories',  
  configuration: BubbleConfiguration(  
    customParameters: audienceParams,  
  ),  
);

CardWidget(  
  alias: 'recommendations',  
  isGrid: true,  
  configuration: CardConfiguration(  
    customParameters: {  
      'plan': 'free',  
      'locale': 'fr_FR',  
    },  
  ),  
);

Updating parameters at runtime

When your audience context changes (e.g., user logs in, AB bucket changes), update the configuration and refresh the widget.

final bubbleController = BubbleController();

BubbleWidget(
  alias: 'homepage-stories',
  controller: bubbleController,
  configuration: BubbleConfiguration(
    customParameters: {'plan': 'premium', 'locale': 'en_US'},
  ),
  // Ensure the controller attaches before first refresh
  onNativeViewCreated: (_) => bubbleController.refresh(),
);

// Later: change parameters and refresh
Future<void> updateAudience() async {
  // Rebuild the widget with new configuration (setState) OR just refresh if
  // your builder reads the new map.
  setState(() {
    // update your state that provides customParameters in configuration
  });
  await bubbleController.refresh();
}

Tip: If you maintain parameters in state (e.g., a provider), pass them into BubbleConfiguration/CardConfiguration and call controller.refresh() after updates.