Skip to content

Working with Users#

Storyteller personalises content, tracking, and follow state per end user. The Flutter SDK mirrors the native capabilities exposed by the iOS and Android libraries.

Associate a user during initialisation#

Provide an externalId when calling Storyteller.initialize. This identifier usually maps to your own user record.

final result = await Storyteller.initialize(
  'YOUR_API_KEY',
  externalId: currentUser.id,
);

If you also need to configure tracking behavior for privacy compliance, pass eventTrackingOptions during initialization. See Privacy and Tracking for details.

The Showcase StorytellerService.initialize persists the API key and externalId, then reuses them on relaunch—mirror that pattern if you need automatic reconnection.

Update custom attributes#

Use key/value attributes to pass additional segmentation information into Storyteller. Attributes are persisted natively and automatically applied to subsequent sessions.

await Storyteller.setCustomAttribute('subscription-tier', 'gold');
await Storyteller.setCustomAttribute('favorite-team', 'city-fc');

final attributes = await Storyteller.customAttributes();
debugPrint('Current attributes: $attributes');

await Storyteller.removeCustomAttribute('favorite-team');

To replace the full attribute map in one Flutter bridge operation, use setCustomAttributes. An empty map clears all attributes.

await Storyteller.setCustomAttributes({
  'subscription-tier': 'gold',
  'favorite-team': 'city-fc',
});

iOS forwards this to its native batch API. Android 11.6.3 exposes only per-attribute primitives, so the Flutter bridge removes the prior keys and sets the replacement values synchronously within the same method call. If an Android replacement fails, the bridge restores the prior map when possible and throws a PlatformException with code CUSTOM_ATTRIBUTES_ERROR.

Toggle personalization controls the same way the Showcase AttributeService._addValue calls setCustomAttribute, setLocale, or addFollowedCategory depending on the attribute type.

Handle locale changes#

If your app allows users to switch language independently from the device, inform Storyteller by overriding the locale:

await Storyteller.setLocale('fr-FR');

// Clear the override and return locale selection to the native SDK.
await Storyteller.setLocale(null);

Follow categories explicitly#

Manipulate follow state in response to profile changes, onboarding, or saved preferences:

await Storyteller.addFollowedCategories(['travel', 'music']);

final isSportsFollowed = await Storyteller.isCategoryFollowed('sports');
if (!isSportsFollowed) {
  await Storyteller.addFollowedCategory('sports');
}

await Storyteller.removeFollowedCategory('travel');
final followed = await Storyteller.followedCategories();

You can also remove several categories at once or replace the whole set:

await Storyteller.removeFollowedCategories(['travel', 'music']);
await Storyteller.setFollowedCategories(['sports', 'news']);

setFollowedCategories waits for native category resolution. If some IDs are unknown, the native SDK applies the subset it can resolve. If that request fails, the Future throws and the previous followed-category state is kept.