diff --git a/go.mod b/go.mod
index f21603b83ac9b3690e24da59e1d1422e6d75884c..ae90af06d721b0967cf76df4b618a3d930784aaa 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
 	github.com/stretchr/testify v1.6.1 // indirect
 	gitlab.com/elixxir/crypto v0.0.0-20200811195343-de268a55c7c4
 	gitlab.com/elixxir/primitives v0.0.0-20200812191102-31c01f08b4dc
-	gitlab.com/xx_network/comms v0.0.0-20200818182121-732dd75b1947
+	gitlab.com/xx_network/comms v0.0.0-20200825213037-f58fa7c0a641
 	gitlab.com/xx_network/crypto v0.0.0-20200806235322-ede3c15881ce
 	gitlab.com/xx_network/primitives v0.0.0-20200812183720-516a65a4a9b2
 	gitlab.com/xx_network/ring v0.0.2
diff --git a/go.sum b/go.sum
index b36c5f3947dd7b483c245ee4eebe97d5f665a56f..2b1a4aaed895fe46a81eb4eced878dac2158968b 100644
--- a/go.sum
+++ b/go.sum
@@ -71,8 +71,8 @@ gitlab.com/elixxir/primitives v0.0.0-20200805174810-86b366d1dd2d/go.mod h1:tzdFF
 gitlab.com/elixxir/primitives v0.0.0-20200812191102-31c01f08b4dc h1:43innow2sbJLflB73gwS8gg1meInFXNA1LGYeeDQ6lw=
 gitlab.com/elixxir/primitives v0.0.0-20200812191102-31c01f08b4dc/go.mod h1:pJx2DZk9s8vVMnLN7x0hIPngDjbNSdOP6kk3RLlRxHg=
 gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw=
-gitlab.com/xx_network/comms v0.0.0-20200818182121-732dd75b1947 h1:g0k4nP0o/6qkh09F9d/Fy7Ys93fkyZU+kK71JviLdMg=
-gitlab.com/xx_network/comms v0.0.0-20200818182121-732dd75b1947/go.mod h1:idLzPGYig57XE7xuU93OlIF9s6NgSJj7OArQvsd5DjY=
+gitlab.com/xx_network/comms v0.0.0-20200825213037-f58fa7c0a641 h1:d48S6FLIUJa1RMm5E20P/kbM8upHmfVgoc9G4+TDjhk=
+gitlab.com/xx_network/comms v0.0.0-20200825213037-f58fa7c0a641/go.mod h1:idLzPGYig57XE7xuU93OlIF9s6NgSJj7OArQvsd5DjY=
 gitlab.com/xx_network/crypto v0.0.0-20200806202113-978fa1984bbf/go.mod h1:i0df/q6dDCBiscgD51fMoS2U2TBrm6LcyN822JmB5Tw=
 gitlab.com/xx_network/crypto v0.0.0-20200806235322-ede3c15881ce h1:gypNBUl2guESEv4MDgH+miwYqR4jPoWM8dLt2Zs5gIs=
 gitlab.com/xx_network/crypto v0.0.0-20200806235322-ede3c15881ce/go.mod h1:i0df/q6dDCBiscgD51fMoS2U2TBrm6LcyN822JmB5Tw=
diff --git a/network/instance.go b/network/instance.go
index 557548946fc15ea94ff3756b5a6622b6b582aab5..0115b42007912463e4d3ab39fe1e5c4247e9b3c9 100644
--- a/network/instance.go
+++ b/network/instance.go
@@ -16,6 +16,7 @@ import (
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	ds "gitlab.com/elixxir/comms/network/dataStructures"
 	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/primitives/states"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/crypto/signature"
 	"gitlab.com/xx_network/primitives/id"
@@ -36,6 +37,9 @@ type Instance struct {
 
 	ipOverride *ds.IpOverrideList
 
+	// Network Health
+	networkHealth chan Heartbeat
+
 	// Waiting Rounds
 	waitingRounds *ds.WaitingRounds
 
@@ -49,6 +53,17 @@ type Instance struct {
 	removeGateway chan *id.ID
 }
 
+// Object used to signal information about the network health
+type Heartbeat struct {
+	hasWaitingRound bool
+	isRoundComplete bool
+}
+
+// Register AddNode channel with Instance
+func (i *Instance) SetNetworkHealthChan(c chan Heartbeat) {
+	i.networkHealth = c
+}
+
 // Register AddNode channel with Instance
 func (i *Instance) SetAddNodeChan(c chan ndf.Node) {
 	i.addNode = c
@@ -212,17 +227,19 @@ func (i *Instance) UpdatePartialNdf(m *pb.NDF) error {
 		i.comm.RemoveHost(nid)
 
 		// Send events into Node Listener
-		select {
-		case i.removeNode <- nid:
-		default:
-			jww.WARN.Printf("Unable to send RemoveNode event for id %s", nid.String())
-		}
-		gwId := nid.DeepCopy()
-		gwId.SetType(id.Gateway)
-		select {
-		case i.removeGateway <- nid:
-		default:
-			jww.WARN.Printf("Unable to send RemoveGateway event for id %s", nid.String())
+		if i.removeNode != nil && i.removeGateway != nil {
+			select {
+			case i.removeNode <- nid:
+			default:
+				jww.WARN.Printf("Unable to send RemoveNode event for id %s", nid.String())
+			}
+			gwId := nid.DeepCopy()
+			gwId.SetType(id.Gateway)
+			select {
+			case i.removeGateway <- nid:
+			default:
+				jww.WARN.Printf("Unable to send RemoveGateway event for id %s", nid.String())
+			}
 		}
 	}
 
@@ -277,17 +294,19 @@ func (i *Instance) UpdateFullNdf(m *pb.NDF) error {
 		i.comm.RemoveHost(nid)
 
 		// Send events into Node Listener
-		select {
-		case i.removeNode <- nid:
-		default:
-			jww.WARN.Printf("Unable to send RemoveNode event for id %s", nid.String())
-		}
-		gwId := nid.DeepCopy()
-		gwId.SetType(id.Gateway)
-		select {
-		case i.removeGateway <- nid:
-		default:
-			jww.WARN.Printf("Unable to send RemoveGateway event for id %s", nid.String())
+		if i.removeNode != nil && i.removeGateway != nil {
+			select {
+			case i.removeNode <- nid:
+			default:
+				jww.WARN.Printf("Unable to send RemoveNode event for id %s", nid.String())
+			}
+			gwId := nid.DeepCopy()
+			gwId.SetType(id.Gateway)
+			select {
+			case i.removeGateway <- nid:
+			default:
+				jww.WARN.Printf("Unable to send RemoveGateway event for id %s", nid.String())
+			}
 		}
 	}
 
@@ -336,6 +355,37 @@ func getBannedNodes(old []ndf.Node, new []ndf.Node) ([]*id.ID, error) {
 	return rmNodes, nil
 }
 
+// Pluralized version of RoundUpdate used by Client
+func (i *Instance) RoundUpdates(rounds []*pb.RoundInfo) error {
+	// Keep track of whether one of the rounds is completed
+	isRoundComplete := false
+	for _, round := range rounds {
+		if states.Round(round.State) == states.COMPLETED {
+			isRoundComplete = true
+		}
+
+		// Send the RoundUpdate
+		err := i.RoundUpdate(round)
+		if err != nil {
+			return err
+		}
+	}
+
+	// Send a Heartbeat over the networkHealth channel
+	if i.networkHealth != nil {
+		select {
+		case i.networkHealth <- Heartbeat{
+			hasWaitingRound: i.GetWaitingRounds().Len() > 0,
+			isRoundComplete: isRoundComplete,
+		}:
+		default:
+			jww.WARN.Printf("Unable to send NetworkHealth event")
+		}
+	}
+
+	return nil
+}
+
 // Add a round to the round and update buffer
 func (i *Instance) RoundUpdate(info *pb.RoundInfo) error {
 	perm, success := i.comm.GetHost(&id.Permissioning)
@@ -366,7 +416,6 @@ func (i *Instance) RoundUpdate(info *pb.RoundInfo) error {
 
 	i.events.TriggerRoundEvent(info)
 	i.waitingRounds.Insert(info)
-
 	return nil
 }
 
@@ -485,11 +534,14 @@ func (i *Instance) updateConns(def *ndf.NetworkDefinition, isGateway, isNode boo
 			host, ok := i.comm.GetHost(gwid)
 			if !ok {
 				// Send events into Node Listener
-				select {
-				case i.addGateway <- gateway:
-				default:
-					jww.WARN.Printf("Unable to send AddGateway event for id %s", gwid.String())
+				if i.addGateway != nil {
+					select {
+					case i.addGateway <- gateway:
+					default:
+						jww.WARN.Printf("Unable to send AddGateway event for id %s", gwid.String())
+					}
 				}
+
 				// Check if gateway ID collides with an existing hard coded ID
 				if id.CollidesWithHardCodedID(gwid) {
 					return errors.Errorf("Gateway ID invalid, collides with a "+
@@ -518,10 +570,12 @@ func (i *Instance) updateConns(def *ndf.NetworkDefinition, isGateway, isNode boo
 			host, ok := i.comm.GetHost(nid)
 			if !ok {
 				// Send events into Node Listener
-				select {
-				case i.addNode <- node:
-				default:
-					jww.WARN.Printf("Unable to send AddNode event for id %s", nid.String())
+				if i.addNode != nil {
+					select {
+					case i.addNode <- node:
+					default:
+						jww.WARN.Printf("Unable to send AddNode event for id %s", nid.String())
+					}
 				}
 
 				// Check if isNode ID collides with an existing hard coded ID