diff --git a/bindings/group.go b/bindings/group.go
index 343bbe7758240f28cfdb124907e0505a3b9cab4e..af9e5d204a941f945bb869aa975a8966699e4a78 100644
--- a/bindings/group.go
+++ b/bindings/group.go
@@ -104,14 +104,14 @@ func (g *GroupChat) LeaveGroup(groupIdBytes []byte) error {
 
 // Send sends the message to the specified group. Returns the round the messages
 // were sent on.
-func (g *GroupChat) Send(groupIdBytes, message []byte) (int64, error) {
+func (g *GroupChat) Send(groupIdBytes, message []byte) (*GroupSendReport, error) {
 	groupID, err := id.Unmarshal(groupIdBytes)
 	if err != nil {
-		return 0, errors.Errorf("Failed to unmarshal group ID: %+v", err)
+		return nil, errors.Errorf("Failed to unmarshal group ID: %+v", err)
 	}
 
-	round, err := g.m.Send(groupID, message)
-	return int64(round), err
+	round, timestamp, err := g.m.Send(groupID, message)
+	return &GroupSendReport{round, timestamp}, err
 }
 
 // GetGroups returns an IdList containing a list of group IDs that the user is a
@@ -141,6 +141,10 @@ func (g *GroupChat) NumGroups() int {
 	return g.m.NumGroups()
 }
 
+////
+// NewGroupReport Structure
+////
+
 // NewGroupReport is returned when creating a new group and contains the ID of
 // the group, a list of rounds that the group requests were sent on, and the
 // status of the send.
@@ -170,6 +174,28 @@ func (ngr *NewGroupReport) GetStatus() int {
 	return int(ngr.status)
 }
 
+////
+// NewGroupReport Structure
+////
+
+// GroupSendReport is returned when sending a group message. It contains the
+// round ID sent on and the timestamp of the send.
+type GroupSendReport struct {
+	roundID   id.Round
+	timestamp time.Time
+}
+
+// GetRoundID returns the ID of the round that the send occurred on.
+func (gsr *GroupSendReport) GetRoundID() int64 {
+	return int64(gsr.roundID)
+}
+
+// GetTimestampMS returns the timestamp of the send in milliseconds.
+func (gsr *GroupSendReport) GetTimestampMS() int64 {
+	ts := uint64(gsr.timestamp.UnixNano()) / uint64(time.Millisecond)
+	return int64(ts)
+}
+
 ////
 // Group Structure
 ////
diff --git a/cmd/group.go b/cmd/group.go
index ca457c65b84f68f87e784d3cec98bc956b32094c..b973fb5c7f2b7addcb12a26c2a59b7b4c1524c22 100644
--- a/cmd/group.go
+++ b/cmd/group.go
@@ -218,12 +218,13 @@ func sendGroup(groupIdString string, msg []byte, gm *groupChat.Manager) {
 
 	jww.INFO.Printf("Sending to group %s message %q", groupID, msg)
 
-	rid, err := gm.Send(groupID, msg)
+	rid, timestamp, err := gm.Send(groupID, msg)
 	if err != nil {
 		jww.FATAL.Panicf("Sending message to group %s: %+v", groupID, err)
 	}
 
-	jww.INFO.Printf("Sent to group %s on round %d", groupID, rid)
+	jww.INFO.Printf("Sent to group %s on round %d at %s",
+		groupID, rid, timestamp)
 	fmt.Printf("Sent message %q to group.\n", msg)
 }
 
diff --git a/groupChat/group.go b/groupChat/group.go
index 5d67d19f1e52f80cf1628f2deece083b4d8f4568..8878a62cdf750823bd4c886fbfbfdca1ac81c13d 100644
--- a/groupChat/group.go
+++ b/groupChat/group.go
@@ -22,6 +22,7 @@ package groupChat
 import (
 	gs "gitlab.com/elixxir/client/groupChat/groupStore"
 	"gitlab.com/xx_network/primitives/id"
+	"time"
 )
 
 // GroupChat is used to send and receive cMix messages to/from multiple users.
@@ -49,8 +50,9 @@ type GroupChat interface {
 	LeaveGroup(groupID *id.ID) error
 
 	// Send sends a message to all GroupChat members using Client.SendManyCMIX.
-	// The send fails if the message is too long.
-	Send(groupID *id.ID, message []byte) (id.Round, error)
+	// The send fails if the message is too long. Returns the ID of the round
+	// sent on and the timestamp of the message send.
+	Send(groupID *id.ID, message []byte) (id.Round, time.Time, error)
 
 	// GetGroups returns a list of all registered GroupChat IDs.
 	GetGroups() []*id.ID
diff --git a/groupChat/send.go b/groupChat/send.go
index ca25cfe604145224d12fd0651b7a0404375baee0..0ac72527b60e535b07fd553f4d7a2b386e578d32 100644
--- a/groupChat/send.go
+++ b/groupChat/send.go
@@ -36,36 +36,38 @@ const (
 
 // Send sends a message to all group members using Client.SendManyCMIX. The
 // send fails if the message is too long.
-func (m *Manager) Send(groupID *id.ID, message []byte) (id.Round, error) {
+func (m *Manager) Send(groupID *id.ID, message []byte) (id.Round, time.Time,
+	error) {
+	timeNow := netTime.Now()
 
 	// Create a cMix message for each group member
-	messages, err := m.createMessages(groupID, message)
+	messages, err := m.createMessages(groupID, message, timeNow)
 	if err != nil {
-		return 0, errors.Errorf(newCmixMsgErr, err)
+		return 0, time.Time{}, errors.Errorf(newCmixMsgErr, err)
 	}
 
 	rid, _, err := m.net.SendManyCMIX(messages, params.GetDefaultCMIX())
 	if err != nil {
-		return 0, errors.Errorf(sendManyCmixErr, m.gs.GetUser().ID, groupID, err)
+		return 0, time.Time{},
+			errors.Errorf(sendManyCmixErr, m.gs.GetUser().ID, groupID, err)
 	}
 
 	jww.DEBUG.Printf("Sent message to group %s.", groupID)
 
-	return rid, nil
+	return rid, timeNow, nil
 }
 
 // createMessages generates a list of cMix messages and a list of corresponding
 // recipient IDs.
-func (m *Manager) createMessages(groupID *id.ID, msg []byte) (
-	map[id.ID]format.Message, error) {
-	timeNow := netTime.Now()
+func (m *Manager) createMessages(groupID *id.ID, msg []byte,
+	timestamp time.Time) (map[id.ID]format.Message, error) {
 
 	g, exists := m.gs.Get(groupID)
 	if !exists {
 		return map[id.ID]format.Message{}, errors.Errorf(newNoGroupErr, groupID)
 	}
 
-	return m.newMessages(g, msg, timeNow)
+	return m.newMessages(g, msg, timestamp)
 }
 
 // newMessages is a private function that allows the passing in of a timestamp
diff --git a/groupChat/send_test.go b/groupChat/send_test.go
index e9f794185429d91e544c8861cbb15660fa73ad56..395ffc3ee9e3b640b38e88e0b2e11331d9e8036d 100644
--- a/groupChat/send_test.go
+++ b/groupChat/send_test.go
@@ -29,7 +29,7 @@ func TestManager_Send(t *testing.T) {
 	message := []byte("Group chat message.")
 	sender := m.gs.GetUser().DeepCopy()
 
-	_, err := m.Send(g.ID, message)
+	_, _, err := m.Send(g.ID, message)
 	if err != nil {
 		t.Errorf("Send() returned an error: %+v", err)
 	}
@@ -109,7 +109,7 @@ func TestManager_Send_CmixMessageError(t *testing.T) {
 	expectedErr := strings.SplitN(newCmixMsgErr, "%", 2)[0]
 
 	// Send message
-	_, err := m.Send(g.ID, make([]byte, 400))
+	_, _, err := m.Send(g.ID, make([]byte, 400))
 	if err == nil || !strings.Contains(err.Error(), expectedErr) {
 		t.Errorf("Send() failed to return the expected error."+
 			"\nexpected: %s\nreceived: %+v", expectedErr, err)
@@ -124,7 +124,7 @@ func TestManager_Send_SendManyCMIXError(t *testing.T) {
 	expectedErr := strings.SplitN(sendManyCmixErr, "%", 2)[0]
 
 	// Send message
-	_, err := m.Send(g.ID, []byte("message"))
+	_, _, err := m.Send(g.ID, []byte("message"))
 	if err == nil || !strings.Contains(err.Error(), expectedErr) {
 		t.Errorf("Send() failed to return the expected error."+
 			"\nexpected: %s\nreceived: %+v", expectedErr, err)
@@ -144,7 +144,7 @@ func TestManager_createMessages(t *testing.T) {
 
 	message := []byte("Test group message.")
 	sender := m.gs.GetUser()
-	messages, err := m.createMessages(g.ID, message)
+	messages, err := m.createMessages(g.ID, message, netTime.Now())
 	if err != nil {
 		t.Errorf("createMessages() returned an error: %+v", err)
 	}
@@ -204,7 +204,8 @@ func TestManager_createMessages_InvalidGroupIdError(t *testing.T) {
 	m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t)
 
 	// Read message and make sure the error is expected
-	_, err := m.createMessages(id.NewIdFromString("invalidID", id.Group, t), nil)
+	_, err := m.createMessages(
+		id.NewIdFromString("invalidID", id.Group, t), nil, time.Time{})
 	if err == nil || !strings.Contains(err.Error(), expectedErr) {
 		t.Errorf("createMessages() did not return the expected error."+
 			"\nexpected: %s\nreceived: %+v", expectedErr, err)