diff --git a/src/helper/p2pool.rs b/src/helper/p2pool.rs
index b67112d..5242c55 100644
--- a/src/helper/p2pool.rs
+++ b/src/helper/p2pool.rs
@@ -29,9 +29,11 @@ use crate::helper::signal_end;
 use crate::helper::sleep_end_loop;
 use crate::regex::P2POOL_REGEX;
 use crate::regex::contains_end_status;
+use crate::regex::contains_newchain_tip;
 use crate::regex::contains_statuscommand;
 use crate::regex::contains_yourhashrate;
 use crate::regex::contains_yourshare;
+use crate::regex::contains_zmq_failure;
 use crate::regex::estimated_hr;
 use crate::regex::nb_current_shares;
 use crate::{
@@ -222,13 +224,13 @@ impl Helper {
     ) {
         helper.lock().unwrap().p2pool.lock().unwrap().state = ProcessState::Middle;
 
-        let (args, api_path_local, api_path_network, api_path_pool) =
+        let (args, api_path_local, api_path_network, api_path_pool, api_path_p2p) =
             Self::build_p2pool_args_and_mutate_img(helper, state, path, backup_hosts);
 
         // Print arguments & user settings to console
         crate::disk::print_dash(&format!(
-            "P2Pool | Launch arguments: {:#?} | Local API Path: {:#?} | Network API Path: {:#?} | Pool API Path: {:#?}",
-            args, api_path_local, api_path_network, api_path_pool,
+            "P2Pool | Launch arguments: {:#?} | Local API Path: {:#?} | Network API Path: {:#?} | Pool API Path: {:#?} | P2P API Path {:#?}",
+            args, api_path_local, api_path_network, api_path_pool, api_path_p2p
         ));
 
         // Spawn watchdog thread
@@ -247,6 +249,7 @@ impl Helper {
                 api_path_local,
                 api_path_network,
                 api_path_pool,
+                api_path_p2p,
                 gupax_p2pool_api,
             );
         });
@@ -272,7 +275,7 @@ impl Helper {
         state: &P2pool,
         path: &Path,
         backup_hosts: Option<Vec<PoolNode>>,
-    ) -> (Vec<String>, PathBuf, PathBuf, PathBuf) {
+    ) -> (Vec<String>, PathBuf, PathBuf, PathBuf, PathBuf) {
         let mut args = Vec::with_capacity(500);
         let path = path.to_path_buf();
         let mut api_path = path;
@@ -447,10 +450,18 @@ impl Helper {
         let mut api_path_local = api_path.clone();
         let mut api_path_network = api_path.clone();
         let mut api_path_pool = api_path.clone();
+        let mut api_path_p2p = api_path.clone();
         api_path_local.push(P2POOL_API_PATH_LOCAL);
         api_path_network.push(P2POOL_API_PATH_NETWORK);
         api_path_pool.push(P2POOL_API_PATH_POOL);
-        (args, api_path_local, api_path_network, api_path_pool)
+        api_path_p2p.push(P2POOL_API_PATH_P2P);
+        (
+            args,
+            api_path_local,
+            api_path_network,
+            api_path_pool,
+            api_path_p2p,
+        )
     }
 
     #[cold]
@@ -469,6 +480,7 @@ impl Helper {
         api_path_local: std::path::PathBuf,
         api_path_network: std::path::PathBuf,
         api_path_pool: std::path::PathBuf,
+        api_path_p2p: std::path::PathBuf,
         gupax_p2pool_api: Arc<Mutex<GupaxP2poolApi>>,
     ) {
         // 1a. Create PTY
@@ -542,6 +554,26 @@ impl Helper {
                 ),
             }
         }
+        debug!("P2Pool | Cleaning old [p2p] API files...");
+        // Attempt to remove stale API file
+        match std::fs::remove_file(&api_path_p2p) {
+            Ok(_) => info!("P2Pool | Attempting to remove stale API file ... OK"),
+            Err(e) => warn!(
+                "P2Pool | Attempting to remove stale API file ... FAIL ... {}",
+                e
+            ),
+        }
+        // Attempt to create a default empty one.
+        if std::fs::File::create(&api_path_p2p).is_ok() {
+            let text = r#"{"connections":0,"incoming_connections":0,"peer_list_size":0,"peers":[],"uptime":0}"#;
+            match std::fs::write(&api_path_p2p, text) {
+                Ok(_) => info!("P2Pool | Creating default empty API file ... OK"),
+                Err(e) => warn!(
+                    "P2Pool | Creating default empty API file ... FAIL ... {}",
+                    e
+                ),
+            }
+        }
         let start = process.lock().unwrap().start;
 
         // Reset stats before loop
@@ -608,6 +640,20 @@ impl Helper {
                         PubP2poolApi::update_from_local(&mut pub_api_lock, local_api);
                     }
                 }
+                // Read [p2p] API
+                // allows to know if p2p is synced and connected to a Node.
+                debug!("P2Pool Watchdog | Attempting [p2p] API file read");
+                if let Ok(string) = Self::path_to_string(&api_path_p2p, ProcessName::P2pool) {
+                    // Deserialize
+                    if let Ok(p2p_api) = PrivP2PoolP2PApi::from_str(&string) {
+                        // Update the structs.
+                        PubP2poolApi::update_from_p2p(&mut pub_api_lock, p2p_api);
+                    }
+                }
+
+                // check if state must be changed based on local and p2p API
+                pub_api_lock.update_state(&mut process_lock);
+
                 // If more than 1 minute has passed, read the other API files.
                 let last_p2pool_request_expired =
                     last_p2pool_request.elapsed() >= Duration::from_secs(60);
@@ -746,7 +792,7 @@ pub struct PubP2poolApi {
     pub monero_difficulty: HumanNumber, // e.g: [15,000,000]
     pub monero_hashrate: HumanNumber,   // e.g: [1.000 GH/s]
     pub hash: String,                   // Current block hash
-    pub height: HumanNumber,
+    pub height: u32,
     pub reward: AtomicUnit,
     // Pool API
     pub p2pool_difficulty: HumanNumber,
@@ -763,6 +809,11 @@ pub struct PubP2poolApi {
     // from status
     pub sidechain_shares: u32,
     pub sidechain_ehr: f32,
+    // from height
+    pub synchronised: bool,
+    // from local/p2p
+    pub p2p_connected: u32,
+    pub node_connected: bool,
 }
 
 impl Default for PubP2poolApi {
@@ -801,7 +852,7 @@ impl PubP2poolApi {
             monero_difficulty: HumanNumber::unknown(),
             monero_hashrate: HumanNumber::unknown(),
             hash: String::from("???"),
-            height: HumanNumber::unknown(),
+            height: 0,
             reward: AtomicUnit::new(),
             p2pool_difficulty: HumanNumber::unknown(),
             p2pool_hashrate: HumanNumber::unknown(),
@@ -814,6 +865,9 @@ impl PubP2poolApi {
             user_monero_percent: HumanNumber::unknown(),
             sidechain_shares: 0,
             sidechain_ehr: 0.0,
+            p2p_connected: 0,
+            synchronised: false,
+            node_connected: false,
         }
     }
 
@@ -876,7 +930,7 @@ impl PubP2poolApi {
         // 2. Parse the full STDOUT
         let mut output_parse = output_parse.lock().unwrap();
         let (payouts_new, xmr_new) = Self::calc_payouts_and_xmr(&output_parse);
-        // Check for "SYNCHRONIZED" only if we aren't already.
+        // Check for "SYNCHRONIZED" only if we aren't already. Works at level 0 and above.
         if process.state == ProcessState::Syncing {
             // How many times the word was captured.
             let synchronized_captures = P2POOL_REGEX.synchronized.find_iter(&output_parse).count();
@@ -897,6 +951,15 @@ impl PubP2poolApi {
                 // just finding 1 instance of "SYNCHRONIZED".
                 process.state = ProcessState::Alive;
             }
+            // if the p2pool node was synced but is not anymore due to faulty monero node and is synced again, the status must be alive again
+            // required log level 2 minimum
+            if contains_newchain_tip(&output_parse) {
+                process.state = ProcessState::Alive;
+            }
+        }
+        // if the node is offline, p2pool can not function properly. Requires at least p2pool log level 1
+        if process.state == ProcessState::Alive && contains_zmq_failure(&output_parse) {
+            process.state = ProcessState::Syncing;
         }
 
         // 3. Throw away [output_parse]
@@ -976,6 +1039,15 @@ impl PubP2poolApi {
             ..std::mem::take(&mut *public)
         };
     }
+    // Mutate [PubP2poolApi] with data from a [PrivP2PoolP2PApi] and the process output.
+    pub(super) fn update_from_p2p(public: &mut Self, p2p: PrivP2PoolP2PApi) {
+        *public = Self {
+            p2p_connected: p2p.connections,
+            // 30 seconds before concluding the monero node connection is lost
+            node_connected: p2p.zmq_last_active < 30,
+            ..std::mem::take(&mut *public)
+        };
+    }
 
     // Mutate [PubP2poolApi] with data from a [PrivP2pool(Network|Pool)Api].
     pub(super) fn update_from_network_pool(
@@ -1033,7 +1105,7 @@ impl PubP2poolApi {
             monero_difficulty: HumanNumber::from_u64(monero_difficulty),
             monero_hashrate: HumanNumber::from_u64_to_gigahash_3_point(monero_hashrate),
             hash: net.hash,
-            height: HumanNumber::from_u32(net.height),
+            height: net.height,
             reward: AtomicUnit::from_u64(net.reward),
             p2pool_difficulty: HumanNumber::from_u64(p2pool_difficulty),
             p2pool_hashrate: HumanNumber::from_u64_to_megahash_3_point(p2pool_hashrate),
@@ -1047,6 +1119,14 @@ impl PubP2poolApi {
             ..std::mem::take(&mut *public)
         };
     }
+    /// Check if all conditions are met to be alive or if something is wrong
+    fn update_state(&self, process: &mut Process) {
+        if self.synchronised && self.node_connected && self.p2p_connected > 1 && self.height > 10 {
+            process.state = ProcessState::Alive;
+        } else {
+            process.state = ProcessState::Syncing;
+        }
+    }
 
     #[inline]
     pub fn calculate_share_or_block_time(hashrate: u64, difficulty: u64) -> HumanTime {
@@ -1273,3 +1353,35 @@ impl PoolStatistics {
         }
     }
 }
+//---------------------------------------------------------------------------------------------------- Private P2Pool "Network" API
+// This matches P2Pool's [local/p2p] JSON API file.
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub(super) struct PrivP2PoolP2PApi {
+    pub connections: u32,
+    pub zmq_last_active: u32,
+}
+
+impl Default for PrivP2PoolP2PApi {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl PrivP2PoolP2PApi {
+    fn new() -> Self {
+        Self {
+            connections: 0,
+            zmq_last_active: 0,
+        }
+    }
+
+    pub(super) fn from_str(string: &str) -> std::result::Result<Self, serde_json::Error> {
+        match serde_json::from_str::<Self>(string) {
+            Ok(a) => Ok(a),
+            Err(e) => {
+                warn!("P2Pool Network API | Could not deserialize API data: {}", e);
+                Err(e)
+            }
+        }
+    }
+}
diff --git a/src/helper/tests.rs b/src/helper/tests.rs
index b4309c9..9621bd5 100644
--- a/src/helper/tests.rs
+++ b/src/helper/tests.rs
@@ -25,6 +25,7 @@ mod test {
         p2pool::{PrivP2poolLocalApi, PrivP2poolNetworkApi},
         xvb::{priv_stats::RuntimeDonationLevel, priv_stats::RuntimeMode},
     };
+    use crate::human::HumanNumber;
     use crate::miscs::client;
 
     #[test]
@@ -308,7 +309,7 @@ Uptime         = 0h 2m 4s
         assert_eq!(p.monero_difficulty.to_string(), "300,000,000,000");
         assert_eq!(p.monero_hashrate.to_string(), "2.500 GH/s");
         assert_eq!(p.hash.to_string(), "asdf");
-        assert_eq!(p.height.to_string(), "1,234");
+        assert_eq!(HumanNumber::from_u32(p.height).to_string(), "1,234");
         assert_eq!(p.reward.to_u64(), 2345);
         assert_eq!(p.p2pool_difficulty.to_string(), "10,000,000");
         assert_eq!(p.p2pool_hashrate.to_string(), "1.000 MH/s");
diff --git a/src/utils/constants.rs b/src/utils/constants.rs
index afc5b6d..1787e8b 100644
--- a/src/utils/constants.rs
+++ b/src/utils/constants.rs
@@ -81,12 +81,16 @@ pub const P2POOL_API_PATH_LOCAL: &str = r"local\stratum";
 pub const P2POOL_API_PATH_NETWORK: &str = r"network\stats";
 #[cfg(target_os = "windows")]
 pub const P2POOL_API_PATH_POOL: &str = r"pool\stats";
+#[cfg(target_family = "windows")]
+pub const P2POOL_API_PATH_P2P: &str = r"local\p2p";
 #[cfg(target_family = "unix")]
 pub const P2POOL_API_PATH_LOCAL: &str = "local/stratum";
 #[cfg(target_family = "unix")]
 pub const P2POOL_API_PATH_NETWORK: &str = "network/stats";
 #[cfg(target_family = "unix")]
 pub const P2POOL_API_PATH_POOL: &str = "pool/stats";
+#[cfg(target_family = "unix")]
+pub const P2POOL_API_PATH_P2P: &str = "local/p2p";
 pub const XMRIG_API_SUMMARY_URI: &str = "1/summary"; // The default relative URI of XMRig's API summary
 // pub const XMRIG_API_CONFIG_URI: &str = "1/config"; // The default relative URI of XMRig's API config
 // todo allow user to change the port of the http api for xmrig and xmrig-proxy
diff --git a/src/utils/regex.rs b/src/utils/regex.rs
index 0a9da66..e25801b 100644
--- a/src/utils/regex.rs
+++ b/src/utils/regex.rs
@@ -277,6 +277,21 @@ pub fn contains_end_status(l: &str) -> bool {
     static LINE_SHARE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^Uptime         ").unwrap());
     LINE_SHARE.is_match(l)
 }
+// P2Pool
+/// if the node is disconnected
+/// this error will be present if log > 1 and Node is disconnected
+pub fn contains_zmq_failure(l: &str) -> bool {
+    static LINE_SHARE: Lazy<Regex> = Lazy::new(|| {
+        Regex::new(r"(p2pool with offline node: failed: error Error (empty response)|ZMQReader failed to connect to|P2Pool Couldn't restart ZMQ reader: exception Operation cannot be accomplished in current state)").unwrap()
+    });
+    LINE_SHARE.is_match(l)
+}
+/// a way to detect that p2pool is alive
+pub fn contains_newchain_tip(l: &str) -> bool {
+    static LINE_SHARE: Lazy<Regex> = Lazy::new(|| Regex::new(r"new chain tip").unwrap());
+    LINE_SHARE.is_match(l)
+}
+
 //---------------------------------------------------------------------------------------------------- TEST
 #[cfg(test)]
 mod test {