diff --git a/channels/emoji.go b/channels/emoji.go
index f97d50889ccb3f931ee33b22f970b5b8747b9465..d65844745e2c81ea549a962a81999fefc09e7214 100644
--- a/channels/emoji.go
+++ b/channels/emoji.go
@@ -1,6 +1,22 @@
 package channels
 
+import (
+	"github.com/forPelevin/gomoji"
+	"github.com/pkg/errors"
+)
+
+var InvalidReaction = errors.New("The reaction is not valid, " +
+	"it must be a single emoji")
+
 // ValidateReaction checks that the reaction only contains a single Emoji
 func ValidateReaction(reaction string) error {
+	if len(gomoji.RemoveEmojis(reaction)) > 0 {
+		return InvalidReaction
+	}
+
+	if len(gomoji.FindAll(reaction)) != 1 {
+		return InvalidReaction
+	}
 
+	return nil
 }
diff --git a/channels/eventModel.go b/channels/eventModel.go
index 08eb972610026dfd8770aabe55fa5f0f01e078ca..93841ba39764e6fe9e608070f1fda363c781e0dc 100644
--- a/channels/eventModel.go
+++ b/channels/eventModel.go
@@ -36,7 +36,7 @@ type EventModel interface {
 		round rounds.Round)
 	ReceiveReaction(ChannelID *id.ID, MessageID cryptoChannel.MessageID,
 		ReactionTo cryptoChannel.MessageID, SenderUsername string,
-		Reaction []byte, timestamp time.Time, lease time.Duration,
+		Reaction string, timestamp time.Time, lease time.Duration,
 		round rounds.Round)
 
 	//unimplemented
@@ -67,7 +67,7 @@ func initEvents(model EventModel) *events {
 	//set up default message types
 	e.registered[Text] = e.receiveTextMessage
 	e.registered[AdminText] = e.receiveTextMessage
-	e.registered[Reaction] =
+	e.registered[Reaction] = e.receiveReaction
 	return e
 }
 
@@ -178,22 +178,25 @@ func (e *events) receiveReaction(ChannelID *id.ID,
 		return
 	}
 
+	//check that the reaction is a single emoji and ignore if it isn't
+	if err := ValidateReaction(react.Reaction); err != nil {
+		jww.ERROR.Printf("Failed process reaction %s from %s on channel "+
+			"%s, type %s, ts: %s, lease: %s, round: %d, due to malformed "+
+			"reaction (%s), ignoring reaction",
+			MessageID, SenderUsername, ChannelID, messageType, timestamp, lease,
+			round.ID, err)
+	}
+
 	if react.ReactionMessageID != nil && len(react.ReactionMessageID) == cryptoChannel.MessageIDLen {
 		var reactTo cryptoChannel.MessageID
-		copy(replyTo[:], react.ReactionMessageID)
-		e.model.ReceiveReply(ChannelID, MessageID, replyTo, SenderUsername, txt.Text,
-			timestamp, lease, round)
-		return
-
+		copy(reactTo[:], react.ReactionMessageID)
+		e.model.ReceiveReaction(ChannelID, MessageID, reactTo, SenderUsername,
+			react.Reaction, timestamp, lease, round)
 	} else {
-		jww.ERROR.Printf("Failed process reply to for message %s from %s on "+
-			"channel %s, type %s, ts: %s, lease: %s, round: %d, returning "+
-			"without reply",
+		jww.ERROR.Printf("Failed process reaction %s from %s on channel "+
+			"%s, type %s, ts: %s, lease: %s, round: %d, reacting to "+
+			"invalid message, ignoring reaction",
 			MessageID, SenderUsername, ChannelID, messageType, timestamp, lease,
 			round.ID)
 	}
 }
-
-e.model.ReceiveMessage(ChannelID, MessageID, SenderUsername, txt.Text,
-timestamp, lease, round)
-}
\ No newline at end of file
diff --git a/channels/joinedChannel.go b/channels/joinedChannel.go
index 81c34bb4884fab649b68c69f95e833c648947797..0496298d6136b771a1cd53b2342ef180bafb4e2f 100644
--- a/channels/joinedChannel.go
+++ b/channels/joinedChannel.go
@@ -48,11 +48,14 @@ func (m *manager) storeUnsafe() error {
 
 // loadChannels loads all currently joined channels from disk and registers
 // them for message reception
-func (m *manager) loadChannels() map[*id.ID]*joinedChannel {
+func (m *manager) loadChannels() {
 
 	obj, err := m.kv.Get(joinedChannelsKey,
 		joinedChannelsVersion)
-	if err != nil {
+	if !m.kv.Exists(err) {
+		m.channels = make(map[*id.ID]*joinedChannel)
+		return
+	} else if err != nil {
 		jww.FATAL.Panicf("Failed to load channels %+v", err)
 	}
 
@@ -72,7 +75,8 @@ func (m *manager) loadChannels() map[*id.ID]*joinedChannel {
 		}
 		chMap[chList[i]] = jc
 	}
-	return chMap
+
+	m.channels = chMap
 }
 
 //addChannel Adds a channel
diff --git a/channels/manager.go b/channels/manager.go
index bf8f820b671f9dfa4d4fc83bb753eff56a599b28..ebad0194c14b4bece68862b8a26746e33620459e 100644
--- a/channels/manager.go
+++ b/channels/manager.go
@@ -22,11 +22,30 @@ type manager struct {
 
 	//Events model
 	events
+
+	// make the function used to create broadcasts be a pointer so it
+	// can be replaced in tests
 	broadcastMaker broadcast.NewBroadcastChannelFunc
 }
 
-func NewManager() {
+func NewManager(kv *versioned.KV, client broadcast.Client,
+	rng *fastRNG.StreamGenerator, name NameService) Manager {
+
+	//prefix the kv with the username so multiple can be run
+	kv = kv.Prefix(name.GetUsername())
+
+	m := manager{
+		kv:             kv,
+		client:         client,
+		rng:            rng,
+		name:           name,
+		events:         events{},
+		broadcastMaker: broadcast.NewBroadcastChannel,
+	}
+
+	m.loadChannels()
 
+	return &m
 }
 
 func (m *manager) JoinChannel(channel cryptoBroadcast.Channel) error {
diff --git a/channels/send.go b/channels/send.go
index 34dfeef454c1fb1484741553ddf30ae38915d76d..86b34441aabd3e6a3d9a657cad2a177ae542b07d 100644
--- a/channels/send.go
+++ b/channels/send.go
@@ -1,7 +1,6 @@
 package channels
 
 import (
-	"github.com/forPelevin/gomoji"
 	"gitlab.com/elixxir/client/broadcast"
 	"gitlab.com/elixxir/client/cmix"
 	cryptoChannel "gitlab.com/elixxir/crypto/channel"
@@ -17,9 +16,9 @@ const (
 	cmixChannelReactionVersion = 0
 )
 
-func (m *manager) SendGeneric(channelID *id.ID, msg []byte, validUntil time.Duration,
-	messageType MessageType, params cmix.CMIXParams) (cryptoChannel.MessageID,
-	id.Round, ephemeral.Id, error) {
+func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType,
+	msg []byte, validUntil time.Duration, params cmix.CMIXParams) (
+	cryptoChannel.MessageID, id.Round, ephemeral.Id, error) {
 
 	//find the channel
 	ch, err := m.getChannel(channelID)
@@ -160,7 +159,7 @@ func (m *manager) SendMessage(channelID *id.ID, msg string,
 		return cryptoChannel.MessageID{}, 0, ephemeral.Id{}, err
 	}
 
-	return m.SendGeneric(channelID, txtMarshaled, validUntil, Text, params)
+	return m.SendGeneric(channelID, Text, txtMarshaled, validUntil, params)
 }
 
 func (m *manager) SendReply(channelID *id.ID, msg string,
@@ -178,7 +177,7 @@ func (m *manager) SendReply(channelID *id.ID, msg string,
 		return cryptoChannel.MessageID{}, 0, ephemeral.Id{}, err
 	}
 
-	return m.SendGeneric(channelID, txtMarshaled, validUntil, Text, params)
+	return m.SendGeneric(channelID, Text, txtMarshaled, validUntil, params)
 }
 
 func (m *manager) SendReaction(channelID *id.ID, reaction string,
@@ -186,20 +185,20 @@ func (m *manager) SendReaction(channelID *id.ID, reaction string,
 	params cmix.CMIXParams) (cryptoChannel.MessageID, id.Round, ephemeral.Id,
 	error) {
 
-	if len(reaction) != 1 {
-		return error
+	if err := ValidateReaction(reaction); err != nil {
+		return cryptoChannel.MessageID{}, 0, ephemeral.Id{}, err
 	}
 
-	txt := &CMIXChannelReaction{
+	react := &CMIXChannelReaction{
 		Version:           cmixChannelReactionVersion,
 		Reaction:          reaction,
 		ReactionMessageID: replyTo[:],
 	}
 
-	txtMarshaled, err := proto.Marshal(txt)
+	reactMarshaled, err := proto.Marshal(react)
 	if err != nil {
 		return cryptoChannel.MessageID{}, 0, ephemeral.Id{}, err
 	}
 
-	return m.SendGeneric(channelID, txtMarshaled, validUntil, Text, params)
+	return m.SendGeneric(channelID, Reaction, reactMarshaled, validUntil, params)
 }
diff --git a/channels/text.pb.go b/channels/text.pb.go
index ebada41edb208d4e5534f55a96831dedd407bd06..20dcb07ee9307c6d66aeaa3b5b5f118fc96d439b 100644
--- a/channels/text.pb.go
+++ b/channels/text.pb.go
@@ -96,7 +96,7 @@ type CMIXChannelReaction struct {
 	unknownFields protoimpl.UnknownFields
 
 	Version           uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
-	Reaction          uint32 `protobuf:"varint,2,opt,name=reaction,proto3" json:"reaction,omitempty"`
+	Reaction          string `protobuf:"bytes,2,opt,name=reaction,proto3" json:"reaction,omitempty"`
 	ReactionMessageID []byte `protobuf:"bytes,3,opt,name=reactionMessageID,proto3" json:"reactionMessageID,omitempty"`
 }
 
@@ -139,11 +139,11 @@ func (x *CMIXChannelReaction) GetVersion() uint32 {
 	return 0
 }
 
-func (x *CMIXChannelReaction) GetReaction() uint32 {
+func (x *CMIXChannelReaction) GetReaction() string {
 	if x != nil {
 		return x.Reaction
 	}
-	return 0
+	return ""
 }
 
 func (x *CMIXChannelReaction) GetReactionMessageID() []byte {
@@ -167,7 +167,7 @@ var file_text_proto_rawDesc = []byte{
 	0x43, 0x4d, 0x49, 0x58, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x61, 0x63, 0x74,
 	0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01,
 	0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a,
-	0x08, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x08, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
 	0x08, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x11, 0x72, 0x65, 0x61,
 	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x03,
 	0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65,
diff --git a/channels/text.proto b/channels/text.proto
index 4e1ad86791428f0d64e92b5bbb1d35d7b02567c4..c2d15310a23b0f293af9f3f2cad7e07332269290 100644
--- a/channels/text.proto
+++ b/channels/text.proto
@@ -18,6 +18,6 @@ message CMIXChannelText {
 
 message CMIXChannelReaction {
   uint32 version = 1;
-  uint32 reaction = 2;
+  string reaction = 2;
   bytes reactionMessageID = 3;
 }
\ No newline at end of file