diff --git a/Examples/xx-messenger/Package.swift b/Examples/xx-messenger/Package.swift
index 34d2f4657375e1a4baf78a7811a96a64d2490571..c864b65ae011a37f81518206f61a791e5e93ec04 100644
--- a/Examples/xx-messenger/Package.swift
+++ b/Examples/xx-messenger/Package.swift
@@ -58,11 +58,16 @@ let package = Package(
       url: "https://github.com/pointfreeco/swift-custom-dump.git",
       .upToNextMajor(from: "0.5.2")
     ),
+    .package(
+      url: "https://github.com/kean/Pulse.git",
+      .upToNextMajor(from: "2.1.2")
+    ),
   ],
   targets: [
     .target(
       name: "AppCore",
       dependencies: [
+        .product(name: "Pulse", package: "Pulse"),
         .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"),
         .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"),
         .product(name: "XXDatabase", package: "client-ios-db"),
@@ -98,6 +103,7 @@ let package = Package(
         .target(name: "WelcomeFeature"),
         .product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
         .product(name: "ComposablePresentation", package: "swift-composable-presentation"),
+        .product(name: "PulseUI", package: "Pulse"),
         .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"),
         .product(name: "XXModels", package: "client-ios-db"),
       ],
diff --git a/Examples/xx-messenger/Sources/AppCore/Logger/Logger.swift b/Examples/xx-messenger/Sources/AppCore/Logger/Logger.swift
new file mode 100644
index 0000000000000000000000000000000000000000..6766d98d4f6ef506112e5cee8d6efa060ec9b214
--- /dev/null
+++ b/Examples/xx-messenger/Sources/AppCore/Logger/Logger.swift
@@ -0,0 +1,45 @@
+import Foundation
+import Pulse
+import XCTestDynamicOverlay
+
+public struct Logger {
+  public enum Message: Equatable {
+    case error(NSError)
+  }
+
+  public var run: (Message, String, String, UInt) -> Void
+
+  public func callAsFunction(
+    _ msg: Message,
+    file: String = #file,
+    function: String = #function,
+    line: UInt = #line
+  ) {
+    run(msg, file, function, line)
+  }
+}
+
+extension Logger {
+  public static func live() -> Logger {
+    Logger { msg, file, function, line in
+      switch msg {
+      case .error(let error):
+        LoggerStore.shared.storeMessage(
+          label: "xx-messenger",
+          level: .error,
+          message: error.localizedDescription,
+          metadata: [:],
+          file: file,
+          function: function,
+          line: line
+        )
+      }
+    }
+  }
+}
+
+extension Logger {
+  public static let unimplemented = Logger(
+    run: XCTUnimplemented("\(Self.self).error")
+  )
+}
diff --git a/Examples/xx-messenger/Sources/AppCore/SharedUI/ShakeViewModifier.swift b/Examples/xx-messenger/Sources/AppCore/SharedUI/ShakeViewModifier.swift
new file mode 100644
index 0000000000000000000000000000000000000000..d46cdc6d1a61adde2ace4c7fd6aebb3a1cfedd16
--- /dev/null
+++ b/Examples/xx-messenger/Sources/AppCore/SharedUI/ShakeViewModifier.swift
@@ -0,0 +1,42 @@
+import SwiftUI
+
+struct ShakeViewModifier: ViewModifier {
+  var action: () -> Void
+
+  func body(content: Content) -> some View {
+    content.onReceive(
+      NotificationCenter.default.publisher(
+        for: UIDevice.deviceDidShakeNotification
+      ),
+      perform: { _ in
+        action()
+      }
+    )
+  }
+}
+
+extension View {
+  public func onShake(perform action: @escaping () -> Void) -> some View {
+    modifier(ShakeViewModifier(action: action))
+  }
+}
+
+extension UIDevice {
+  static let deviceDidShakeNotification = Notification.Name(
+    rawValue: "deviceDidShakeNotification"
+  )
+}
+
+extension UIWindow {
+  open override func motionEnded(
+    _ motion: UIEvent.EventSubtype,
+    with event: UIEvent?
+  ) {
+    super.motionEnded(motion, with: event)
+    guard motion == .motionShake else { return }
+    NotificationCenter.default.post(
+      name: UIDevice.deviceDidShakeNotification,
+      object: nil
+    )
+  }
+}
diff --git a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
index 3c75f40afb41be86846967f43d2b8fb0f8462b8c..c79d5b935e7f12255b852278256742608695734e 100644
--- a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
+++ b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
@@ -90,6 +90,7 @@ extension AppEnvironment {
         messenger: messenger,
         db: dbManager.getDB
       ),
+      log: .live(),
       mainQueue: mainQueue,
       bgQueue: bgQueue,
       welcome: {
diff --git a/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift b/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift
index 9424cbf2991248fa6369fb44a2a23982ff6fe8d8..caae3368d778873e89af41f51a8a9ecce581866c 100644
--- a/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift
+++ b/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift
@@ -50,6 +50,7 @@ struct AppEnvironment {
   var messenger: Messenger
   var authHandler: AuthCallbackHandler
   var messageListener: MessageListenerHandler
+  var log: Logger
   var mainQueue: AnySchedulerOf<DispatchQueue>
   var bgQueue: AnySchedulerOf<DispatchQueue>
   var welcome: () -> WelcomeEnvironment
@@ -63,6 +64,7 @@ extension AppEnvironment {
     messenger: .unimplemented,
     authHandler: .unimplemented,
     messageListener: .unimplemented,
+    log: .unimplemented,
     mainQueue: .unimplemented,
     bgQueue: .unimplemented,
     welcome: { .unimplemented },
@@ -87,10 +89,10 @@ let appReducer = Reducer<AppState, AppAction, AppEnvironment>
         }
 
         cancellables.append(env.authHandler(onError: { error in
-          // TODO: handle error
+          env.log(.error(error as NSError))
         }))
         cancellables.append(env.messageListener(onError: { error in
-          // TODO: handle error
+          env.log(.error(error as NSError))
         }))
 
         let isLoaded = env.messenger.isLoaded()
diff --git a/Examples/xx-messenger/Sources/AppFeature/AppView.swift b/Examples/xx-messenger/Sources/AppFeature/AppView.swift
index 64a8411df29fe65ebab6b403ae9f2c88438d140c..57983b1dd0b826321f3dac8c120637736ff64b60 100644
--- a/Examples/xx-messenger/Sources/AppFeature/AppView.swift
+++ b/Examples/xx-messenger/Sources/AppFeature/AppView.swift
@@ -1,11 +1,13 @@
 import ComposableArchitecture
 import HomeFeature
+import PulseUI
 import RestoreFeature
 import SwiftUI
 import WelcomeFeature
 
 struct AppView: View {
   let store: Store<AppState, AppAction>
+  @State var isPresentingPulse = false
 
   enum ViewState: Equatable {
     case loading
@@ -119,6 +121,15 @@ struct AppView: View {
       .animation(.default, value: viewStore.state)
       .task { viewStore.send(.start) }
     }
+    .onShake {
+      isPresentingPulse = true
+    }
+    .fullScreenCover(isPresented: $isPresentingPulse) {
+      PulseUI.MainView(
+        store: .shared,
+        onDismiss: { isPresentingPulse = false }
+      )
+    }
   }
 }
 
diff --git a/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift b/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift
index 93d719030e6bd5554465078f957f1e0412c3da76..5bda4eb3f27c96014321e14766017b81a9f05f4e 100644
--- a/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift
@@ -351,6 +351,9 @@ final class AppFeatureTests: XCTestCase {
         actions.append(.didCancelMessageListener)
       }
     }
+    store.environment.log.run = { msg, _, _, _ in
+      actions.append(.didLog(msg))
+    }
 
     store.send(.start)
 
@@ -381,15 +384,21 @@ final class AppFeatureTests: XCTestCase {
     actions = []
 
     struct AuthError: Error {}
-    authHandlerOnError.first?(AuthError())
+    let authError = AuthError()
+    authHandlerOnError.first?(authError)
 
-    XCTAssertNoDifference(actions, [])
+    XCTAssertNoDifference(actions, [
+      .didLog(.error(authError as NSError))
+    ])
     actions = []
 
     struct MessageError: Error {}
-    messageListenerOnError.first?(MessageError())
+    let messageError = MessageError()
+    messageListenerOnError.first?(messageError)
 
-    XCTAssertNoDifference(actions, [])
+    XCTAssertNoDifference(actions, [
+      .didLog(.error(messageError as NSError))
+    ])
     actions = []
 
     store.send(.stop)
@@ -408,4 +417,5 @@ private enum Action: Equatable {
   case didLoadMessenger
   case didCancelAuthHandler
   case didCancelMessageListener
+  case didLog(Logger.Message)
 }
diff --git a/Examples/xx-messenger/XXMessenger.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/xx-messenger/XXMessenger.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 42a8b2ba71e97e1f4f1a04cdf740a1fb59c1242d..0407c096921c2a803d4776a42c53ab56a275507a 100644
--- a/Examples/xx-messenger/XXMessenger.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Examples/xx-messenger/XXMessenger.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -36,6 +36,15 @@
         "version" : "4.2.2"
       }
     },
+    {
+      "identity" : "pulse",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/kean/Pulse.git",
+      "state" : {
+        "revision" : "786611d3094e33f27d4546b260a966352bc45fd6",
+        "version" : "2.1.2"
+      }
+    },
     {
       "identity" : "swift-case-paths",
       "kind" : "remoteSourceControl",
@@ -90,6 +99,15 @@
         "version" : "0.4.1"
       }
     },
+    {
+      "identity" : "swift-log",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/apple/swift-log.git",
+      "state" : {
+        "revision" : "6fe203dc33195667ce1759bf0182975e4653ba1c",
+        "version" : "1.4.4"
+      }
+    },
     {
       "identity" : "xctest-dynamic-overlay",
       "kind" : "remoteSourceControl",