Skip to main content


If needed, your app users can chat with you to provide you more details about their reported bugs, crashes or feedback. You will be able to fix issues faster and make your customers happier.


Once your app user is registered with Shake, the chat feature is enabled automatically. Each ticket they send you will be a separate conversation.

This feature is tightly integrated with and follows the lifecycle of your User registration, which means that calling Shake.unregisterUser also disconnects the current app user from chat and they won't receive any new messages until registered again.


Shake will notify your app user when you send them a new message from the Shake dashboard. Notifications are presented automatically to the app user. You don't have to code anything.


At the moment, Shake supports only local notifications. Which means that end-users won't get notified about new messages when your application is in the background.


Notifications are automatically presented to the end-user, no additional code is required.


To present any kind of notifications to the end-user, the host application must request a permission from the app user. Find a suitable place in your application flow where this native alert dialog will be presented.

In order to be highly customizable and minimally intrusive to existing notification logic of host applications, Shake requires additional setup outlined in the below snippets.

Use the UNUserNotificationCenter ...) methods to delegate the notification presentation logic to Shake.

#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
@import Shake;
@import UserNotifications;
static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
if ([response.notification.request.content.categoryIdentifier containsString:SHKNotificationCategoryIdentifierDomain]){
[SHKShake reportNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
if ([notification.request.content.categoryIdentifier containsString:SHKNotificationCategoryIdentifierDomain]) {
[SHKShake reportNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler];
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound);
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge{
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
@import UserNotifications;
@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate, RCTBridgeDelegate>
@property (nonatomic, strong) UIWindow *window;

Given the above setup, all notifications originated from Shake are handled by the Shake SDK, and all other notifications remain handled by your application.


You can cancel the display of notifications in certain contexts by simply not reporting anything to Shake, or even stub the received native completion handler with your own set of UNNotificationPresentationOptions which will be respected by the Shake SDK.

Unread messages

If you want to show number of unread chat messages somewhere in your app, you can set the unread messages listener. The listener is called immediately when set and on each change in the number of unread messages for a registered app user:

Shake.setUnreadMessagesListener(count => {
// Update number in your text element

To remove the unread messages listener, use Shake.setUnreadMessagesListener(null).