Migration Steps
Follow these steps to migrate from the SAP Emarsys SDKs to the SAP Engagement Cloud SDK. Where relevant, the SAP Emarsys SDK's approach is shown for comparison.
1. Installing and Removing Dependencies
- Android
- Kotlin Multiplatform
- iOS
- Web
Install the SAP Engagement Cloud SDK by adding it as a dependency:
// Ensure required repositories in settings.gradle.kts
pluginManagement {
repositories {
google()
mavenCentral()
}
}
// module build.gradle.kts
dependencies {
implementation("com.sap.engagement-cloud:engagement-cloud-sdk-android:<latest-version>")
}
Remove the com.emarsys:android-emarsys-sdk dependency and any related artifact lines.
The SAP Engagement Cloud SDK's FCM and HMS library modules include push messaging service declarations in their AndroidManifest.xml files. These are merged into your app automatically — you can remove any manual *MessagingService or <service> entries from your AndroidManifest.xml. The SDK also ships consumer ProGuard rules in the AAR, so no manual keep rules are needed.
Install the SAP Engagement Cloud SDK by adding it as a dependency:
// module build.gradle.kts
dependencies {
implementation("com.sap.engagement-cloud:engagement-cloud-sdk:<latest-version>")
}
Remove the com.emarsys:android-emarsys-sdk dependency and any related artifact lines.
Install the SAP Engagement Cloud SDK using Swift Package Manager, either using Xcode Add Package or Package.swift:
// Package.swift example
.dependencies = [
.package(url: "https://github.com/emartech/engagement-cloud-sdk.git", from: "<latest-version>")
]
Remove the CocoaPods or Swift Package Manager references to EmarsysSDK and EmarsysNotificationService.
Install the SAP Engagement Cloud SDK using your preferred package manager or script tag.
npm install @sap/engagement-cloud-sdk
Bundle the SAP Engagement Cloud SDK (ESM example) and remove global loader / queue (WebEmarsysSdk) from the Web Push SDK.
import {EngagementCloud} from "@sap/engagement-cloud-sdk";
// No immediate tracking; defer enable until consent.
Remove old script tags, such as this one:
<script src="/web-emarsys-sdk.js" async></script>
If you prefer using a script tag, add the loader script to your page. It automatically downloads and initializes the SDK, collecting events until initialization is complete.
<script src="engagement-cloud-sdk-loader.js"></script>
2. Initializing the SDK
- Android
- Kotlin Multiplatform
- iOS
- Web
On Android, EngagementCloud.initialize() is called automatically. There is no need to call it manually.
class MyApp: Application() {
override fun onCreate() {
super.onCreate()
// Enable tracking once consent is given and the application code is available
EngagementCloud.setup.enable(AndroidEngagementCloudSDKConfig(
applicationCode = "ABCDE-12345",
launchActivityClass = MainActivity::class.java
))
}
}
For Kotlin Multiplatform projects, the SDK initializes automatically on Android. On other KMP targets, initialization is handled by the platform-specific integration.
// Delay tracking until consent / appCode ready
EngagementCloud.setup.enable(SdkConfig(
applicationCode = "ABCDE-12345"
))
On iOS, EngagementCloud.shared.initialize() is called automatically. There is no need to call it manually.
Choose one of the integration approaches below.
Option A: Use EngagementCloudSDKAppDelegate (SwiftUI example)
The SDK initializes itself. You only call enable once the user has given consent and configuration is ready.
@main
struct YourApplication: App {
@UIApplicationDelegateAdaptor private var appDelegate: EngagementCloudSDKAppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Option B: Inherit from EngagementCloudSDKAppDelegate
@UIApplicationMain
class AppDelegate: EngagementCloudSDKAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
super.application(application, didFinishLaunchingWithOptions: launchOptions)
// Your custom startup code here
return true
}
}
Option C: Manual AppDelegate, Including Explicit initialize and enable
Do not forget to register the device token with try? await EngagementCloud.shared.push.registerToken(token: apnsToken) once you have it.
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Task {
try? await EngagementCloud.shared.initialize()
let center = UNUserNotificationCenter.current()
center.delegate = EngagementCloud.shared.push.userNotificationCenterDelegate
try? await EngagementCloud.shared.setup.enable(config: EngagementCloudConfig(
applicationCode: <#String#>
))
try? await EngagementCloud.shared.contact.link(contactFieldValue: <String>)
try? await EngagementCloud.shared.event.track(event: CustomEvent(name: <String>, attributes: <#Dictionary<String, String>>))
}
return true
}
}
The SAP Emarsys SDK for Web initialized immediately using a global instance and started tracking right away:
// SAP Emarsys SDK (simplified)
WebEmarsysSdk({ applicationCode: 'ABCDE-12345' }).init();
// Tracking begins implicitly
The SAP Engagement Cloud SDK separates initialization from tracking:
// Init called automatically at script loading.
// Once user has given consent and configuration is ready
await window.EngagementCloud.setup.enable({
applicationCode: 'ABCDE-12345'
});
Service worker registration and push subscription are now decoupled. Perform them after tracking is enabled and a contact is linked, so that attribution is correct.
3. Identifying Contacts
The SAP Emarsys SDK's setContact, setAuthenticatedContact, and clearContact methods are replaced by link, linkAuthenticated, and unlink in the SAP Engagement Cloud SDK.
- Android
- Kotlin Multiplatform
- iOS
- Web
EngagementCloud.contact.link(contactFieldValue)
EngagementCloud.contact.linkAuthenticated(openIdToken)
EngagementCloud.contact.unlink()
EngagementCloud.contact.link(contactFieldValue)
EngagementCloud.contact.linkAuthenticated(openIdToken)
EngagementCloud.contact.unlink()
try? await EngagementCloud.shared.contact.link(contactFieldValue: <String>)
try? await EngagementCloud.shared.contact.linkAuthenticated(openIdToken: <String>)
try? await EngagementCloud.shared.contact.unlink()
await window.EngagementCloud.contact.link(<contactFieldValue>);
await window.EngagementCloud.contact.linkAuthenticated(<openIdToken>);
await window.EngagementCloud.contact.unlink();
- Linking after
enable()ensures events are associated correctly. - OpenID linking for contact authentication behaves the same as before.
4. Handling Push Tokens
The SAP Emarsys SDK's setPushToken, clearPushToken, and getPushToken methods are replaced by registerToken, clearToken, and getToken in the SAP Engagement Cloud SDK.
- Android
- Kotlin Multiplatform
- iOS
- Web
// In FirebaseMessagingService
override fun onNewToken(token: String) {
EngagementCloud.push.registerToken(token)
}
EngagementCloud.push.clearToken()
// In FirebaseMessagingService
override fun onNewToken(token: String) {
EngagementCloud.push.registerToken(token)
}
EngagementCloud.push.clearToken()
// In AppDelegate didRegisterForRemoteNotifications
let token = deviceToken.map { data in String(format: "%02.2hhx", data) }.joined()
try? await EngagementCloud.shared.push.registerToken(token: token)
try? await EngagementCloud.shared.push.clearToken()
// After obtaining a push subscription, for example via ServiceWorker registration
const subscription = await navigator.serviceWorker.ready.then(r => r.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey }));
const token = extractToken(subscription); // Depends on implementation
await window.EngagementCloud.push.registerToken(token);
// Clear
await window.EngagementCloud.push.clearToken();
If required, retrieve the current token:
- Android
- Kotlin Multiplatform
- iOS
- Web
val token = EngagementCloud.push.getToken().getOrNull()
val token = EngagementCloud.push.getToken().getOrNull()
let token = try? await EngagementCloud.shared.push.getToken()
// Check if token exists
const current = await window.EngagementCloud.push.getToken();
const isSubscribed = !!current;
If a push token exists, the SAP Engagement Cloud SDK derives that a subscription also exists. This approach makes separate wrappers for isSubscribed and subscribe obsolete.
5. Sending Custom Events
The SAP Emarsys SDK's trackCustomEvent method is replaced by constructing a CustomEvent and passing it to EngagementCloud.event.track in the SAP Engagement Cloud SDK.
- Android
- Kotlin Multiplatform
- iOS
- Web
EngagementCloud.event.track(CustomEvent(name, attributes))
EngagementCloud.event.track(CustomEvent(name, attributes))
try? await EngagementCloud.shared.event.track(event: CustomEvent(name: <String>, attributes: Dictionary<String, String>))
await window.EngagementCloud.event.track({ type: 'custom', name: 'eventName', attributes: { key: 'value' } });
6. Controlling In-App Messaging
The pause, resume, and isPaused methods for in-app messaging work the same way in both SDKs.
- Android
- Kotlin Multiplatform
- iOS
- Web
// Identical use for both SDKs, just update dependency
if (!EngagementCloud.inApp.isPaused) {
EngagementCloud.inApp.pause()
}
// Later, when you're ready
EngagementCloud.inApp.resume()
// Identical use for both SDKs, just update dependency
if (!EngagementCloud.inApp.isPaused) {
EngagementCloud.inApp.pause()
}
// Later, when you're ready
EngagementCloud.inApp.resume()
Simply update imports and switch to EngagementCloud.shared. If you need steps carried out in a certain order, for example if you want to pause before presenting a sensitive UI, await the calls in Swift.
try? await EngagementCloud.shared.inApp.resume()
In-app and webchannel integration are not supported on Web.
Inline In-App Callbacks
The SAP Emarsys SDK provided callbacks for inline in-app messages to track lifecycle events. The SAP Engagement Cloud SDK supports similar callbacks with updated naming.
SAP Emarsys SDK Callbacks
The SAP Emarsys SDK used onCompletion, onClose, and onEvent callbacks:
- Android
- iOS
// SAP Emarsys SDK
InlineInAppView(context).apply {
loadInApp(inApp)
this.onCompletionListener {
/* message loaded */
}
this.onCloseListener = {
/* message closed */
}
this.onAppEventListener = { property, json ->
/* handling AppEvents */
}
}
// SAP Emarsys SDK
InlineInAppView(viewId: key,
onClose: {
/* message closed */
},
onEvent: { name, payload in
/* handling AppEvents */
},
onCompletion: { error in
/* message loaded */
})
SAP Engagement Cloud SDK Callbacks
The SAP Engagement Cloud SDK uses onLoaded and onClose callbacks:
- Android
- Kotlin Multiplatform
- iOS
// SAP Engagement Cloud SDK
InlineInAppView(
viewId = "view-id",
onLoaded = {
// Called when message finishes loading
println("Message loaded")
},
onClose = {
// Called when message is closed
println("Message closed")
}
)
// SAP Engagement Cloud SDK
InlineInAppView(
viewId = "view-id",
onLoaded = {
// Called when message finishes loading
println("Message loaded")
},
onClose = {
// Called when message is closed
println("Message closed")
}
)
// SAP Engagement Cloud SDK
let inlineInAppViewController = EngagementCloud.shared.inApp.InlineInAppViewController(
viewId: "view-id",
onLoaded: {
print("Message loaded")
},
onClose: {
print("Message closed")
}
)
For SwiftUI with UIViewControllerRepresentable:
struct InlineInAppViewWrapper: UIViewControllerRepresentable {
var viewId: String
var onLoaded: (() -> Void)?
var onClose: (() -> Void)?
func makeUIViewController(context: Context) -> UIViewController {
EngagementCloud.shared.inApp.InlineInAppViewController(
viewId: viewId,
onLoaded: onLoaded,
onClose: onClose
)
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}
}
Callback Mapping
| SAP Emarsys SDK Callback | SAP Engagement Cloud SDK Callback | Description |
|---|---|---|
onCompletion | onLoaded | Called after message finishes loading |
onClose | onClose | Called when message is closed |
onEvent | Use EngagementCloud.events instead | For interaction events, subscribe to the global events flow |
For tracking interaction events like button clicks, use the EngagementCloud.events API to subscribe to SDK events. This provides a unified event stream for all SDK interactions rather than per-view callbacks. App Events are extended with a source property to make it easy to filter events by origin (for example, only events from in-app interactions).
- Android
- Kotlin Multiplatform
- iOS
// Subscribe to SDK events for interaction tracking
lifecycleScope.launch {
EngagementCloud.events.collect { event ->
when (event) {
is AppEvent -> {
// handle app event
}
else -> {}
}
}
}
// Subscribe to SDK events for interaction tracking
lifecycleScope.launch {
EngagementCloud.events.collect { event ->
when (event) {
is AppEvent -> {
// handle app event
}
else -> {}
}
}
}
// Subscribe to SDK events for interaction tracking
Task {
for await event in EngagementCloud.shared.events {
// Handle in-app events
}
}
7. Tracking Deep Links
The SAP Emarsys SDK's trackDeepLink method is replaced by deepLink.track in the SAP Engagement Cloud SDK.
- Android
- Kotlin Multiplatform
- iOS
- Web
// In your Activity's onNewIntent
EngagementCloud.deepLink.track(this, intent)
val url = Url("https://example.com/promo")
EngagementCloud.deepLink.track(url)
// In your SceneDelegate or AppDelegate continueUserActivity handler
EngagementCloud.shared.deepLink.track(userActivity: userActivity)
window.EngagementCloud.deepLink.track(url)
8. Reactive Event Stream and onEventAction Handlers
The SAP Emarsys SDK's onEventAction handlers are replaced by the reactive EngagementCloud.events stream in the SAP Engagement Cloud SDK.
- Android
- Kotlin Multiplatform
- iOS
- Web
lifecycleScope.launch {
EngagementCloud.events.collect { event ->
when (event) {
is AppEvent -> // Handle event
is BadgeCountEvent -> // Update badge
else -> <...>
}
}
}
lifecycleScope.launch {
EngagementCloud.events.collect { event ->
when (event) {
is AppEvent -> // Handle event
is BadgeCountEvent -> // Update badge
else -> <...>
}
}
}
Task {
for await event in EngagementCloud.shared.events { event in
// Handle event
}
}
The event listeners (onSubscribe, onUnsubscribe, permission change callbacks) from the SAP Emarsys SDK are replaced by registering listeners for different event types in the SAP Engagement Cloud SDK:
EngagementCloud.events.on("app_event", (event) => console.log(JSON.stringify(event)));
9. Checklist for Validating the Migration
Check the following to validate that your migration is complete:
- Initialization does not trigger network calls before you call
enable(). - Contact linking returns a successful result.
- Push token appears in the SAP Engagement Cloud system. To verify, you can use SDK Events on the App Management page or in the logs.
- Custom events are visible in analytics.
- Deep links are being tracked.
- In-app
pause()andresume()calls work as expected.
10. Changes in Error Handling
The SAP Emarsys SDK used completion listeners and blocks with nullable error objects. The SAP Engagement Cloud SDK replaces them with suspend and async functions, enabling easier composition with coroutines and async/await. These functions return typed results:
- Success:
result.isSuccessortry? await(Swift) /.getOrThrow()(Kotlin). - Failure: Inspect
result.exceptionOrNull()or catch the thrown error if using.getOrThrow().
Example:
- Android
- Kotlin Multiplatform
- iOS
- Web
EngagementCloud.contact.link(contactFieldValue).onFailure { e ->
// Log or retry
}
EngagementCloud.contact.link(contactFieldValue).onFailure { e ->
// Log or retry
}
do {
try await EngagementCloud.shared.contact.link(contactFieldValue: <String>)
} catch {
// Handle error
}
try {
await window.EngagementCloud.contact.link(<contactFieldValue>);
} catch (e) {
// Log or retry
}
Next Steps
- Review Known Limitations for features that are not yet supported.
- Refer to API Mapping to migrate feature-specific calls.