diff --git a/Sources/XXMessengerClient/Utils/BackupCallbackRegistry.swift b/Sources/XXMessengerClient/Utils/BackupCallbackRegistry.swift
new file mode 100644
index 0000000000000000000000000000000000000000..7c7fc9e8ae08a983f72a4240728610bab152f965
--- /dev/null
+++ b/Sources/XXMessengerClient/Utils/BackupCallbackRegistry.swift
@@ -0,0 +1,36 @@
+import Foundation
+import XCTestDynamicOverlay
+import XXClient
+
+public struct BackupCallbacksRegistry {
+  public var register: (UpdateBackupFunc) -> Cancellable
+  public var registered: () -> UpdateBackupFunc
+}
+
+extension BackupCallbacksRegistry {
+  public static func live() -> BackupCallbacksRegistry {
+    class Registry {
+      var callbacks: [UUID: UpdateBackupFunc] = [:]
+    }
+    let registry = Registry()
+    return BackupCallbacksRegistry(
+      register: { callback in
+        let id = UUID()
+        registry.callbacks[id] = callback
+        return Cancellable { registry.callbacks[id] = nil }
+      },
+      registered: {
+        UpdateBackupFunc { data in
+          registry.callbacks.values.forEach { $0.handle(data) }
+        }
+      }
+    )
+  }
+}
+
+extension BackupCallbacksRegistry {
+  public static let unimplemented = BackupCallbacksRegistry(
+    register: XCTUnimplemented("\(Self.self).register", placeholder: Cancellable {}),
+    registered: XCTUnimplemented("\(Self.self).registered", placeholder: UpdateBackupFunc { _ in })
+  )
+}
diff --git a/Tests/XXMessengerClientTests/Utils/BackupCallbackRegistryTests.swift b/Tests/XXMessengerClientTests/Utils/BackupCallbackRegistryTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..d3cba50cb81fe1efb2188985fed7ef9a8470290d
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Utils/BackupCallbackRegistryTests.swift
@@ -0,0 +1,43 @@
+import CustomDump
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class BackupCallbackRegistryTests: XCTestCase {
+  func testRegistry() {
+    var firstCallbackDidHandle: [Data] = []
+    var secondCallbackDidHandle: [Data] = []
+
+    let firstCallback = UpdateBackupFunc { data in
+      firstCallbackDidHandle.append(data)
+    }
+    let secondCallback = UpdateBackupFunc { data in
+      secondCallbackDidHandle.append(data)
+    }
+    let callbackRegistry: BackupCallbacksRegistry = .live()
+    let registeredCallbacks = callbackRegistry.registered()
+    let firstCallbackCancellable = callbackRegistry.register(firstCallback)
+    let secondCallbackCancellable = callbackRegistry.register(secondCallback)
+
+    let firstData = "1".data(using: .utf8)!
+    registeredCallbacks.handle(firstData)
+
+    XCTAssertNoDifference(firstCallbackDidHandle, [firstData])
+    XCTAssertNoDifference(secondCallbackDidHandle, [firstData])
+
+    firstCallbackCancellable.cancel()
+    let secondData = "2".data(using: .utf8)!
+    registeredCallbacks.handle(secondData)
+
+    XCTAssertNoDifference(firstCallbackDidHandle, [firstData])
+    XCTAssertNoDifference(secondCallbackDidHandle, [firstData, secondData])
+
+    secondCallbackCancellable.cancel()
+
+    let thirdData = "3".data(using: .utf8)!
+    registeredCallbacks.handle(thirdData)
+
+    XCTAssertNoDifference(firstCallbackDidHandle, [firstData])
+    XCTAssertNoDifference(secondCallbackDidHandle, [firstData, secondData])
+  }
+}