diff --git a/plugins/analysis/client/plugin.go b/plugins/analysis/client/plugin.go
index 6fd3f07c4771964506bf9712aadd72542dc93f32..369702a4ba73de559b1dbd69eac2dab54deacd81 100644
--- a/plugins/analysis/client/plugin.go
+++ b/plugins/analysis/client/plugin.go
@@ -1,6 +1,7 @@
 package client
 
 import (
+	"encoding/hex"
 	"net"
 	"time"
 
@@ -57,19 +58,19 @@ func Run(plugin *node.Plugin) {
 func getEventDispatchers(conn *network.ManagedConnection) *EventDispatchers {
 	return &EventDispatchers{
 		AddNode: func(nodeId []byte) {
-			log.Debugw("AddNode", "nodeId", nodeId)
+			log.Debugw("AddNode", "nodeId", hex.EncodeToString(nodeId))
 			_, _ = conn.Write((&addnode.Packet{NodeId: nodeId}).Marshal())
 		},
 		RemoveNode: func(nodeId []byte) {
-			log.Debugw("RemoveNode", "nodeId", nodeId)
+			log.Debugw("RemoveNode", "nodeId", hex.EncodeToString(nodeId))
 			_, _ = conn.Write((&removenode.Packet{NodeId: nodeId}).Marshal())
 		},
 		ConnectNodes: func(sourceId []byte, targetId []byte) {
-			log.Debugw("ConnectNodes", "sourceId", sourceId, "targetId", targetId)
+			log.Debugw("ConnectNodes", "sourceId", hex.EncodeToString(sourceId), "targetId", hex.EncodeToString(targetId))
 			_, _ = conn.Write((&connectnodes.Packet{SourceId: sourceId, TargetId: targetId}).Marshal())
 		},
 		DisconnectNodes: func(sourceId []byte, targetId []byte) {
-			log.Debugw("DisconnectNodes", "sourceId", sourceId, "targetId", targetId)
+			log.Debugw("DisconnectNodes", "sourceId", hex.EncodeToString(sourceId), "targetId", hex.EncodeToString(targetId))
 			_, _ = conn.Write((&disconnectnodes.Packet{SourceId: sourceId, TargetId: targetId}).Marshal())
 		},
 	}
@@ -80,7 +81,9 @@ func reportCurrentStatus(eventDispatchers *EventDispatchers) {
 		eventDispatchers.AddNode(local.GetInstance().ID().Bytes())
 	}
 
+	reportKnownPeers(eventDispatchers)
 	reportChosenNeighbors(eventDispatchers)
+	reportAcceptedNeighbors(eventDispatchers)
 }
 
 func setupHooks(plugin *node.Plugin, conn *network.ManagedConnection, eventDispatchers *EventDispatchers) {
@@ -123,6 +126,7 @@ func setupHooks(plugin *node.Plugin, conn *network.ManagedConnection, eventDispa
 	var onClose *events.Closure
 	onClose = events.NewClosure(func() {
 		discover.Events.PeerDiscovered.Detach(onDiscoverPeer)
+		discover.Events.PeerDeleted.Detach(onDeletePeer)
 		selection.Events.IncomingPeering.Detach(onAddAcceptedNeighbor)
 		selection.Events.OutgoingPeering.Detach(onAddChosenNeighbor)
 		selection.Events.Dropped.Detach(onRemoveNeighbor)
@@ -132,15 +136,32 @@ func setupHooks(plugin *node.Plugin, conn *network.ManagedConnection, eventDispa
 	conn.Events.Close.Attach(onClose)
 }
 
+func reportKnownPeers(dispatchers *EventDispatchers) {
+	if autopeering.Discovery != nil {
+		for _, peer := range autopeering.Discovery.GetVerifiedPeers() {
+			dispatchers.AddNode(peer.ID().Bytes())
+		}
+	}
+}
+
 func reportChosenNeighbors(dispatchers *EventDispatchers) {
 	if autopeering.Selection != nil {
 		for _, chosenNeighbor := range autopeering.Selection.GetOutgoingNeighbors() {
-			dispatchers.AddNode(chosenNeighbor.ID().Bytes())
+			//dispatchers.AddNode(chosenNeighbor.ID().Bytes())
 			dispatchers.ConnectNodes(local.GetInstance().ID().Bytes(), chosenNeighbor.ID().Bytes())
 		}
 	}
 }
 
+func reportAcceptedNeighbors(dispatchers *EventDispatchers) {
+	if autopeering.Selection != nil {
+		for _, acceptedNeighbor := range autopeering.Selection.GetIncomingNeighbors() {
+			//dispatchers.AddNode(acceptedNeighbor.ID().Bytes())
+			dispatchers.ConnectNodes(local.GetInstance().ID().Bytes(), acceptedNeighbor.ID().Bytes())
+		}
+	}
+}
+
 func keepConnectionAlive(conn *network.ManagedConnection, shutdownSignal <-chan struct{}) bool {
 	go conn.Read(make([]byte, 1))
 
diff --git a/plugins/analysis/webinterface/httpserver/index.go b/plugins/analysis/webinterface/httpserver/index.go
index 15fea5145b07fc8ef35403cf0a69e6507635a3d7..e4009b1ded8855b564884c8c2067beca9eecc71e 100644
--- a/plugins/analysis/webinterface/httpserver/index.go
+++ b/plugins/analysis/webinterface/httpserver/index.go
@@ -7,15 +7,84 @@ import (
 
 func index(w http.ResponseWriter, r *http.Request) {
 	fmt.Fprintf(w, `<head>
-  <style> body { margin: 0; } </style>
+  <style> 
+  body {
+    text-align: center;
+    margin: 0;
+    overflow: hidden;
+  }
+
+  #nfo{
+    position:absolute;
+    right: 0;
+    padding:10px;	
+  }
+
+  #knownPeers{
+    position:relative;
+    margin:0;
+    font-size:14px;
+    font-weight: bold;
+    text-align:right;
+    color:#aaa;
+  }
+
+  #avgNeighbors{
+    position:relative;
+    margin:0;
+    font-size:13px;
+    text-align:right;
+    color:grey;
+  }
+
+  #graphc {
+    position: absolute;
+    top: 0px;
+    right: 0px;
+    margin:0;
+    right: 0px;
+  }
+
+  #nodeId{
+    position:relative;
+    margin:0;
+    padding:5px 0;
+    font-size:13px;
+    font-weight: bold;
+    text-align:right;
+    color:#aaa; 
+  }
+  
+  #nodestat{
+    position:relative;
+    margin:0;
+    font-size:12px;
+    text-align:right;
+    color:grey; 
+  }
+  
+  #in, #out{
+    margin:0;
+    padding: 3px 0;
+  }
+
+  </style>
 
   <script src="https://unpkg.com/3d-force-graph"></script>
   <!--<script src="../../dist/3d-force-graph.js"></script>-->
 </head>
 
 <body>
-  <div id="3d-graph"></div>
-
+  <div id="graphc"></div>
+  <div id="nfo">
+    <p id="knownPeers"></p>
+    <p id="avgNeighbors"></p>
+    <div id="nodeId"></div>
+    <div id="nodestat">
+      <p id="in"></p>
+      <p id="out"></p>
+  </div>
+  
   <script>
 	var socket = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/datastream");
 
@@ -26,7 +95,8 @@ func index(w http.ResponseWriter, r *http.Request) {
 	};
 
 	socket.onmessage = function (e) {
-        console.log("Len: ", data.nodes.length);
+        document.getElementById("knownPeers").innerHTML = "Known peers: " + data.nodes.length;
+        document.getElementById("avgNeighbors").innerHTML = "Average neighbors: " + parseFloat(((data.links.length * 2) / data.nodes.length).toFixed(2));
         switch (e.data[0]) {
           case "_":
             // do nothing - its just a ping
@@ -43,13 +113,13 @@ func index(w http.ResponseWriter, r *http.Request) {
           break;
 
           case "C":
-             connectNodes(e.data.substr(1, 64), e.data.substr(65, 128));
-             console.log("Connect nodes:",e.data.substr(1, 64), " - ", e.data.substr(65, 128));
+             connectNodes(e.data.substr(1, 64), e.data.substr(65, 64));
+             console.log("Connect nodes:",e.data.substr(1, 64), " - ", e.data.substr(65, 64));
           break;
 
           case "c":
-             disconnectNodes(e.data.substr(1, 64), e.data.substr(65, 128));
-             console.log("Disconnect nodes:",e.data.substr(1, 64), " - ", e.data.substr(65, 128));
+             disconnectNodes(e.data.substr(1, 64), e.data.substr(65, 64));
+             console.log("Disconnect nodes:",e.data.substr(1, 64), " - ", e.data.substr(65, 64));
           break;
 
           case "O":
@@ -73,14 +143,45 @@ func index(w http.ResponseWriter, r *http.Request) {
 
     var existingLinks = {};
 
-    const elem = document.getElementById("3d-graph");
+    let highlightNodes = [];
+    let highlightLinks = [];
+    let highlightLink = null;
+
+    const elem = document.getElementById("graphc");
+
+      //.onNodeHover(node => elem.style.cursor = node ? 'pointer' : null)
 
     const Graph = ForceGraph3D()(elem)
+        .graphData(data)
         .enableNodeDrag(false)
-        .onNodeHover(node => elem.style.cursor = node ? 'pointer' : null)
-        .onNodeClick(removeNodeX)
-        .nodeColor(node => node.online ? 'rgba(0,255,0,1)' : 'rgba(255,255,255,1)')
-        .graphData(data);
+        .onNodeClick(showNodeStat)
+        .nodeColor(node => highlightNodes.indexOf(node) === -1 ? 'rgba(0,255,255,0.6)' : 'rgb(255,0,0,1)')
+        .linkWidth(link => highlightLinks.indexOf(link) === -1 ? 1 : 4)
+        .linkDirectionalParticles(link => highlightLinks.indexOf(link) === -1 ? 0 : 4)
+        .linkDirectionalParticleWidth(4)
+        .onNodeHover(node => {
+          // no state change
+          if ((!node && !highlightNodes.length) || (highlightNodes.length === 1 && highlightNodes[0] === node)) return;
+
+          highlightNodes = node ? [node] : [];
+
+          highlightLinks = [];
+          clearNodeStat();
+          if (node != null) {
+            highlightLinks = data.links.filter(l => (l.target.id == node.id) || (l.source.id == node.id));
+            showNodeStat(node);
+          }
+          updateHighlight();
+        })
+        .onLinkHover(link => {
+          // no state change
+          if ((!link && !highlightLinks.length) || (highlightLinks.length === 1 && highlightLinks[0] === link)) return;
+
+          highlightLinks = [link];
+          highlightNodes = link ? [link.source, link.target] : [];
+
+          updateHighlight();
+        });
 
     var updateRequired = true;
 
@@ -92,6 +193,14 @@ func index(w http.ResponseWriter, r *http.Request) {
       }
     }, 500)
 
+    function updateHighlight() {
+      // trigger update of highlighted objects in scene
+      Graph
+        .nodeColor(Graph.nodeColor())
+        .linkWidth(Graph.linkWidth())
+        .linkDirectionalParticles(Graph.linkDirectionalParticles());
+    }
+
     updateGraph = function() {
       updateRequired = true;
     };
@@ -144,6 +253,7 @@ func index(w http.ResponseWriter, r *http.Request) {
         }
         nodesById[sourceNodeId].online = true;
         nodesById[targetNodeId].online = true;
+        existingLinks[sourceNodeId + targetNodeId] = true
         data.links = [...data.links, { source: sourceNodeId, target: targetNodeId }];
 
         updateGraph();
@@ -158,10 +268,28 @@ func index(w http.ResponseWriter, r *http.Request) {
       updateGraph();
     }
 
-    function removeNodeX(node) {
-      if (node.id in nodesById) {
-        removeNode(node.id);
-      }
+    function clearNodeStat() {
+      document.getElementById("nodeId").innerHTML = ""
+      document.getElementById("in").innerHTML = ""
+      document.getElementById("out").innerHTML = ""
+    }
+
+    function showNodeStat(node) {
+      document.getElementById("nodeId").innerHTML = "ID: " + node.id.substr(0, 16);
+
+      var incoming = data.links.filter(l => (l.target.id == node.id));
+      document.getElementById("in").innerHTML = "IN: " + incoming.length + "<br>";
+      incoming.forEach(function(link){
+        document.getElementById("in").innerHTML += link.source.id.substr(0, 16) + " &rarr; NODE <br>";
+      });
+
+      var outgoing = data.links.filter(l => (l.source.id == node.id));
+      document.getElementById("out").innerHTML = "OUT: " + outgoing.length + "<br>";
+      outgoing.forEach(function(link){
+        document.getElementById("out").innerHTML += "NODE &rarr; " + link.target.id.substr(0, 16) + "<br>";
+      });
+
+      nodesById[node.id].color = 'rgba(0,255,255,1)'
     }
   </script>
 </body>`)
diff --git a/plugins/analysis/webinterface/recordedevents/recorded_events.go b/plugins/analysis/webinterface/recordedevents/recorded_events.go
index ae6a5597c0eb6376bdb5f856d7d8077116a45398..398ca97082bbbd35db53d22f38ec76eeb1a1ad2b 100644
--- a/plugins/analysis/webinterface/recordedevents/recorded_events.go
+++ b/plugins/analysis/webinterface/recordedevents/recorded_events.go
@@ -16,6 +16,7 @@ var lock sync.Mutex
 
 func Configure(plugin *node.Plugin) {
 	server.Events.AddNode.Attach(events.NewClosure(func(nodeId string) {
+		plugin.Node.Logger.Debugw("AddNode", "nodeID", nodeId)
 		lock.Lock()
 		defer lock.Unlock()
 
@@ -25,6 +26,7 @@ func Configure(plugin *node.Plugin) {
 	}))
 
 	server.Events.RemoveNode.Attach(events.NewClosure(func(nodeId string) {
+		plugin.Node.Logger.Debugw("RemoveNode", "nodeID", nodeId)
 		lock.Lock()
 		defer lock.Unlock()
 
@@ -32,6 +34,7 @@ func Configure(plugin *node.Plugin) {
 	}))
 
 	server.Events.NodeOnline.Attach(events.NewClosure(func(nodeId string) {
+		plugin.Node.Logger.Debugw("NodeOnline", "nodeID", nodeId)
 		lock.Lock()
 		defer lock.Unlock()
 
@@ -39,6 +42,7 @@ func Configure(plugin *node.Plugin) {
 	}))
 
 	server.Events.NodeOffline.Attach(events.NewClosure(func(nodeId string) {
+		plugin.Node.Logger.Debugw("NodeOffline", "nodeID", nodeId)
 		lock.Lock()
 		defer lock.Unlock()
 
@@ -46,6 +50,7 @@ func Configure(plugin *node.Plugin) {
 	}))
 
 	server.Events.ConnectNodes.Attach(events.NewClosure(func(sourceId string, targetId string) {
+		plugin.Node.Logger.Debugw("ConnectNodes", "sourceID", sourceId, "targetId", targetId)
 		lock.Lock()
 		defer lock.Unlock()
 
@@ -59,6 +64,7 @@ func Configure(plugin *node.Plugin) {
 	}))
 
 	server.Events.DisconnectNodes.Attach(events.NewClosure(func(sourceId string, targetId string) {
+		plugin.Node.Logger.Debugw("DisconnectNodes", "sourceID", sourceId, "targetId", targetId)
 		lock.Lock()
 		defer lock.Unlock()