diff --git a/include/opendht/dht_proxy_server.h b/include/opendht/dht_proxy_server.h
index ac4cb248535f09e865abcdf778ddd28b55f9582f..42519882fc5ae2bb139a69dd5afb41c04aff3cca 100644
--- a/include/opendht/dht_proxy_server.h
+++ b/include/opendht/dht_proxy_server.h
@@ -65,6 +65,7 @@ using RequestStatus = restinio::request_handling_status_t;
 struct ProxyServerConfig {
     in_port_t port {8000};
     std::string pushServer {};
+    std::string bundleId {};
     std::string persistStatePath {};
     dht::crypto::Identity identity {};
 };
@@ -275,6 +276,7 @@ private:
 
 #ifdef OPENDHT_PUSH_NOTIFICATIONS
     PushType getTypeFromString(const std::string& type);
+    const std::string& getDefaultTopic(PushType type);
     /**
      * Subscribe to push notifications for an iOS or Android device.
      * Method: SUBSCRIBE "/{InfoHash: .*}"
@@ -419,6 +421,7 @@ private:
     mutable std::atomic<time_point> lastStatsReset_ {time_point::min()};
 
     std::string pushServer_;
+    std::string bundleId_;
 
 #ifdef OPENDHT_PUSH_NOTIFICATIONS
     struct Listener {
diff --git a/src/dht_proxy_server.cpp b/src/dht_proxy_server.cpp
index 56d3ec65946b40105594bf817956f9dbca98ca7e..d20f49c7c9155a3a56d4d6d5889c40be63b230d4 100644
--- a/src/dht_proxy_server.cpp
+++ b/src/dht_proxy_server.cpp
@@ -205,7 +205,8 @@ DhtProxyServer::DhtProxyServer(const std::shared_ptr<DhtRunner>& dht,
         dht_(dht), persistPath_(config.persistStatePath), logger_(logger),
         printStatsTimer_(std::make_unique<asio::steady_timer>(*ioContext_, 3s)),
         connListener_(std::make_shared<ConnectionListener>(std::bind(&DhtProxyServer::onConnectionClosed, this, std::placeholders::_1))),
-        pushServer_(config.pushServer)
+        pushServer_(config.pushServer),
+        bundleId_(config.bundleId)
 {
     if (not dht_)
         throw std::invalid_argument("A DHT instance must be provided");
@@ -760,6 +761,20 @@ DhtProxyServer::getTypeFromString(const std::string& type) {
     return PushType::None;
 }
 
+const std::string&
+DhtProxyServer::getDefaultTopic(PushType type) {
+    if (bundleId_.empty()) {
+        return {};
+    }
+    if (type == PushType::iOSLegacy) {
+        return bundleId_  + ".voip";
+    }
+    if (type == PushType::iOS) {
+        return bundleId_;
+    }
+    return {};
+}
+
 RequestStatus
 DhtProxyServer::subscribe(restinio::request_handle_t request,
                           restinio::router::route_params_t params)
@@ -788,6 +803,9 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
         }
         auto type = getTypeFromString(root["platform"].asString());
         auto topic = root["topic"].asString();
+        if (topic.empty()) {
+            topic = getDefaultTopic(type);
+        }
         auto clientId = root["client_id"].asString();
         auto sessionId = root["session_id"].asString();
 
@@ -1188,6 +1206,9 @@ DhtProxyServer::put(restinio::request_handle_t request,
                         pput.pushToken = pushToken;
                         pput.clientId = clientId;
                         pput.type = getTypeFromString(platform);
+                        if (topic.empty()) {
+                            topic = getDefaultTopic(pput.type);
+                        }
                         pput.topic = topic;
                         pput.sessionCtx = std::make_shared<PushSessionContext>(sessionId);
                         // notify push listen expire
diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp
index 3fde3d8533d177b199fafba9e092ee3ffd8874ab..69dd1ffa62ec6d52a2a47d4623d829a38e9002bc 100644
--- a/tools/dhtnode.cpp
+++ b/tools/dhtnode.cpp
@@ -43,7 +43,7 @@ void print_version() {
 }
 
 void print_usage() {
-    std::cout << "Usage: dhtnode [-v [-l logfile]] [-i] [-d] [-n network_id] [-p local_port] [-b bootstrap_host[:port]] [--proxyserver local_port] [--proxyserverssl local_port]" << std::endl << std::endl;
+    std::cout << "Usage: dhtnode [-v [-l logfile]] [-i] [-d] [-n network_id] [-p local_port] [-b bootstrap_host[:port]] [--proxyserver local_port] [--proxyserverssl local_port] [--bundleid bundleid]" << std::endl << std::endl;
     print_info();
 }
 
@@ -550,6 +550,7 @@ main(int argc, char **argv)
 #ifdef OPENDHT_PROXY_SERVER
             ProxyServerConfig serverConfig;
             serverConfig.pushServer = params.pushserver;
+            serverConfig.bundleId = params.bundle_id;
             if (params.proxyserverssl and params.proxy_id.first and params.proxy_id.second){
                 serverConfig.identity = params.proxy_id;
                 serverConfig.port = params.proxyserverssl;
diff --git a/tools/tools_common.h b/tools/tools_common.h
index c123617204e6f07abe17105fc15ed2f41b3d6db2..889cd055fe4232b36d8c2c6ba41251c7989a66f7 100644
--- a/tools/tools_common.h
+++ b/tools/tools_common.h
@@ -133,6 +133,7 @@ struct dht_params {
     std::string proxyclient {};
     std::string pushserver {};
     std::string devicekey {};
+    std::string bundle_id {};
     std::string persist_path {};
     dht::crypto::Identity id {};
     dht::crypto::Identity proxy_id {};
@@ -229,6 +230,7 @@ static const constexpr struct option long_options[] = {
     {"proxyclient",             required_argument, nullptr, 'C'},
     {"pushserver",              required_argument, nullptr, 'y'},
     {"devicekey",               required_argument, nullptr, 'z'},
+    {"bundleid",                required_argument, nullptr, 'u'},
     {"version",                 no_argument      , nullptr, 'V'},
     {nullptr,                   0                , nullptr,  0}
 };
@@ -336,6 +338,9 @@ parseArgs(int argc, char **argv) {
         case 'k':
             privkey = optarg;
             break;
+        case 'u':
+            params.bundle_id = optarg;
+            break;
         case 'K':
             proxy_privkey = optarg;
             break;