Add and use device mode integrations in the Android (Kotlin) and iOS (Swift) SDKs.
9 minute read
This guide shows you how to add device mode integrations in your Android (Kotlin) and iOS (Swift) apps to send events directly to third-party destinations. It covers how to:
To add a standard integration, instantiate the integration plugin and add it to your Analytics instance.
Android (Kotlin)
importcom.rudderstack.sdk.kotlin.android.plugins.devicemode.IntegrationPluginimportcom.rudderstack.integration.kotlin.firebase.FirebaseIntegration// Get reference to your integration plugin
valintegrationPlugin:IntegrationPlugin=FirebaseIntegration()// Add integration plugin to your analytics instance
analytics.add(integrationPlugin)
importcom.rudderstack.sdk.kotlin.android.plugins.devicemode.IntegrationPlugin;importcom.rudderstack.integration.kotlin.firebase.FirebaseIntegration;// Get reference to your integration plugin
IntegrationPluginintegrationPlugin=newFirebaseIntegration();// Add integration plugin to your analytics instance
analytics.add(integrationPlugin);
iOS (Swift)
importRudderStackAnalyticsimportRudderIntegrationFirebase// Get reference to your integration pluginletintegrationPlugin:IntegrationPlugin=FirebaseIntegration()// Add integration plugin to your analytics instanceanalytics.add(integrationPlugin)
@importRudderStackAnalytics;@importRudderIntegrationFirebase;// Get reference to your integration plugin
RSSFirebaseIntegration*integration=[RSSFirebaseIntegrationnew];// Add integration plugin to your analytics instance
[self.analyticsaddPlugin:integration];
Tip:
Always add the integrationPlugin to the Analytics instance before invoking any APIs on the integrationPlugin. Calling them earlier may lead to unexpected behavior.
Access destination instances
Device mode integrations provide the following APIs to interact with destination instances:
onDestinationReady(): Register a callback for destination initialization
getDestinationInstance(): Access the destination instance directly
onDestinationReady() lets you perform actions only after the destination is successfully initialized. This is useful for fetching IDs or initializing resources that depend on the destination being ready.
Tip:
Use the onDestinationReady() API for critical startup logic that requires the destination to be ready before proceeding.
Android (Kotlin)
importcom.rudderstack.sdk.kotlin.android.plugins.devicemode.IntegrationPluginimportcom.rudderstack.sdk.kotlin.core.internals.utils.Resultimportcom.rudderstack.integration.kotlin.firebase.FirebaseIntegrationvalintegrationPlugin:IntegrationPlugin=FirebaseIntegration()analytics.add(integrationPlugin)integrationPlugin.onDestinationReady{instance,result->if(resultisResult.Success){// Destination is ready
println("Destination is ready: $instance")}else{// Handle initialization failure
println("Destination initialization failed: ${(result as Result.Failure).exception.message}")}}
importcom.rudderstack.sdk.kotlin.android.plugins.devicemode.IntegrationPlugin;importcom.rudderstack.sdk.kotlin.core.internals.utils.Result;importcom.rudderstack.integration.kotlin.firebase.FirebaseIntegration;IntegrationPluginintegrationPlugin=newFirebaseIntegration();analytics.add(integrationPlugin);integrationPlugin.onDestinationReady((instance,result)->{if(resultinstanceofResult.Success){// Destination is ready
System.out.println("Destination is ready: "+instance);}elseif(resultinstanceofResult.Failure){// Handle initialization failure
Exceptionexception=((Result.Failure)result).getException();System.out.println("Destination initialization failed: "+exception.getMessage());}});
iOS (Swift)
importRudderStackAnalyticsimportRudderIntegrationFirebaseletintegrationPlugin:IntegrationPlugin=FirebaseIntegration()analytics.add(integrationPlugin)integrationPlugin.onDestinationReady{instance,resultinswitchresult{case.success:// Destination is ready, safe to send eventsprint("Destination is ready: \(String(describing:instance))")case.failure(leterror):// Handle initialization failureprint("Destination initialization failed: \(error.localizedDescription)")}}
@importRudderStackAnalytics;@importRudderIntegrationFirebase;RSSFirebaseIntegration*integration=[RSSFirebaseIntegrationnew];[self.analyticsaddPlugin:integration];[self.analyticsonDestinationReadyForKey:integration.key:^(id_Nullabledestination,NSError*_Nullableerror){if(error==nil){// Destination is ready, safe to send events
[RSSLoggerAnalyticsdebug:[NSStringstringWithFormat:@"Destination is ready: %@",destination]];}else{// Handle initialization failure
[RSSLoggerAnalyticsdebug:[NSStringstringWithFormat:@"Destination initialization failed: %@",[errorlocalizedDescription]]];}}];
Example: Fetch Firebase app instance ID
importcom.google.firebase.analytics.FirebaseAnalyticsintegrationPlugin.onDestinationReady{instance,result->if(resultisResult.Success&&instanceisFirebaseAnalytics){instance.appInstanceId.addOnSuccessListener{appInstanceId->appInstanceId?.let{// Send to your backend for analytics correlation
sendToBackend(it)}}}}
importFirebaseAnalyticsintegrationPlugin.onDestinationReady{instance,resultinswitchresult{case.success:ifletfirebaseAnalytics=instanceas?Analytics{firebaseAnalytics.appInstanceID{appInstanceIDinifletappInstanceID=appInstanceID{// Send to your backend for analytics correlationsendToBackend(appInstanceID)}}}case.failure(_):break}}
getDestinationInstance()
getDestinationInstance() lets you directly access the destination SDK instance for advanced use cases like interacting with destination-specific APIs or features.
Tip:
Use the getDestinationInstance() API for on-demand access later in the app lifecycle when you need to interact with the destination instance immediately.
Android (Kotlin)
valdestination=integrationPlugin.getDestinationInstance()if(destination!=null){// Interact with the destination SDK
println("Destination instance: $destination")// Cast to specific destination type if needed
// val firebaseDestination = destination as? FirebaseAnalytics
}
Objectdestination=integrationPlugin.getDestinationInstance();if(destination!=null){// Interact with the destination SDK
System.out.println("Destination instance: "+destination);// Cast to specific destination type if needed
// FirebaseAnalytics firebaseDestination = (FirebaseAnalytics) destination;
}
iOS (Swift)
ifletdestination=integrationPlugin.getDestinationInstance(){// Interact with the destination SDKprint("Destination instance: \(destination)")// Cast to specific destination type if needed// let firebaseDestination = destination as? Analytics}
iddestination=[integrationgetDestinationInstance];if(destination!=nil){// Interact with the destination SDK
[RSSLoggerAnalyticsdebug:[NSStringstringWithFormat:@"Destination instance: %@",destination]];// Cast to specific destination type if needed
// Analytics *firebaseDestination = [integration getDestinationInstance];
}
Example 1: Set default event parameters for Firebase
importandroid.os.Bundleimportcom.google.firebase.analytics.FirebaseAnalyticsvalfirebaseAnalytics=firebaseIntegration.getDestinationInstance()as?FirebaseAnalyticsfirebaseAnalytics?.let{valparameters=Bundle().apply{putString("app_variant","premium")putString("global_source","mobile_app")}// This ensures these parameters are included in every subsequent Firebase event
it.setDefaultEventParameters(parameters)}
importFirebaseAnalyticsifletfirebaseAnalytics=firebaseIntegration.getDestinationInstance()as?Analytics{// Set the global parametersletparameters:[String:Any]=["app_variant":"premium","global_source":"mobile_app"]// This ensures these parameters are included in every subsequent Firebase eventAnalytics.setDefaultEventParameters(parameters)}
Example 2: Use Braze content cards
importcom.braze.Brazevalbraze=brazeIntegration.getDestinationInstance()as?Brazebraze?.let{// Manually request a refresh of Content Cards
it.requestContentCardsRefresh()// Access current content cards for custom UI rendering
valunreadCount=it.getContentCardCount()println("User has $unreadCount unread Content Cards.")}?:run{println("Braze integration is not yet ready or is disabled.")}
importRudderIntegrationBrazeimportBrazeKitifletbraze=brazeIntegration.getDestinationInstance()as?Braze{// Manually request a refresh of Content Cardsbraze.contentCards.requestRefresh()// Access current content cards for custom UI renderingletunreadCount=braze.contentCards.cards.filter{!$0.viewed}.countprint("User has \(unreadCount) unread Content Cards.")}else{print("Braze integration is not yet ready or is disabled.")}
Add custom plugins to integrations
Device mode integrations support adding custom plugins to modify or enhance event data before sending it to a specific destination. This enables filtering, transformation, or enrichment of events for specific destinations.
With this feature, you can:
Add different plugins to different device mode integrations (for example, Firebase, Amplitude, Braze)
Apply unique transformations, filtering, or enrichment logic for each destination
Handle destination-specific requirements without affecting other integrations
importcom.rudderstack.sdk.kotlin.android.plugins.devicemode.IntegrationPluginimportcom.rudderstack.sdk.kotlin.core.internals.plugins.Pluginimportcom.rudderstack.sdk.kotlin.core.internals.plugins.EventPluginimportcom.rudderstack.sdk.kotlin.core.internals.models.Eventimportcom.rudderstack.sdk.kotlin.core.internals.models.TrackEventimportcom.rudderstack.integration.kotlin.firebase.FirebaseIntegration// Step 1: Create a custom plugin
classMyCustomPlugin:EventPlugin{overridevalpluginType=Plugin.PluginType.PreProcessoverridesuspendfunintercept(event:Event):Event?{// Filter out debug events
returnif(eventisTrackEvent&&event.event.startsWith("Debug_")){null// This will drop the event
}else{event// Pass through all other events
}}}// Step 2: Add integration to analytics
valintegrationPlugin:IntegrationPlugin=FirebaseIntegration()analytics.add(integrationPlugin)// Step 3: Add custom plugin to integration
valcustomPlugin=MyCustomPlugin()integrationPlugin.add(customPlugin)
importandroidx.annotation.NonNull;importandroidx.annotation.Nullable;importcom.rudderstack.sdk.kotlin.core.Analytics;importcom.rudderstack.sdk.kotlin.core.internals.models.Event;importcom.rudderstack.sdk.kotlin.core.internals.models.TrackEvent;importcom.rudderstack.sdk.kotlin.core.internals.plugins.Plugin;importkotlin.coroutines.Continuation;// Step 1: Create a custom plugin
publicclassMyCustomPluginimplementsPlugin{privateAnalyticsanalytics;privatestaticfinalPlugin.PluginTypepluginType=Plugin.PluginType.PreProcess;@OverridepublicvoidsetAnalytics(@NonNullAnalyticsanalytics){this.analytics=analytics;}@Overridepublicvoidsetup(@NonNullAnalyticsanalytics){this.analytics=analytics;}@Nullable@OverridepublicObjectintercept(@NonNullEventevent,@NonNullContinuation<?superEvent>$completion){// Filter out debug events
if(eventinstanceofTrackEvent&&((TrackEvent)event).getEvent().startsWith("Debug_")){returnnull;// This will drop the event
}returnevent;// Pass through all other events
}@NonNull@OverridepublicAnalyticsgetAnalytics(){returnthis.analytics;}@NonNull@OverridepublicPlugin.PluginTypegetPluginType(){returnpluginType;}@Overridepublicvoidteardown(){// Clean up resources if needed
}}// Step 2: Add integration to analytics
IntegrationPluginintegrationPlugin=newFirebaseIntegration();analytics.add(integrationPlugin);// Step 3: Add custom plugin to integration
MyCustomPlugincustomPlugin=newMyCustomPlugin();integrationPlugin.add(customPlugin);
iOS (Swift)
importRudderStackAnalyticsimportRudderIntegrationFirebase// Step 1: Create a custom pluginclassMyCustomPlugin:EventPlugin{varpluginType:PluginType=.preProcessvaranalytics:Analytics?funcintercept(event:anyEvent)->(anyEvent)?{// Filter out debug eventsiflettrackEvent=eventas?TrackEvent,leteventName=trackEvent.event,eventName.hasPrefix("Debug_"){returnnil// This will drop the event}returnevent// Pass through all other events}}// Step 2: Add integration to analyticsletintegrationPlugin:IntegrationPlugin=FirebaseIntegration()analytics.add(plugin:integrationPlugin)// Step 3: Add custom plugin to integrationletcustomPlugin=MyCustomPlugin()integrationPlugin.add(plugin:customPlugin)
// Step 1: Create custom plugin
// MyCustomPlugin.h
#import <Foundation/Foundation.h>
@importRudderStackAnalytics;@interfaceMyCustomPlugin : NSObject<RSSEventPlugin>@end// MyCustomPlugin.m
@implementationMyCustomPlugin@synthesizepluginType;-(instancetype)init{self=[superinit];if(self){}returnself;}-(enumRSSPluginType)pluginType{returnRSSPluginTypeTerminal;}-(RSSEvent*)intercept:(RSSEvent*)event{if([eventisKindOfClass:[RSSTrackEventclass]]){RSSTrackEvent*trackEvent=(RSSTrackEvent*)event;NSString*eventName=trackEvent.eventName;if([eventNamehasPrefix:@"Debug_"]){returnnil;// This will drop the event
}}returnevent;// Pass through all other events
}@end// Step 2: Add integration to analytics:
// Import Firebase integration at the top of the file
@importRudderIntegrationFirebase;// Adding firebase integration to analytics instance
RSSFirebaseIntegration*integrationPlugin=[RSSFirebaseIntegrationnew];[self.analyticsaddPlugin:integrationPlugin];// Step 3: Add custom plugin to integration:
MyCustomPlugin*customPlugin=[MyCustomPluginnew];[self.analyticsaddPlugin:customPlugindestinationKey:integrationPlugin.key];
Troubleshooting
Issue
Solution
Integration not initializing
Ensure you have added the integration plugin to the Analytics instance before calling any integration APIs
Check that the destination is enabled in your RudderStack dashboard
Verify that required dependencies are properly installed
Destination instance is null
The destination may not be initialized yet. Use onDestinationReady() to wait for initialization
Check if the integration failed to initialize by handling the failure case in onDestinationReady()
Ensure the integration is properly configured in your RudderStack dashboard
Events not reaching destination
Verify the integration is added to your Analytics instance
Check that events are being tracked using the standard RudderStack APIs (track, identify, etc.)
Review destination-specific requirements in the destination’s documentation
This site uses cookies to improve your experience while you navigate through the website. Out of
these
cookies, the cookies that are categorized as necessary are stored on your browser as they are as
essential
for the working of basic functionalities of the website. We also use third-party cookies that
help
us
analyze and understand how you use this website. These cookies will be stored in your browser
only
with
your
consent. You also have the option to opt-out of these cookies. But opting out of some of these
cookies
may
have an effect on your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. This
category only includes cookies that ensures basic functionalities and security
features of the website. These cookies do not store any personal information.
This site uses cookies to improve your experience. If you want to
learn more about cookies and why we use them, visit our cookie
policy. We'll assume you're ok with this, but you can opt-out if you wish Cookie Settings.