Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Theme
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Create API Key
Add Docs
Storyly SDK
https://github.com/netvent/storyly-mobile
Admin
Storyly SDK is a cross-platform mobile and web integration framework that enables developers to
...
Tokens:
18,764
Snippets:
140
Trust Score:
7.3
Update:
1 month ago
Context
Skills
Chat
Benchmark
88
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Storyly SDK Storyly SDK is a cross-platform mobile and web integration framework that enables developers to embed vertical story experiences and interactive content into their applications. The SDK provides native implementations for Android (Java/Kotlin), iOS (Swift/Objective-C), React Native, Flutter, Web, and Xamarin platforms, allowing apps to display Instagram-like stories with rich interactive components including polls, quizzes, product catalogs, ratings, and e-commerce integrations. The SDK supports multiple content types including traditional story bars, vertical feeds, and moments (user-generated content). It offers extensive customization options for styling story groups, handling user interactions, managing product catalogs with shopping cart functionality, and tracking analytics events. The SDK communicates with Storyly's backend services using a unique `storylyId` token to fetch and display story content configured through the Storyly Dashboard. ## Basic Integration - Android (Kotlin) Initialize StorylyView with your instance token to display story groups in your Android application. ```kotlin import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.appsamurai.storyly.StorylyInit import com.appsamurai.storyly.StorylyView class BasicActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Initialize via XML-defined view val storylyView = findViewById<StorylyView>(R.id.storyly_view) storylyView.storylyInit = StorylyInit("YOUR_STORYLY_INSTANCE_TOKEN") // Or create programmatically val storylyViewProgrammatic = StorylyView(this) storylyViewProgrammatic.storylyInit = StorylyInit("YOUR_STORYLY_INSTANCE_TOKEN") binding.storylyViewHolder.addView(storylyViewProgrammatic) } } ``` ## Basic Integration - iOS (Swift) Initialize StorylyView with your instance token and set the rootViewController for proper modal presentation. ```swift import UIKit import Storyly class BasicViewController: UIViewController { @IBOutlet weak var storylyView: StorylyView! override func viewDidLoad() { super.viewDidLoad() // Initialize via Storyboard/XIB storylyView.storylyInit = StorylyInit(storylyId: "YOUR_STORYLY_INSTANCE_TOKEN") storylyView.rootViewController = self // Or create programmatically with Auto Layout let storylyViewProgrammatic = StorylyView() storylyViewProgrammatic.translatesAutoresizingMaskIntoConstraints = false storylyViewProgrammatic.storylyInit = StorylyInit(storylyId: "YOUR_STORYLY_INSTANCE_TOKEN") storylyViewProgrammatic.rootViewController = self view.addSubview(storylyViewProgrammatic) NSLayoutConstraint.activate([ storylyViewProgrammatic.leadingAnchor.constraint(equalTo: view.leadingAnchor), storylyViewProgrammatic.trailingAnchor.constraint(equalTo: view.trailingAnchor), storylyViewProgrammatic.topAnchor.constraint(equalTo: storylyView.bottomAnchor, constant: 10), storylyViewProgrammatic.heightAnchor.constraint(equalToConstant: 120) ]) } } ``` ## Basic Integration - React Native Use the Storyly component with event handlers to display and interact with stories in React Native applications. ```javascript import React from 'react'; import { SafeAreaView, View, StyleSheet } from 'react-native'; import { Storyly } from 'storyly-react-native'; const App = () => { return ( <SafeAreaView style={styles.container}> <View style={styles.storylyContainer}> <Storyly style={styles.storyly} storylyId="YOUR_STORYLY_INSTANCE_TOKEN" storyGroupSize="small" onLoad={(event) => { console.log('Stories loaded:', event.storyGroupList.length); }} onFail={(event) => { console.log('Load failed:', event.errorMessage); }} onStoryOpen={() => { console.log('Story opened'); }} onStoryClose={() => { console.log('Story closed'); }} onPress={(event) => { console.log('Story pressed:', event.story.title); }} onUserInteracted={(event) => { console.log('User interacted with:', event.storyComponent.type); }} /> </View> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { flex: 1 }, storylyContainer: { height: 100, marginTop: 10 }, storyly: { height: '100%' } }); export default App; ``` ## Basic Integration - Flutter Create a StorylyView widget with platform-specific parameters and callback handlers. ```dart import 'package:flutter/material.dart'; import 'package:storyly_flutter/storyly_flutter.dart'; class StorylyDemo extends StatefulWidget { @override _StorylyDemoState createState() => _StorylyDemoState(); } class _StorylyDemoState extends State<StorylyDemo> { late StorylyViewController storylyViewController; void onStorylyViewCreated(StorylyViewController controller) { storylyViewController = controller; } @override Widget build(BuildContext context) { return Scaffold( body: Column( children: [ Container( height: 120, child: StorylyView( onStorylyViewCreated: onStorylyViewCreated, androidParam: StorylyParam() ..storylyId = 'YOUR_STORYLY_INSTANCE_TOKEN' ..storyGroupSize = 'large', iosParam: StorylyParam() ..storylyId = 'YOUR_STORYLY_INSTANCE_TOKEN' ..storyGroupSize = 'large', storylyLoaded: (storyGroups, dataSource) { debugPrint('Loaded ${storyGroups.length} story groups'); }, storylyLoadFailed: (errorMessage) { debugPrint('Load failed: $errorMessage'); }, storylyEvent: (event, storyGroup, story, storyComponent) { debugPrint('Event: $event'); }, storylyActionClicked: (story) { debugPrint('Action clicked: ${story.actionUrl}'); }, storylyUserInteracted: (storyGroup, story, storyComponent) { debugPrint('User interacted: ${storyComponent?.type}'); }, ), ), ], ), ); } } ``` ## Event Handling - Android (Java) Implement StorylyListener interface to handle all story events including load, fail, show, dismiss, and user interactions. ```java import com.appsamurai.storyly.*; import com.appsamurai.storyly.analytics.StorylyEvent; public class EventHandlingActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_event_handling); StorylyView storylyView = findViewById(R.id.storyly_view); storylyView.setStorylyInit(new StorylyInit("YOUR_STORYLY_INSTANCE_TOKEN")); storylyView.setStorylyListener(new StorylyListener() { @Override public void storylyLoaded(@NonNull StorylyView storylyView, @NonNull List<StoryGroup> storyGroupList, @NonNull StorylyDataSource dataSource) { // Handle stories loaded Log.d("Storyly", "Loaded " + storyGroupList.size() + " groups"); } @Override public void storylyLoadFailed(@NonNull StorylyView storylyView, @NonNull String errorMessage) { Log.e("Storyly", "Load failed: " + errorMessage); } @Override public void storylyStoryShown(@NonNull StorylyView storylyView) { // Story modal opened } @Override public void storylyStoryShowFailed(@NonNull StorylyView storylyView, @NonNull String errorMessage) { Log.e("Storyly", "Show failed: " + errorMessage); } @Override public void storylyStoryDismissed(@NonNull StorylyView storylyView) { // Story modal closed } @Override public void storylyActionClicked(@NonNull StorylyView storylyView, @NonNull Story story) { // Handle CTA button or swipe-up action String actionUrl = story.getMedia().getActionUrl(); // Open URL or handle custom action } @Override public void storylyUserInteracted(@NonNull StorylyView storylyView, @NonNull StoryGroup storyGroup, @NonNull Story story, @NonNull StoryComponent storyComponent) { // Handle interactive component responses (quiz, poll, etc.) Log.d("Storyly", "Interacted with: " + storyComponent.getType()); } @Override public void storylyEvent(@NonNull StorylyView storylyView, @NonNull StorylyEvent storylyEvent, @Nullable StoryGroup storyGroup, @Nullable Story story, @Nullable StoryComponent storyComponent) { // Track analytics events } }); } } ``` ## Custom Theming - iOS (Swift) Customize story group appearance including colors, borders, and icon styling. ```swift import UIKit import Storyly class CustomThemeViewController: UIViewController { @IBOutlet weak var storylyView: StorylyView! override func viewDidLoad() { super.viewDidLoad() storylyView.storylyInit = StorylyInit(storylyId: "YOUR_STORYLY_INSTANCE_TOKEN") storylyView.rootViewController = self // Customize story group text color storylyView.storyGroupTextColor = UIColor(red: 240/255, green: 57/255, blue: 50/255, alpha: 1.0) // Customize icon background color storylyView.storyGroupIconBackgroundColor = UIColor(red: 76/255, green: 175/255, blue: 80/255, alpha: 1.0) // Customize border colors for seen story groups (gradient) storylyView.storyGroupIconBorderColorSeen = [ UIColor(red: 197/255, green: 172/255, blue: 165/255, alpha: 1.0), UIColor.black ] // Customize border colors for unseen story groups (gradient) storylyView.storyGroupIconBorderColorNotSeen = [ UIColor(red: 251/255, green: 50/255, blue: 0, alpha: 1.0), UIColor(red: 255/255, green: 235/255, blue: 59/255, alpha: 1.0) ] // Customize story header icon border storylyView.storyItemIconBorderColor = [ UIColor(red: 251/255, green: 50/255, blue: 0, alpha: 1.0), UIColor(red: 255/255, green: 235/255, blue: 59/255, alpha: 1.0) ] // Customize progress bar colors (gradient) storylyView.storylyItemProgressBarColor = [ UIColor(red: 251/255, green: 50/255, blue: 0, alpha: 1.0), UIColor(red: 255/255, green: 235/255, blue: 59/255, alpha: 1.0) ] } } ``` ## Custom Theming - React Native Configure story group appearance with styling props for size, colors, layout, and typography. ```javascript import React, { useRef } from 'react'; import { View, StyleSheet } from 'react-native'; import { Storyly } from 'storyly-react-native'; const CustomThemeStoryly = () => { const storylyRef = useRef(null); return ( <View style={styles.container}> <Storyly ref={storylyRef} style={styles.storyly} storylyId="YOUR_STORYLY_INSTANCE_TOKEN" // Story Group Size storyGroupSize="custom" storyGroupIconWidth={80} storyGroupIconHeight={80} storyGroupIconCornerRadius={40} // Story Group Text storyGroupTextIsVisible={true} storyGroupTextSize={12} storyGroupTextLines={2} storyGroupTextColorSeen="#808080" storyGroupTextColorNotSeen="#000000" // Border Colors (gradient arrays) storyGroupIconBorderColorSeen={['#C5ACA5', '#000000']} storyGroupIconBorderColorNotSeen={['#FB3200', '#FFEB3B']} storyGroupIconBackgroundColor="#4CAF50" // Story Group List Layout storyGroupListOrientation="horizontal" storyGroupListSections={1} storyGroupListHorizontalEdgePadding={8} storyGroupListHorizontalPaddingBetweenItems={8} // Story Item Styling storyItemIconBorderColor={['#FB3200', '#FFEB3B']} storyItemProgressBarColor={['#FB3200', '#FFEB3B']} storyItemTextColor="#FFFFFF" // Header Visibility storyHeaderIconIsVisible={true} storyHeaderTextIsVisible={true} storyHeaderCloseButtonIsVisible={true} // Animation storyGroupAnimation="border-rotation" // Layout Direction storylyLayoutDirection="ltr" storylyLocale="en-US" /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1 }, storyly: { height: 120 } }); export default CustomThemeStoryly; ``` ## Controller Methods - React Native Use ref methods to programmatically control story playback, navigation, and data management. ```javascript import React, { useRef } from 'react'; import { View, Button, StyleSheet } from 'react-native'; import { Storyly } from 'storyly-react-native'; const StorylyController = () => { const storylyRef = useRef(null); // Refresh stories from network const handleRefresh = () => { storylyRef.current?.refresh(); }; // Open specific story by deep link URI const openStoryByUri = () => { storylyRef.current?.openStory('storyly://story/abc123'); }; // Open specific story by IDs const openStoryById = () => { storylyRef.current?.openStoryWithId( 'story-group-id', // storyGroupId 'story-id', // storyId (optional) 'default' // playMode (optional) ); }; // Control playback const pauseStory = () => storylyRef.current?.pauseStory(); const resumeStory = () => storylyRef.current?.resumeStory(); const closeStory = () => storylyRef.current?.closeStory(); return ( <View style={styles.container}> <Storyly ref={storylyRef} style={styles.storyly} storylyId="YOUR_STORYLY_INSTANCE_TOKEN" onLoad={({ storyGroupList }) => { console.log(`Loaded ${storyGroupList.length} groups`); }} /> <Button title="Refresh" onPress={handleRefresh} /> <Button title="Open by URI" onPress={openStoryByUri} /> <Button title="Open by ID" onPress={openStoryById} /> <Button title="Pause" onPress={pauseStory} /> <Button title="Resume" onPress={resumeStory} /> <Button title="Close" onPress={closeStory} /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1 }, storyly: { height: 120 } }); export default StorylyController; ``` ## Controller Methods - Flutter Use StorylyViewController to programmatically control stories after the view is created. ```dart import 'package:flutter/material.dart'; import 'package:storyly_flutter/storyly_flutter.dart'; class StorylyControllerDemo extends StatefulWidget { @override _StorylyControllerDemoState createState() => _StorylyControllerDemoState(); } class _StorylyControllerDemoState extends State<StorylyControllerDemo> { StorylyViewController? _controller; void _onStorylyViewCreated(StorylyViewController controller) { _controller = controller; } @override Widget build(BuildContext context) { return Scaffold( body: Column( children: [ Container( height: 120, child: StorylyView( onStorylyViewCreated: _onStorylyViewCreated, androidParam: StorylyParam() ..storylyId = 'YOUR_STORYLY_INSTANCE_TOKEN', iosParam: StorylyParam() ..storylyId = 'YOUR_STORYLY_INSTANCE_TOKEN', ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton( onPressed: () => _controller?.refresh(), child: Text('Refresh'), ), ElevatedButton( onPressed: () => _controller?.openStory('group-id', 'story-id'), child: Text('Open Story'), ), ElevatedButton( onPressed: () => _controller?.openStoryUri('storyly://story/abc'), child: Text('Open URI'), ), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton( onPressed: () => _controller?.pauseStory(), child: Text('Pause'), ), ElevatedButton( onPressed: () => _controller?.resumeStory(), child: Text('Resume'), ), ElevatedButton( onPressed: () => _controller?.closeStory(), child: Text('Close'), ), ], ), ], ), ); } } ``` ## Product Integration & Shopping Cart - React Native Handle product hydration, cart updates, and wishlist functionality for shoppable stories. ```javascript import React, { useRef } from 'react'; import { View, StyleSheet } from 'react-native'; import { Storyly } from 'storyly-react-native'; const ShoppableStoryly = () => { const storylyRef = useRef(null); // Handle product hydration requests const handleProductHydration = (event) => { const { products } = event; // Fetch product data from your backend const hydratedProducts = products.map(({ productId, productGroupId }) => ({ productId, productGroupId, title: 'Product Name', desc: 'Product description', price: 99.99, salesPrice: 79.99, currency: 'USD', imageUrls: ['https://example.com/product.jpg'], url: 'https://example.com/product', variants: [ { name: 'Size', value: 'M', key: 'size' }, { name: 'Color', value: 'Blue', key: 'color' } ], ctaText: 'Add to Cart' })); storylyRef.current?.hydrateProducts(hydratedProducts); }; // Handle cart update requests const handleCartUpdate = async (event) => { const { cart, change, responseId } = event; try { // Update cart in your backend const updatedCart = await updateCartAPI(cart, change); // Approve the change with updated cart state storylyRef.current?.approveCartChange(responseId, { items: updatedCart.items.map(item => ({ item: item.product, quantity: item.quantity, totalPrice: item.totalPrice })), totalPrice: updatedCart.totalPrice, oldTotalPrice: updatedCart.oldTotalPrice, currency: 'USD' }); } catch (error) { // Reject the change with error message storylyRef.current?.rejectCartChange(responseId, error.message); } }; // Handle wishlist updates const handleWishlistUpdate = async (event) => { const { item, responseId } = event; try { await toggleWishlistAPI(item.productId); storylyRef.current?.approveWishlistChange(responseId, { ...item, wishlist: !item.wishlist }); } catch (error) { storylyRef.current?.rejectWishlistChange(responseId, error.message); } }; return ( <View style={styles.container}> <Storyly ref={storylyRef} style={styles.storyly} storylyId="YOUR_STORYLY_INSTANCE_TOKEN" storyCartIsEnabled={true} storyFallbackIsEnabled={true} onProductHydration={handleProductHydration} onCartUpdate={handleCartUpdate} onWishlistUpdate={handleWishlistUpdate} onProductEvent={(event) => { console.log('Product event:', event.event); }} /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1 }, storyly: { height: 120 } }); export default ShoppableStoryly; ``` ## Vertical Feed - React Native Display TikTok-style vertical video feeds with the VerticalFeedBar component. ```javascript import React, { useRef } from 'react'; import { View, StyleSheet } from 'react-native'; import { VerticalFeedBar } from 'storyly-react-native'; const VerticalFeedDemo = () => { const feedRef = useRef(null); return ( <View style={styles.container}> <VerticalFeedBar ref={feedRef} style={styles.feed} storylyId="YOUR_STORYLY_INSTANCE_TOKEN" // Segmentation storylySegments={['segment1', 'segment2']} storylyUserProperty={{ userId: 'user123', plan: 'premium' }} // Group Styling verticalFeedGroupIconHeight={200} verticalFeedGroupIconCornerRadius={12} verticalFeedGroupTextIsVisible={true} verticalFeedGroupTextSize={14} verticalFeedGroupTextColor="#000000" verticalFeedTypeIndicatorIsVisible={true} verticalFeedGroupOrder="bySeenState" // List Layout verticalFeedGroupListSections={2} verticalFeedGroupListHorizontalEdgePadding={16} verticalFeedGroupListHorizontalPaddingBetweenItems={8} // Feed Item Styling verticalFeedItemTitleVisibility={true} verticalFeedItemProgressBarVisibility={true} verticalFeedItemCloseButtonIsVisible={true} verticalFeedItemShareButtonIsVisible={true} verticalFeedItemLikeButtonIsVisible={true} verticalFeedItemProgressBarColor={['#FF0000', '#FFFF00']} // Product Config verticalFeedFallbackIsEnabled={true} verticalFeedCartIsEnabled={true} // Event Handlers onLoad={({ feedGroupList, dataSource }) => { console.log(`Loaded ${feedGroupList.length} feed groups`); }} onFail={(errorMessage) => { console.log('Feed load failed:', errorMessage); }} onVerticalFeedOpen={() => { console.log('Feed opened'); }} onVerticalFeedClose={() => { console.log('Feed closed'); }} onPress={({ feedItem }) => { console.log('Feed item pressed:', feedItem.title); }} onUserInteracted={({ story, storyGroup, storyComponent }) => { console.log('User interacted:', storyComponent.type); }} /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1 }, feed: { flex: 1 } }); export default VerticalFeedDemo; ``` ## Storyly Moments - React Native Enable user-generated content creation and viewing with Storyly Moments. ```javascript import React, { useEffect } from 'react'; import { View, Button, StyleSheet } from 'react-native'; import StorylyMoments, { StorylyMomentsUserPayload } from 'storyly-moments-react-native'; const MomentsDemo = () => { useEffect(() => { // Initialize with encrypted user payload initializeMoments(); // Set up event listeners const subscription = StorylyMoments.addEventListener( 'storylyMomentsEvent', (event) => { console.log('Moments event:', event.eventName); } ); StorylyMoments.addEventListener('onUserStoriesLoaded', (event) => { console.log('User stories loaded:', event.storyGroup); }); StorylyMoments.addEventListener('onUserStoriesLoadFailed', (event) => { console.log('Load failed:', event.errorMessage); }); StorylyMoments.addEventListener('onOpenCreateStory', (event) => { console.log('Create story opened, direct upload:', event.isDirectMediaUploaded); }); StorylyMoments.addEventListener('onUserActionClicked', (event) => { console.log('Action clicked:', event.stories); }); return () => { StorylyMoments.removeAllListeners(); }; }, []); const initializeMoments = async () => { const userPayload = new StorylyMomentsUserPayload(); userPayload.id = 'user123'; userPayload.username = 'John Doe'; userPayload.avatarUrl = 'https://example.com/avatar.jpg'; userPayload.followings = ['user456', 'user789']; userPayload.creatorTags = ['influencer', 'verified']; userPayload.consumerTags = ['premium']; userPayload.expirationTime = Date.now() + 3600000; // 1 hour // Encrypt user payload const encryptedPayload = await StorylyMoments.encryptUserPayload( userPayload, 'YOUR_SECRET_KEY', 'YOUR_INITIALIZATION_VECTOR' ); // Initialize Moments StorylyMoments.initialize('YOUR_MOMENTS_TOKEN', encryptedPayload); }; return ( <View style={styles.container}> <Button title="View My Stories" onPress={() => StorylyMoments.openUserStories()} /> <Button title="Create Story" onPress={() => StorylyMoments.openStoryCreator()} /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', padding: 20 } }); export default MomentsDemo; ``` ## Ad Monetization - React Native Integrate Google AdMob ads into your Storyly stories for monetization. ```javascript import React, { useRef, useEffect } from 'react'; import { View, StyleSheet } from 'react-native'; import { Storyly } from 'storyly-react-native'; import { setStorylyAdViewProvider } from 'storyly-monetization-react-native'; const MonetizedStoryly = () => { const storylyRef = useRef(null); useEffect(() => { // Configure ad provider after component mounts if (storylyRef.current) { setStorylyAdViewProvider(storylyRef.current, { adMobAdUnitId: 'ca-app-pub-xxxxx/yyyyy', adMobAdExtras: new Map([ ['npa', '1'], // Non-personalized ads ['rdp', '1'] // Restrict data processing ]) }); } }, []); return ( <View style={styles.container}> <Storyly ref={storylyRef} style={styles.storyly} storylyId="YOUR_STORYLY_INSTANCE_TOKEN" onLoad={({ storyGroupList }) => { console.log('Stories with ads loaded'); }} /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1 }, storyly: { height: 120 } }); export default MonetizedStoryly; ``` ## Storyly Placement - React Native Use the Placement SDK to embed multiple widget types (StoryBar, Banner, VideoFeed, SwipeCard) via a provider system. ```javascript import React, { useRef } from 'react'; import { View, StyleSheet } from 'react-native'; import { StorylyPlacement, StorylyPlacementProvider } from 'storyly-placement-react-native'; const PlacementDemo = () => { const placementRef = useRef(null); // Create a provider with your placement configuration const provider = new StorylyPlacementProvider({ placementId: 'YOUR_PLACEMENT_ID', userId: 'user123', userProperties: { tier: 'premium' } }); const handleWidgetReady = (event) => { const { widget } = event; console.log('Widget ready:', widget.viewId, widget.type); // Get widget controller for programmatic control const controller = placementRef.current?.getWidget(widget); // Control widget based on type if (widget.type === 'storyBar') { controller?.refresh(); } else if (widget.type === 'videoFeed') { controller?.play(); } }; const handleCartUpdate = async (event) => { const { responseId, cart, change } = event; try { // Process cart update await processCartUpdate(cart, change); placementRef.current?.approveCartChange(responseId); } catch (error) { placementRef.current?.rejectCartChange(responseId, error.message); } }; return ( <View style={styles.container}> <StorylyPlacement ref={placementRef} style={styles.placement} provider={provider} onWidgetReady={handleWidgetReady} onActionClicked={(event) => { console.log('Action clicked:', event.actionUrl); }} onEvent={(event) => { console.log('Placement event:', event.event); }} onFail={(event) => { console.log('Placement failed:', event.errorMessage); }} onProductEvent={(event) => { console.log('Product event:', event.event); }} onUpdateCart={handleCartUpdate} onUpdateWishlist={async (event) => { const { responseId, item } = event; try { await toggleWishlist(item); placementRef.current?.approveWishlistChange(responseId); } catch (error) { placementRef.current?.rejectWishlistChange(responseId, error.message); } }} /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1 }, placement: { flex: 1 } }); export default PlacementDemo; ``` ## Web SDK Integration Integrate Storyly stories into web applications using the JavaScript SDK loaded via CDN. ```html <!DOCTYPE html> <html> <head> <title>Storyly Web Demo</title> <script src="https://web-story.storyly.io/sdk/4.10.5/storyly-web.js"></script> </head> <body> <div id="storyly-container"></div> <script> // Initialize Storyly const storyly = new Storyly({ token: 'YOUR_STORYLY_INSTANCE_TOKEN', container: '#storyly-container', // Segmentation segments: ['segment1', 'segment2'], userProperty: { userId: 'user123', plan: 'premium' }, customParameter: 'analytics-param', // Locale locale: 'en-US', direction: 'ltr', // Layout Configuration layout: 'bar', // 'bar' | 'grid' props: { // Story Group Styling storyGroupSize: 'large', storyGroupBorderRadius: 50, storyGroupTextVisibility: true, storyGroupTextSize: 12, storyGroupTextColor: '#000000', // Border Colors storyGroupBorderColorSeen: ['#C5ACA5', '#000000'], storyGroupBorderColorNotSeen: ['#FB3200', '#FFEB3B'], // Scroll Indicator scrollIndicator: true, scrollIndicatorBorderWidth: 2 }, // Event Handlers events: { loaded: (storyGroups) => { console.log('Stories loaded:', storyGroups.length); }, noStoryGroup: () => { console.log('No stories available'); }, storyOpened: (storyGroup, story) => { console.log('Story opened:', story.title); }, storyClosed: () => { console.log('Story closed'); }, storyViewed: (storyGroup, story) => { console.log('Story viewed:', story.id); }, actionClicked: (storyGroup, story, actionUrl, customPayload) => { console.log('Action clicked:', actionUrl); // Handle CTA click if (actionUrl) { window.open(actionUrl, '_blank'); } }, userInteracted: (storyGroup, story, component) => { console.log('User interacted:', component.type); } } }); // Programmatic Control function refreshStories() { storyly.refresh(); } function openStory(groupId, storyId) { storyly.openStory(groupId, storyId); } function setLanguage(lang) { storyly.setLang(lang); } function setSegments(segments) { storyly.setSegments(segments); } function setUserProperties(props) { storyly.setProperties(props); } // Manual layout update (for dynamic containers) function updateLayout() { storyly.reLayout(); } </script> </body> </html> ``` ## Segmentation and User Properties Configure user segmentation and personalization to show targeted story content. ```javascript // React Native Example import { Storyly } from 'storyly-react-native'; const SegmentedStoryly = ({ userId, userTier, userInterests }) => { return ( <Storyly style={{ height: 120 }} storylyId="YOUR_STORYLY_INSTANCE_TOKEN" // User segmentation - show content for matching segments storylySegments={[ userTier, // e.g., 'premium', 'free' ...userInterests, // e.g., ['sports', 'tech', 'fashion'] 'all-users' ]} // User properties - personalize story content storylyUserProperty={{ userId: userId, name: 'John Doe', email: 'john@example.com', tier: userTier, locale: 'en-US', registrationDate: '2024-01-15', customField: 'custom-value' }} // Custom parameter for analytics customParameter="campaign-winter-2024" // Test mode to see all story groups storylyTestMode={false} onLoad={({ storyGroupList, dataSource }) => { console.log(`Loaded ${storyGroupList.length} targeted groups`); console.log('Data source:', dataSource); }} /> ); }; ``` The Storyly SDK is designed for mobile-first engagement, enabling brands to create immersive story experiences similar to Instagram and TikTok. Common use cases include product showcases, promotional campaigns, onboarding tutorials, user engagement features, and shoppable content. The SDK integrates seamlessly with e-commerce platforms through product catalogs, shopping carts, and wishlist functionality. Integration follows a provider-consumer pattern where the Storyly backend serves as the content management system while native SDK components render the stories. Developers configure their content through the Storyly Dashboard and connect their apps using unique instance tokens. The SDK supports real-time updates, deep linking for story sharing, analytics event tracking, and A/B testing through segmentation. For complex deployments, the Placement SDK offers a unified approach to managing multiple widget types across different screen placements.