Why We Built a Unified Error Monitoring Solution for Kotlin Multiplatform

Why We Built a Unified Error Monitoring Solution for Kotlin Multiplatform
Jason Morris
  June 25, 2025

The new bugsnag-kmp SDK is a unified error monitoring solution for Kotlin Multiplatform (KMP) projects, enabling developers to track and monitor errors across Android, iOS, and web platforms from a single codebase. 

The new SDK works seamlessly on Android, iOS, and web browsers Native Integration, each one linking directly with our existing platform SDKs: 

  1. Android: Integrates with the official BugSnag Android SDK
  2. iOS: Uses the BugSnag Cocoa SDK (via XCFramework) through Kotlin/Native interop 
  3. Web: Leverages @bugsnag/browser JavaScript package using the IR compiler and ES modules 

Multiplatform, not just cross-platform 

Unlike cross-platform tools such as Flutter and ReactNative, which seek to abstract the platform behind a deep tooling stack, Kotlin Multiplatform brings a fundamentally different approach to sharing code between platforms. Typical cross-platform tooling strongly separates the “common” codebase from the platform, but Kotlin Multiplatform  embraces the platform differences to create native-first experiences while using Kotlin as a common language for shared code. 

This approach is very different to any we’ve worked with before, and while it opens up opportunities for deep integrations into each targeted platform, it also brought some new challenges when building an error-monitoring SDK. 

Kotlin-first API design 

In an ideal world we would have perfect alignment between all of our platform SDKs, and they would have a Kotlin -friendly API surface, but this is unfortunately not the case. Objective-C, for example, has very limited support for generics. So we can’t simply write an idealized set of expect declarations and then typealias them to the platform types. 

We explored several options when approaching this problem: 

Write a brand new Kotlin first SDK 

While this would allow for a reasonable level of code reuse within the new SDK and would provide an ideal API surface, it would also sacrifice nearly all the benefits of Kotlin Multiplatform. Effectively we would be building a “cross-platform” SDK, rather than a true “multi-platform” SDK and blocking users from truly leveraging our native SDKs via Kotlin. 

Minimal expect / typealias with extensions 

In this scenario, we explored using minimal expect declarations that would perfectly map onto the underlying native SDK types and functions (where possible) and then creating extension functions and extension properties that could handle the platform-specific mappings. This sounds good in theory, but in reality, ends up with empty expect class definitions with all of the functionality exposed via extensions: 

expect class Error
expect var Error.errorClass: String?
expect var Error.errorMessage: String?
expect val Error.stackTrace: List<Stackframe> 

While this pattern is nice, because it means that the native and common code directly share types, it requires that the common code import the extension functions. It can be confusing in platform-specific code, when many of the extensions will shadow the platform functions and properties. 

It also has an added disadvantage, since the extensions typically get imported individually, making it difficult to extend or alter the API structure in future without breaking compatibility. 

Idiomatic Kotlin API 

We therefore decided to implement bugsnag-kmp as a common wrapper layer, presenting a unified, Kotlin-first API that feels natural across all platforms. Instead of empty classes and extensions, or a completely new API, we adopted a more flexible and pragmatic approach: wrapper classes and objects, using value classes where possible. This provides an intuitive API surface for common sources with minimal (if any) runtime overhead, while also not blocking access to the native types and functionality in the platform-specific sources. 

This approach provides the flexibility to use platform-specific features while maintaining a consistent cross-platform development experience. The wrapper layer handles the complexity of platform differences while still allowing escape hatches to the native implementations when needed. 

Trying out the new SDK  

Installation 

Add bugsnag-kmp to your build.gradle.kts file: 

dependencies {
    implementation("com.bugsnag:bugsnag-kmp:+")

In your Xcode project add bugsnag-cocoa as a Swift Package Manager (recommended) or other project dependency – see our online docs for instructions. bugsnag-kmp does not use Gradle Cocoapods support and includes the Objective-C bindings / interop. This means that while you don’t need to add a pod("Bugsnag") to your Gradle project, you do still need to manually link to the native framework so that the Kotlin interop has something to bind to. 

Basic configuration 

As with the native platform SDKs, bugsnag-kmp should be initialized as early as possible in your application lifecycle. On Android this is typically in the onCreate method of your Application class, while on iOS this is typically in the didFinishLaunchingWithOptions method of your AppDelegate class, or in the init method of your App class. Since we have Kotlin Multiplatform support, you can share most of your configuration code: 

// BugsnagStartup.kt
import com.bugsnag.kmp.Bugsnag
import com.bugsnag.kmp.Configuration

fun startBugsnag(configuration: Configuration) { // common configuration here 
    configuration.addMetadata("App", "multiplatform", true)
    Bugsnag.start(configuration)
}

Bugsnag.start should still be called in a platform-specific location: 

// don't accidentally import 'com.bugsnag.android.Configuration'
// if you want common configuration import com.bugsnag.kmp.Configuration

class MyApp : Application() { 
    override fun onCreate() {
        super.onCreate() 
        startBugsnag(Configuration(this, "your-api-key"))
    }
}
@main
struct iOSApp: App {
    init() { 
        BugsnagStartupKt.startBugsnag(configuration: 
            Bugsnag_kmpConfiguration(apiKey: "your-api-key"))
    }
}

Beta release 

We hope you’ll find that bugsnag-kmp provides an elegant, Kotlin-first interface to the battle-hardened BugSnag SDKs you know and love. 

It is currently in its pre-release stage and we welcome developers with an interest in KMP to try it out. Let us know what you think of our approach and help form the direction we go in.  

Get involved via the open-source repo on GitHub: https://github.com/bugsnag/bugsnag-kotlin-multiplatform

You Might Also Like