How to Create Custom Integrations

Create custom device mode integrations for unsupported destinations in the Android (Kotlin) and iOS (Swift) SDKs.

This guide shows you how to create custom integration plugins to send events to third-party destinations that are not officially supported by RudderStack.

Overview

Custom integrations let you wrap any third-party SDK and send event data directly to destinations that are not officially supported. You can extend RudderStack’s capabilities by integrating any third-party SDK into your mobile apps.

Key differences from standard integrations

AspectStandard integrationsCustom integrations
MaintenanceMaintained by RudderStackMaintained by you
ConfigurationUses dashboard configurationUses hardcoded or custom configuration
Source configurationReceives destination configuration from the RudderStack dashboardReceives an empty configuration object
UpdatesAutomatic (via RudderStack releases)Manual (updates made by the developer)

Implementation guide

The following example creates an integration plugin called MyCustomIntegrationPlugin that wraps a destination called CustomDestinationSdk. All APIs are implemented for demonstration purposes. Apart from the mandatory APIs (key, create, and getDestinationInstance), you can implement other APIs as needed.

Android (Kotlin)

This section shows you how to create a custom integration plugin for Android (Kotlin).

1. Create the integration plugin

kotlin
import com.rudderstack.sdk.kotlin.android.plugins.devicemode.IntegrationPlugin
import com.rudderstack.sdk.kotlin.core.internals.logger.LoggerAnalytics
import com.rudderstack.sdk.kotlin.core.internals.models.*
import kotlinx.serialization.json.JsonObject

/**
 * Custom integration plugin for CustomDestination
 */
class MyCustomIntegrationPlugin : IntegrationPlugin() {

    /**
     * The instance of the destination SDK which is wrapped with this integration plugin.
     * Here, `CustomDestinationSdk` is a sample third party SDK class which you can wrap with an integration plugin.
     */
    private var destinationSdk: CustomDestinationSdk? = null

    // Unique identifier for your integration
    override val key: String = "CustomDestination"

    /**
     * Initialize your destination SDK
     * Note: destinationConfig will be empty for custom integrations
     */
    override fun create(destinationConfig: JsonObject) {
        // Initialize with your custom configuration
        val apiKey = "your-api-key"
        val serverUrl = "https://api.yourdestination.com"
        destinationSdk = CustomDestinationSdk.initialize(apiKey, serverUrl)
        LoggerAnalytics.debug("MyCustomDestination: SDK initialized")
    }

    /**
     * Return the destination SDK instance
     */
    override fun getDestinationInstance(): Any? {
        return destinationSdk
    }

    /**
     * Implement event methods to forward events to your destination SDK.
     * Call the appropriate methods on your destination SDK instance.
     */
    override fun track(payload: TrackEvent) {
        destinationSdk?.trackEvent(
            eventName = payload.event,
            properties = payload.properties.toMap()
        )
    }

    override fun identify(payload: IdentifyEvent) {
        destinationSdk?.identifyUser(
            userId = payload.userId,
            traits = payload.context["traits"]?.jsonObject?.toMap() ?: emptyMap()
        )
    }

    override fun screen(payload: ScreenEvent) {
        destinationSdk?.trackScreen(
            screenName = payload.screenName,
            properties = payload.properties.toMap()
        )
    }

    override fun group(payload: GroupEvent) {
        destinationSdk?.setGroup(
            groupId = payload.groupId,
            traits = payload.traits.toMap()
        )
    }

    override fun alias(payload: AliasEvent) {
        destinationSdk?.aliasUser(
            newUserId = payload.userId,
            previousUserId = payload.previousId
        )
    }

    /**
     * Optional: Implement flush method if supported by your destination SDK
     */
    override fun flush() {
        destinationSdk?.flush()
        LoggerAnalytics.debug("MyCustomDestination: Flushed events")
    }

    /**
     * Optional: Implement reset method if supported by your destination SDK
     */
    override fun reset() {
        destinationSdk?.reset()
        LoggerAnalytics.debug("MyCustomDestination: Reset user data")
    }
}

2. Add the plugin to Analytics

kotlin
import com.rudderstack.sdk.kotlin.android.Analytics
import com.rudderstack.sdk.kotlin.android.Configuration

class MyApp : Application() {
    
    lateinit var analytics: Analytics
    
    override fun onCreate() {
        super.onCreate()
        
        // Initialize Analytics
        analytics = Analytics(
            configuration = Configuration(
                writeKey = "your-write-key",
                application = this,
                dataPlaneUrl = "your-data-plane-url"
            )
        )
        
        // Create and add your custom integration
        val customIntegration = MyCustomIntegrationPlugin()
        
        // Add the integration to analytics
        analytics.add(customIntegration)
    }
}

iOS (Swift)

This section shows you how to create a custom integration plugin for iOS (Swift).

1. Create the integration plugin

swift
import Foundation
import RudderStackAnalytics

/**
 * Custom integration plugin for MyCustomDestination
 */
class MyCustomIntegrationPlugin: IntegrationPlugin {
    var pluginType: PluginType = .terminal
    var analytics: Analytics?
    var key: String = "MyCustomDestination"
    
    /**
     * The instance of the destination SDK which is wrapped with this integration plugin.
     * Here, `CustomDestinationSdk` is a sample third party SDK class which you can wrap with an integration plugin.
     */
    private var destinationSdk: MyCustomDestinationSdk?
    
    func getDestinationInstance() -> Any? {
        return destinationSdk
    }
    
    /**
     * Initialize your destination SDK
     * Note: destinationConfig will be empty for custom integrations
     */
    func create(destinationConfig: [String: Any]) throws {
        // Initialize with your custom configuration
        let apiKey = "your-api-key"
        let serverUrl = "https://api.yourdestination.com"
        destinationSdk = MyCustomDestinationSdk.initialize(apiKey: apiKey, serverUrl: serverUrl)
        print("MyCustomDestination: SDK initialized")
    }
    
    /**
     * Implement event methods to forward events to your destination SDK.
     * Call the appropriate methods on your destination SDK instance.
     */
    func identify(payload: IdentifyEvent) {
        destinationSdk?.identifyUser(
            userId: payload.userId ?? "",
            traits: payload.traits ?? [:]
        )
    }
    
    func track(payload: TrackEvent) {
        destinationSdk?.trackEvent(
            eventName: payload.event ?? "",
            properties: payload.properties ?? [:]
        )
    }
    
    func screen(payload: ScreenEvent) {
        destinationSdk?.trackScreen(
            screenName: payload.name ?? "",
            properties: payload.properties ?? [:]
        )
    }
    
    func group(payload: GroupEvent) {
        destinationSdk?.setGroup(
            groupId: payload.groupId ?? "",
            traits: payload.traits ?? [:]
        )
    }
    
    func alias(payload: AliasEvent) {
        destinationSdk?.aliasUser(
            newUserId: payload.userId ?? "",
            previousUserId: payload.previousId ?? ""
        )
    }
    
    /**
     * Optional: Implement flush method if supported by your destination SDK
     */
    func flush() {
        destinationSdk?.flush()
        print("MyCustomDestination: Flushed events")
    }
    
    /**
     * Optional: Implement reset method if supported by your destination SDK
     */
    func reset() {
        destinationSdk?.reset()
        print("MyCustomDestination: Reset user data")
    }
}

2. Add the plugin to Analytics

swift
import UIKit
import RudderStackAnalytics

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var analytics: Analytics!
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Initialize Analytics
        let config = Configuration(
            writeKey: "your-write-key",
            dataPlaneUrl: "your-data-plane-url"
        )
        
        analytics = Analytics(configuration: config)
        
        // Create and add your custom integration
        let customIntegration = MyCustomIntegrationPlugin()
        
        // Add the integration to analytics
        analytics.add(plugin: customIntegration)

        return true
    }
}

Important consideration

The pluginType for a custom integration plugin in iOS (Swift) SDK should always be .terminal.

Required and optional methods

This section lists the required and optional methods for custom integration plugins.

Required methods

MethodDescription
keyUnique identifier for your integration
create(destinationConfig)Initializes your destination SDK
getDestinationInstance()Returns the destination SDK instance

Optional methods

MethodDescription
track(payload)Forwards track events to your destination SDK
identify(payload)Forwards identify events to your destination SDK
screen(payload)Forwards screen events to your destination SDK
group(payload)Forwards group events to your destination SDK
alias(payload)Forwards alias events to your destination SDK
flush()Flushes events to your destination SDK (if supported)
reset()Resets user data to your destination SDK (if supported)

Custom integration APIs

Custom integrations support the following device mode integration APIs:

  • onDestinationReady(): Register a callback for when the destination is ready
  • getDestinationInstance(): Access the destination instance directly

See more

Questions? Let's figure it out together.

Join the RudderStack Slack community to connect with other users, customers, and the RudderStack team — or reach out for direct support.