diff --git a/App/client-ios/Resources/Info.plist b/App/client-ios/Resources/Info.plist
index ed25d86cf62d659ee34ae0f720d9de7f8a56fefb..dd578c50c07a9aef6e5edff517adeffcbe4be8ca 100644
--- a/App/client-ios/Resources/Info.plist
+++ b/App/client-ios/Resources/Info.plist
@@ -34,10 +34,10 @@
 		</dict>
 		<dict>
 			<key>CFBundleURLName</key>
-			<string>xxmessenger</string>
+			<string>xxnetwork</string>
 			<key>CFBundleURLSchemes</key>
 			<array>
-				<string>xxmessenger</string>
+				<string>xxnetwork</string>
 			</array>
 		</dict>
 		<dict>
diff --git a/Package.swift b/Package.swift
index bcec957c2be3321cb1b9f1bcc1dd176814764b54..08f6fef2fb77a9c65ba50627b93abcb367a5a6f6 100644
--- a/Package.swift
+++ b/Package.swift
@@ -722,6 +722,13 @@ let package = Package(
                 dependencies: ["DependencyInjection"]
             ),
 
+        // MARK: - AppTests
+
+            .testTarget(
+                name: "AppTests",
+                dependencies: ["App"]
+            ),
+
         // MARK: - ProfileFeatureTests
 
             .testTarget(
diff --git a/Sources/App/AppDelegate.swift b/Sources/App/AppDelegate.swift
index 72a7f682477967599a823601b8315c46ed429ee6..00b8875eaf650d668ae4541fb254fc52c2c50980 100644
--- a/Sources/App/AppDelegate.swift
+++ b/Sources/App/AppDelegate.swift
@@ -20,6 +20,7 @@ public class AppDelegate: UIResponder, UIApplicationDelegate {
     @Dependency private var crashReporter: CrashReporter
     @Dependency private var dropboxService: DropboxInterface
 
+    @KeyObject(.invitation, defaultValue: nil) var invitation: String?
     @KeyObject(.hideAppList, defaultValue: false) var hideAppList: Bool
     @KeyObject(.recordingLogs, defaultValue: true) var recordingLogs: Bool
     @KeyObject(.crashReporting, defaultValue: true) var isCrashReportingEnabled: Bool
@@ -142,10 +143,30 @@ public class AppDelegate: UIResponder, UIApplicationDelegate {
         open url: URL,
         options: [UIApplication.OpenURLOptionsKey : Any] = [:]
     ) -> Bool {
-        dropboxService.handleOpenUrl(url)
+        if let username = getUsernameFromInvitationDeepLink(url) {
+            let router = try! DependencyInjection.Container.shared.resolve() as PushRouter
+            invitation = username
+            router.navigateTo(.search, {})
+
+            return true
+        } else {
+            return dropboxService.handleOpenUrl(url)
+        }
     }
 }
 
+func getUsernameFromInvitationDeepLink(_ url: URL) -> String? {
+    if let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
+       components.scheme == "xxnetwork",
+       components.host == "messenger",
+       let queryItem = components.queryItems?.first(where: { $0.name == "invitation" }),
+       let username = queryItem.value {
+        return username
+    }
+
+    return nil
+}
+
 // MARK: Notifications
 
 extension AppDelegate: UNUserNotificationCenterDelegate {
diff --git a/Sources/App/DependencyRegistrator.swift b/Sources/App/DependencyRegistrator.swift
index 14a7b7bdb482974cff2b5b2be573d3f5fb1a33fc..05d03f78e33764ef8a3f3cd325b5fa1b9d958c18 100644
--- a/Sources/App/DependencyRegistrator.swift
+++ b/Sources/App/DependencyRegistrator.swift
@@ -113,6 +113,7 @@ struct DependencyRegistrator {
 
         container.register(
             LaunchCoordinator(
+                searchFactory: SearchContainerController.init,
                 requestsFactory: RequestsContainerController.init,
                 chatListFactory: ChatListController.init,
                 onboardingFactory: OnboardingStartController.init(_:),
@@ -250,38 +251,3 @@ struct DependencyRegistrator {
             ) as ChatListCoordinating)
     }
 }
-
-extension PushRouter {
-    static func live(navigationController: UINavigationController) -> PushRouter {
-        PushRouter { route, completion in
-            if let launchController = navigationController.viewControllers.last as? LaunchController {
-                launchController.pendingPushRoute = route
-            } else {
-                switch route {
-                case .requests:
-                    if (navigationController.viewControllers.last as? RequestsContainerController) == nil {
-                        navigationController.setViewControllers([RequestsContainerController()], animated: true)
-                    }
-                case .contactChat(id: let id):
-                    if let session = try? DependencyInjection.Container.shared.resolve() as SessionType,
-                       let contact = try? session.dbManager.fetchContacts(.init(id: [id])).first {
-                        navigationController.setViewControllers([
-                            ChatListController(),
-                            SingleChatController(contact)
-                        ], animated: true)
-                    }
-                case .groupChat(id: let id):
-                    if let session = try? DependencyInjection.Container.shared.resolve() as SessionType,
-                       let info = try? session.dbManager.fetchGroupInfos(.init(groupId: id)).first {
-                        navigationController.setViewControllers([
-                            ChatListController(),
-                            GroupChatController(info)
-                        ], animated: true)
-                    }
-                }
-            }
-
-            completion()
-        }
-    }
-}
diff --git a/Sources/App/PushRouter.swift b/Sources/App/PushRouter.swift
new file mode 100644
index 0000000000000000000000000000000000000000..d81f841fc2c8b28a0380da507e37208c0bf2faf9
--- /dev/null
+++ b/Sources/App/PushRouter.swift
@@ -0,0 +1,51 @@
+import UIKit
+import PushFeature
+import Integration
+import ChatFeature
+import SearchFeature
+import LaunchFeature
+import ChatListFeature
+import RequestsFeature
+import DependencyInjection
+
+extension PushRouter {
+    static func live(navigationController: UINavigationController) -> PushRouter {
+        PushRouter { route, completion in
+            if let launchController = navigationController.viewControllers.last as? LaunchController {
+                launchController.pendingPushRoute = route
+            } else {
+                switch route {
+                case .search:
+                    if !(navigationController.viewControllers.last is SearchContainerController) {
+                        navigationController.setViewControllers([
+                            ChatListController(),
+                            SearchContainerController()
+                        ], animated: true)
+                    }
+                case .requests:
+                    if !(navigationController.viewControllers.last is RequestsContainerController) {
+                        navigationController.setViewControllers([RequestsContainerController()], animated: true)
+                    }
+                case .contactChat(id: let id):
+                    if let session = try? DependencyInjection.Container.shared.resolve() as SessionType,
+                       let contact = try? session.dbManager.fetchContacts(.init(id: [id])).first {
+                        navigationController.setViewControllers([
+                            ChatListController(),
+                            SingleChatController(contact)
+                        ], animated: true)
+                    }
+                case .groupChat(id: let id):
+                    if let session = try? DependencyInjection.Container.shared.resolve() as SessionType,
+                       let info = try? session.dbManager.fetchGroupInfos(.init(groupId: id)).first {
+                        navigationController.setViewControllers([
+                            ChatListController(),
+                            GroupChatController(info)
+                        ], animated: true)
+                    }
+                }
+            }
+
+            completion()
+        }
+    }
+}
diff --git a/Sources/Defaults/KeyObject.swift b/Sources/Defaults/KeyObject.swift
index 7757f7ed4fa550c478736b76cd7c1036ef4fde34..5714b112586e2c54b1c6aeae19224e4a060770fc 100644
--- a/Sources/Defaults/KeyObject.swift
+++ b/Sources/Defaults/KeyObject.swift
@@ -21,6 +21,7 @@ public enum Key: String {
     // MARK: General
 
     case theme
+    case invitation
 
     // MARK: Requests
 
diff --git a/Sources/Integration/Session/Session+UD.swift b/Sources/Integration/Session/Session+UD.swift
index 1fe3e2e09b2f7f0ae327b039602320bbc884eb2b..27add4b13b1839482aefe29badc0f0fbe4e61e8f 100644
--- a/Sources/Integration/Session/Session+UD.swift
+++ b/Sources/Integration/Session/Session+UD.swift
@@ -1,9 +1,24 @@
+import Retry
 import Models
+import Combine
 import XXModels
 import Foundation
-import Combine
 
 extension Session {
+    public func waitForNodes(timeout: Int) -> AnyPublisher<Void, Error> {
+        Deferred {
+            Future { promise in
+                retry(max: timeout, retryStrategy: .delay(seconds: 1)) { [weak self] in
+                    guard let self = self else { return }
+                    try self.client.bindings.nodeRegistrationStatus()
+                    promise(.success(()))
+                }.finalCatch {
+                    promise(.failure($0))
+                }
+            }
+        }.eraseToAnyPublisher()
+    }
+
     public func search(fact: String) -> AnyPublisher<Contact, Error> {
         Deferred {
             Future { promise in
diff --git a/Sources/Integration/Session/SessionType.swift b/Sources/Integration/Session/SessionType.swift
index b871332b216e5c7dbdc0adfebc4bac3f306913b7..effd6c96c3239904722b74f2856f2a953f0b986e 100644
--- a/Sources/Integration/Session/SessionType.swift
+++ b/Sources/Integration/Session/SessionType.swift
@@ -68,4 +68,6 @@ public protocol SessionType {
     )
 
     func search(fact: String) -> AnyPublisher<Contact, Error>
+
+    func waitForNodes(timeout: Int) -> AnyPublisher<Void, Error>
 }
diff --git a/Sources/LaunchFeature/LaunchController.swift b/Sources/LaunchFeature/LaunchController.swift
index 2eb373f55784bed3e9a11293acc7cca9aee2fc08..0a6a1c651affe95c973a5eb6b5b46a968b5b5a48 100644
--- a/Sources/LaunchFeature/LaunchController.swift
+++ b/Sources/LaunchFeature/LaunchController.swift
@@ -5,7 +5,6 @@ import Combine
 import PushFeature
 import DependencyInjection
 
-
 public final class LaunchController: UIViewController {
     @Dependency private var hud: HUD
     @Dependency private var coordinator: LaunchCoordinating
@@ -50,9 +49,14 @@ public final class LaunchController: UIViewController {
             .receive(on: DispatchQueue.main)
             .sink { [unowned self] in
                 switch $0 {
+                case .search:
+                    coordinator.toSearch(from: self)
                 case .chats:
                     if let pushRoute = pendingPushRoute {
                         switch pushRoute {
+                        case .search:
+                            coordinator.toSearch(from: self)
+
                         case .requests:
                             coordinator.toRequests(from: self)
 
diff --git a/Sources/LaunchFeature/LaunchCoordinator.swift b/Sources/LaunchFeature/LaunchCoordinator.swift
index 4f5a56291b19634df4c46edc2634acb55ba5812e..a9612d61ecf217dcdef7af544cef60b67509adbd 100644
--- a/Sources/LaunchFeature/LaunchCoordinator.swift
+++ b/Sources/LaunchFeature/LaunchCoordinator.swift
@@ -5,6 +5,7 @@ import Presentation
 
 public protocol LaunchCoordinating {
     func toChats(from: UIViewController)
+    func toSearch(from: UIViewController)
     func toRequests(from: UIViewController)
     func toOnboarding(with: String, from: UIViewController)
     func toSingleChat(with: Contact, from: UIViewController)
@@ -14,6 +15,7 @@ public protocol LaunchCoordinating {
 public struct LaunchCoordinator: LaunchCoordinating {
     var replacePresenter: Presenting = ReplacePresenter()
 
+    var searchFactory: () -> UIViewController
     var requestsFactory: () -> UIViewController
     var chatListFactory: () -> UIViewController
     var onboardingFactory: (String) -> UIViewController
@@ -21,12 +23,14 @@ public struct LaunchCoordinator: LaunchCoordinating {
     var groupChatFactory: (GroupInfo) -> UIViewController
 
     public init(
+        searchFactory: @escaping () -> UIViewController,
         requestsFactory: @escaping () -> UIViewController,
         chatListFactory: @escaping () -> UIViewController,
         onboardingFactory: @escaping (String) -> UIViewController,
         singleChatFactory: @escaping (Contact) -> UIViewController,
         groupChatFactory: @escaping (GroupInfo) -> UIViewController
     ) {
+        self.searchFactory = searchFactory
         self.requestsFactory = requestsFactory
         self.chatListFactory = chatListFactory
         self.groupChatFactory = groupChatFactory
@@ -36,6 +40,12 @@ public struct LaunchCoordinator: LaunchCoordinating {
 }
 
 public extension LaunchCoordinator {
+    func toSearch(from parent: UIViewController) {
+        let screen = searchFactory()
+        let chatListScreen = chatListFactory()
+        replacePresenter.present(chatListScreen, screen, from: parent)
+    }
+
     func toChats(from parent: UIViewController) {
         let screen = chatListFactory()
         replacePresenter.present(screen, from: parent)
diff --git a/Sources/LaunchFeature/LaunchViewModel.swift b/Sources/LaunchFeature/LaunchViewModel.swift
index fefbe7cf6035b19d804febd7e544e22166d11bf8..42b69bb7bfc8e2d45ec2fe14acdf18f01e9bd3db 100644
--- a/Sources/LaunchFeature/LaunchViewModel.swift
+++ b/Sources/LaunchFeature/LaunchViewModel.swift
@@ -24,6 +24,7 @@ struct Update {
 
 enum LaunchRoute {
     case chats
+    case search
     case update(Update)
     case onboarding(String)
 }
@@ -36,6 +37,7 @@ final class LaunchViewModel {
     @Dependency private var permissionHandler: PermissionHandling
 
     @KeyObject(.username, defaultValue: nil) var username: String?
+    @KeyObject(.invitation, defaultValue: nil) var invitation: String?
     @KeyObject(.biometrics, defaultValue: false) var isBiometricsOn: Bool
 
     var hudPublisher: AnyPublisher<HUDStatus, Never> {
@@ -180,17 +182,28 @@ final class LaunchViewModel {
     private func checkBiometrics() {
         if permissionHandler.isBiometricsAvailable && isBiometricsOn {
             permissionHandler.requestBiometrics { [weak self] in
+                guard let self = self else { return }
+
                 switch $0 {
                 case .success(let granted):
                     guard granted else { return }
-                    self?.routeSubject.send(.chats)
+
+                    if self.invitation != nil {
+                        self.routeSubject.send(.search)
+                    } else {
+                        self.routeSubject.send(.chats)
+                    }
 
                 case .failure(let error):
-                    self?.hudSubject.send(.error(HUDError(with: error)))
+                    self.hudSubject.send(.error(HUDError(with: error)))
                 }
             }
         } else {
-            routeSubject.send(.chats)
+            if self.invitation != nil {
+                self.routeSubject.send(.search)
+            } else {
+                self.routeSubject.send(.chats)
+            }
         }
     }
 }
diff --git a/Sources/MenuFeature/Controllers/MenuController.swift b/Sources/MenuFeature/Controllers/MenuController.swift
index 682e23d450bde134916a2db8a00d13c2279c9321..93f1fcf4a328da1f73f077b8f0f8806ceee0c7f5 100644
--- a/Sources/MenuFeature/Controllers/MenuController.swift
+++ b/Sources/MenuFeature/Controllers/MenuController.swift
@@ -9,6 +9,7 @@ public enum MenuItem {
     case join
     case scan
     case chats
+    case share
     case profile
     case contacts
     case requests
@@ -171,6 +172,19 @@ public final class MenuController: UIViewController {
                 }
             }.store(in: &cancellables)
 
+        screenView.shareButton
+            .publisher(for: .touchUpInside)
+            .receive(on: DispatchQueue.main)
+            .sink { [unowned self] in
+                dismiss(animated: true) { [weak self] in
+                    guard let self = self, self.previousItem != .share else { return }
+                    self.coordinator.toActivityController(
+                        with: [Localized.Menu.shareContent(self.viewModel.referralDeeplink)],
+                        from: self.previousController
+                    )
+                }
+            }.store(in: &cancellables)
+
         viewModel.requestCount
             .receive(on: DispatchQueue.main)
             .sink { [weak screenView] in screenView?.requestsButton.updateNotification($0) }
diff --git a/Sources/MenuFeature/Coordinator/MenuCoordinator.swift b/Sources/MenuFeature/Coordinator/MenuCoordinator.swift
index fba5c8ea4f8bfb1aa155dcf4ada8fba1a58c3f39..3e7d20cc85f6a4afa7e50e2f8133bdf041f5ace6 100644
--- a/Sources/MenuFeature/Coordinator/MenuCoordinator.swift
+++ b/Sources/MenuFeature/Coordinator/MenuCoordinator.swift
@@ -4,9 +4,11 @@ import Presentation
 public protocol MenuCoordinating {
     func toFlow(_ item: MenuItem, from: UIViewController)
     func toDrawer(_: UIViewController, from: UIViewController)
+    func toActivityController(with: [Any], from: UIViewController)
 }
 
 public struct MenuCoordinator: MenuCoordinating {
+    var modalPresenter: Presenting = ModalPresenter()
     var bottomPresenter: Presenting = BottomPresenter()
     var replacePresenter: Presenting = ReplacePresenter()
 
@@ -16,6 +18,8 @@ public struct MenuCoordinator: MenuCoordinating {
     var settingsFactory: () -> UIViewController
     var contactsFactory: () -> UIViewController
     var requestsFactory: () -> UIViewController
+    var activityControllerFactory: ([Any]) -> UIViewController
+    = { UIActivityViewController(activityItems: $0, applicationActivities: nil) }
 
     public init(
         scanFactory: @escaping () -> UIViewController,
@@ -61,4 +65,9 @@ public extension MenuCoordinator {
 
         replacePresenter.present(controller, from: parent)
     }
+
+    func toActivityController(with items: [Any], from parent: UIViewController) {
+        let screen = activityControllerFactory(items)
+        modalPresenter.present(screen, from: parent)
+    }
 }
diff --git a/Sources/MenuFeature/ViewModels/MenuViewModel.swift b/Sources/MenuFeature/ViewModels/MenuViewModel.swift
index f3e4bcbd5260af8c2e62849c7eca05b4098cffe4..98bc5d74b66c3e85e43ea5f9b7a21129db7cd55d 100644
--- a/Sources/MenuFeature/ViewModels/MenuViewModel.swift
+++ b/Sources/MenuFeature/ViewModels/MenuViewModel.swift
@@ -40,4 +40,8 @@ final class MenuViewModel {
     var version: String {
         Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
     }
+
+    var referralDeeplink: String {
+        "xxnetwork://messenger?invitation=\(username)"
+    }
 }
diff --git a/Sources/MenuFeature/Views/MenuView.swift b/Sources/MenuFeature/Views/MenuView.swift
index b19ec9d1d1367f5d910dfe97d40ee9198b7e3ec0..e256782eddaa5e686d2bfc7e3ef4af237c3eb51c 100644
--- a/Sources/MenuFeature/Views/MenuView.swift
+++ b/Sources/MenuFeature/Views/MenuView.swift
@@ -2,31 +2,33 @@ import UIKit
 import Shared
 
 final class MenuView: UIView {
-    let headerView = MenuHeaderView()
+    let buildLabel = UILabel()
+    let versionLabel = UILabel()
     let stackView = UIStackView()
+    let xxdkVersionLabel = UILabel()
+    let infoStackView = UIStackView()
+    let headerView = MenuHeaderView()
+    let joinButton = MenuSectionButton()
     let scanButton = MenuSectionButton()
+    let shareButton = MenuSectionButton()
     let chatsButton = MenuSectionButton()
     let contactsButton = MenuSectionButton()
     let requestsButton = MenuSectionButton()
     let settingsButton = MenuSectionButton()
     let dashboardButton = MenuSectionButton()
-    let joinButton = MenuSectionButton()
-    let infoStackView = UIStackView()
-    let buildLabel = UILabel()
-    let versionLabel = UILabel()
-    let xxdkVersionLabel = UILabel()
 
     init() {
         super.init(frame: .zero)
         backgroundColor = Asset.neutralDark.color
 
-        chatsButton.set(title: Localized.Menu.chats, image: Asset.menuChats.image)
         scanButton.set(title: Localized.Menu.scan, image: Asset.menuScan.image)
+        shareButton.set(title: Localized.Menu.share, image: Asset.menuShare.image)
+        chatsButton.set(title: Localized.Menu.chats, image: Asset.menuChats.image)
+        joinButton.set(title: Localized.Menu.join, image: Asset.permissionLogo.image)
         requestsButton.set(title: Localized.Menu.requests, image: Asset.menuRequests.image)
         contactsButton.set(title: Localized.Menu.contacts, image: Asset.menuContacts.image)
         settingsButton.set(title: Localized.Menu.settings, image: Asset.menuSettings.image)
         dashboardButton.set(title: Localized.Menu.dashboard, image: Asset.menuDashboard.image)
-        joinButton.set(title: "Join xx network", image: Asset.permissionLogo.image)
 
         stackView.addArrangedSubview(chatsButton)
         stackView.addArrangedSubview(contactsButton)
@@ -35,6 +37,7 @@ final class MenuView: UIView {
         stackView.addArrangedSubview(settingsButton)
         stackView.addArrangedSubview(dashboardButton)
         stackView.addArrangedSubview(joinButton)
+        stackView.addArrangedSubview(shareButton)
 
         infoStackView.spacing = 10
         infoStackView.axis = .vertical
@@ -59,17 +62,17 @@ final class MenuView: UIView {
 
     func select(item: MenuItem) {
         switch item {
+        case .scan:
+            scanButton.set(color: Asset.brandPrimary.color)
         case .chats:
             chatsButton.set(color: Asset.brandPrimary.color)
         case .contacts:
             contactsButton.set(color: Asset.brandPrimary.color)
         case .requests:
             requestsButton.set(color: Asset.brandPrimary.color)
-        case .scan:
-            scanButton.set(color: Asset.brandPrimary.color)
         case .settings:
             settingsButton.set(color: Asset.brandPrimary.color)
-        case .profile, .dashboard, .join:
+        case .share, .join, .profile, .dashboard:
             break
         }
     }
diff --git a/Sources/PushFeature/PushRouter.swift b/Sources/PushFeature/PushRouter.swift
index 6fc66797612acf41e56213ab64ffc9a7029d873e..51af8a80ae87cf6bbab518a666256e9925685325 100644
--- a/Sources/PushFeature/PushRouter.swift
+++ b/Sources/PushFeature/PushRouter.swift
@@ -4,6 +4,7 @@ public struct PushRouter {
     public typealias NavigateTo = (Route, @escaping () -> Void) -> Void
 
     public enum Route {
+        case search
         case requests
         case groupChat(id: Data)
         case contactChat(id: Data)
diff --git a/Sources/SearchFeature/Controllers/SearchLeftController.swift b/Sources/SearchFeature/Controllers/SearchLeftController.swift
index bbfabd2836990bb00c86e01a09527bdbac8b1145..b3ca0e83922c6fe4868b68e5338ff1ee7fdaa496 100644
--- a/Sources/SearchFeature/Controllers/SearchLeftController.swift
+++ b/Sources/SearchFeature/Controllers/SearchLeftController.swift
@@ -37,6 +37,11 @@ final class SearchLeftController: UIViewController {
         setupBindings()
     }
 
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        viewModel.viewDidAppear()
+    }
+
     func endEditing() {
         screenView.inputField.endEditing(true)
     }
@@ -131,6 +136,13 @@ final class SearchLeftController: UIViewController {
             .sink { [unowned self] in screenView.countryButton.setFlag($0.flag, prefix: $0.prefix) }
             .store(in: &cancellables)
 
+        viewModel.statePublisher
+            .map(\.input)
+            .removeDuplicates()
+            .receive(on: DispatchQueue.main)
+            .sink { [unowned self] in screenView.inputField.update(content: $0) }
+            .store(in: &cancellables)
+
         viewModel.statePublisher
             .compactMap(\.snapshot)
             .receive(on: DispatchQueue.main)
@@ -403,7 +415,6 @@ final class SearchLeftController: UIViewController {
 
         coordinator.toDrawer(drawer, from: self)
     }
-
 }
 
 extension SearchLeftController: UITableViewDelegate {
diff --git a/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift b/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift
index 6c0a8390f2c65ad407e77f058a0d30fd0ab6a20e..8206e136f89d0068432458ccac97d8ebe544c2da 100644
--- a/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift
+++ b/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift
@@ -3,8 +3,10 @@ import UIKit
 import Shared
 import Combine
 import XXModels
+import Defaults
 import Countries
 import Integration
+import NetworkMonitor
 import DependencyInjection
 
 typealias SearchSnapshot = NSDiffableDataSourceSnapshot<SearchSection, SearchItem>
@@ -18,6 +20,9 @@ struct SearchLeftViewState {
 
 final class SearchLeftViewModel {
     @Dependency var session: SessionType
+    @Dependency var networkMonitor: NetworkMonitoring
+
+    @KeyObject(.invitation, defaultValue: nil) var invitation: String?
 
     var hudPublisher: AnyPublisher<HUDStatus, Never> {
         hudSubject.eraseToAnyPublisher()
@@ -35,6 +40,29 @@ final class SearchLeftViewModel {
     private let successSubject = PassthroughSubject<Contact, Never>()
     private let hudSubject = CurrentValueSubject<HUDStatus, Never>(.none)
     private let stateSubject = CurrentValueSubject<SearchLeftViewState, Never>(.init())
+    private var networkCancellable = Set<AnyCancellable>()
+
+    func viewDidAppear() {
+        if let pendingInvitation = invitation {
+            invitation = nil
+            stateSubject.value.input = pendingInvitation
+            hudSubject.send(.onAction(Localized.Ud.Search.cancel))
+
+            networkCancellable.removeAll()
+
+            networkMonitor.statusPublisher
+                .first { $0 == .available }
+                .eraseToAnyPublisher()
+                .flatMap { _ in self.session.waitForNodes(timeout: 5) }
+                .sink {
+                    if case .failure(let error) = $0 {
+                        self.hudSubject.send(.error(.init(with: error)))
+                    }
+                } receiveValue: {
+                    self.didStartSearching()
+                }.store(in: &networkCancellable)
+        }
+    }
 
     func didEnterInput(_ string: String) {
         stateSubject.value.input = string
diff --git a/Sources/Shared/AutoGenerated/Assets.swift b/Sources/Shared/AutoGenerated/Assets.swift
index 6755de526a369e8245365d38a47984ea96a02e42..c55ff98183f5c8b9c3776a40a24bc8ddba91429b 100644
--- a/Sources/Shared/AutoGenerated/Assets.swift
+++ b/Sources/Shared/AutoGenerated/Assets.swift
@@ -70,6 +70,7 @@ public enum Asset {
   public static let menuRequests = ImageAsset(name: "menu_requests")
   public static let menuScan = ImageAsset(name: "menu_scan")
   public static let menuSettings = ImageAsset(name: "menu_settings")
+  public static let menuShare = ImageAsset(name: "menu_share")
   public static let onboardingBackground = ImageAsset(name: "onboarding_background")
   public static let onboardingBottomLogoStart = ImageAsset(name: "onboarding_bottom_logo_start")
   public static let onboardingEmail = ImageAsset(name: "onboarding_email")
diff --git a/Sources/Shared/AutoGenerated/Strings.swift b/Sources/Shared/AutoGenerated/Strings.swift
index 315babf8e14569c98f9ea0f2513962566f9bfef8..1640774e563ec20094d2d9df9fc77dd118cc3f56 100644
--- a/Sources/Shared/AutoGenerated/Strings.swift
+++ b/Sources/Shared/AutoGenerated/Strings.swift
@@ -633,6 +633,8 @@ public enum Localized {
     public static let contacts = Localized.tr("Localizable", "menu.contacts")
     /// Dashboard
     public static let dashboard = Localized.tr("Localizable", "menu.dashboard")
+    /// Join xx network
+    public static let join = Localized.tr("Localizable", "menu.join")
     /// Profile
     public static let profile = Localized.tr("Localizable", "menu.profile")
     /// Requests
@@ -641,6 +643,16 @@ public enum Localized {
     public static let scan = Localized.tr("Localizable", "menu.scan")
     /// Settings
     public static let settings = Localized.tr("Localizable", "menu.settings")
+    /// Share my profile
+    public static let share = Localized.tr("Localizable", "menu.share")
+    /// Hi, I'm using xx messenger, you can download it here:
+    /// https://invite.xx.network
+    /// 
+    /// And you can add me using this link:
+    /// %@
+    public static func shareContent(_ p1: Any) -> String {
+      return Localized.tr("Localizable", "menu.shareContent", String(describing: p1))
+    }
     /// Hello
     public static let title = Localized.tr("Localizable", "menu.title")
     /// Version %@
diff --git a/Sources/Shared/Resources/Assets.xcassets/AssetsMenu/menu_share.imageset/Contents.json b/Sources/Shared/Resources/Assets.xcassets/AssetsMenu/menu_share.imageset/Contents.json
new file mode 100644
index 0000000000000000000000000000000000000000..5c2f805eb3317d819659b5d73f14b6a1b249804f
--- /dev/null
+++ b/Sources/Shared/Resources/Assets.xcassets/AssetsMenu/menu_share.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+  "images" : [
+    {
+      "filename" : "Icon.pdf",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "preserves-vector-representation" : true
+  }
+}
diff --git a/Sources/Shared/Resources/Assets.xcassets/AssetsMenu/menu_share.imageset/Icon.pdf b/Sources/Shared/Resources/Assets.xcassets/AssetsMenu/menu_share.imageset/Icon.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..b09b053bb7c5bd064ae240eb8d69b92a81b85519
--- /dev/null
+++ b/Sources/Shared/Resources/Assets.xcassets/AssetsMenu/menu_share.imageset/Icon.pdf
@@ -0,0 +1,101 @@
+%PDF-1.7
+
+1 0 obj
+  << >>
+endobj
+
+2 0 obj
+  << /Length 3 0 R >>
+stream
+/DeviceRGB CS
+/DeviceRGB cs
+q
+1.000000 0.000000 -0.000000 1.000000 5.000000 4.000000 cm
+0.693500 0.711750 0.730000 scn
+12.599999 1.800547 m
+12.599999 4.501754 l
+12.599999 4.999001 13.002944 5.402100 13.500000 5.402100 c
+13.997056 5.402100 14.400000 4.999001 14.400000 4.501754 c
+14.400000 1.800547 l
+14.400000 0.807714 13.593665 0.000029 12.603939 0.000029 c
+1.796060 0.000029 l
+0.802609 0.000029 0.000000 0.804142 0.000000 1.800547 c
+0.000000 4.501754 l
+0.000000 4.999001 0.402944 5.402100 0.900000 5.402100 c
+1.397056 5.402100 1.800000 4.999001 1.800000 4.501754 c
+1.796060 1.800718 l
+12.599999 1.800547 l
+h
+f
+n
+Q
+q
+-1.000000 -0.000000 0.000000 -1.000000 15.648438 20.002563 cm
+0.693500 0.711750 0.730000 scn
+1.539240 4.081299 m
+2.545713 3.074440 l
+2.545713 11.492543 l
+2.545713 11.989956 2.945192 12.393188 3.445713 12.393188 c
+3.942770 12.393188 4.345713 11.990088 4.345713 11.492543 c
+4.345713 3.074440 l
+5.352188 4.081299 l
+5.705159 4.434405 6.273771 4.438073 6.627693 4.084015 c
+6.979165 3.732409 6.977091 3.160265 6.624980 2.808019 c
+4.084824 0.266890 l
+3.906826 0.088822 3.676712 0.001439 3.446377 0.001585 c
+3.215733 -0.000003 2.985826 0.087598 2.809317 0.264174 c
+2.807509 0.265984 0.266448 2.808019 0.266448 2.808019 c
+-0.086523 3.161125 -0.090189 3.729957 0.263733 4.084015 c
+0.615205 4.435622 1.187128 4.433546 1.539240 4.081299 c
+h
+f
+n
+Q
+
+endstream
+endobj
+
+3 0 obj
+  1353
+endobj
+
+4 0 obj
+  << /Annots []
+     /Type /Page
+     /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
+     /Resources 1 0 R
+     /Contents 2 0 R
+     /Parent 5 0 R
+  >>
+endobj
+
+5 0 obj
+  << /Kids [ 4 0 R ]
+     /Count 1
+     /Type /Pages
+  >>
+endobj
+
+6 0 obj
+  << /Pages 5 0 R
+     /Type /Catalog
+  >>
+endobj
+
+xref
+0 7
+0000000000 65535 f
+0000000010 00000 n
+0000000034 00000 n
+0000001443 00000 n
+0000001466 00000 n
+0000001639 00000 n
+0000001713 00000 n
+trailer
+<< /ID [ (some) (id) ]
+   /Root 6 0 R
+   /Size 7
+>>
+startxref
+1772
+%%EOF
\ No newline at end of file
diff --git a/Sources/Shared/Resources/en.lproj/Localizable.strings b/Sources/Shared/Resources/en.lproj/Localizable.strings
index 2b7263918c46d1868d27b5fe82ff5d21137786e9..32235ed0528a1881c6c513f4edece96ca47ce4b3 100644
--- a/Sources/Shared/Resources/en.lproj/Localizable.strings
+++ b/Sources/Shared/Resources/en.lproj/Localizable.strings
@@ -8,6 +8,10 @@
 = "Connections";
 "menu.requests"
 = "Requests";
+"menu.join"
+= "Join xx network";
+"menu.share"
+= "Share my profile";
 "menu.viewProfile"
 = "View Profile";
 "menu.profile"
@@ -22,6 +26,8 @@
 = "Build %@";
 "menu.version"
 = "Version %@";
+"menu.shareContent"
+= "Hi, I'm using xx messenger, you can download it here:\nhttps://invite.xx.network\n\nAnd you can add me using this link:\n%@";
 
 // ChatListFeature
 
diff --git a/Sources/Shared/Views/SearchComponent.swift b/Sources/Shared/Views/SearchComponent.swift
index 9608aad71aaa56a5da852516405d069837a703c5..b3d530991d687604af21ea311eca69c458566f32 100644
--- a/Sources/Shared/Views/SearchComponent.swift
+++ b/Sources/Shared/Views/SearchComponent.swift
@@ -115,6 +115,10 @@ public final class SearchComponent: UIView {
         }
     }
 
+    public func update(content: String) {
+        inputField.text = content
+    }
+
     public func update(placeholder: String) {
         inputField.attributedPlaceholder = NSAttributedString(
             string: placeholder,
diff --git a/Tests/AppTests/General/InvitationTests.swift b/Tests/AppTests/General/InvitationTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..146c885afab3c85686cc5f216c8e85ff851911b5
--- /dev/null
+++ b/Tests/AppTests/General/InvitationTests.swift
@@ -0,0 +1,21 @@
+import XCTest
+
+@testable import App
+
+final class AppDelegateTests: XCTestCase {
+    func test_invitationDeeplink() {
+        XCTAssertNil(
+            getUsernameFromInvitationDeepLink(URL(string: "http://messenger?invitation=john_doe")!)
+        )
+
+        XCTAssertNotEqual(
+            getUsernameFromInvitationDeepLink(URL(string: "xxnetwork://messenger?invitation=the_rock")!),
+            "john_doe"
+        )
+
+        XCTAssertEqual(
+            getUsernameFromInvitationDeepLink(URL(string: "xxnetwork://messenger?invitation=john_doe")!),
+            "john_doe"
+        )
+    }
+}