diff --git a/bindings/group.go b/bindings/group.go
index ecd8ca664da3a97f00294c712b40408787b15d0b..e277ca505b81a14e89a6d3f9101f10c8eb2f0ac4 100644
--- a/bindings/group.go
+++ b/bindings/group.go
@@ -17,68 +17,9 @@ import (
 	gs "gitlab.com/elixxir/client/groupChat/groupStore"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
-	"sync"
 	"time"
 )
 
-////////////////////////////////////////////////////////////////////////////////
-// Group Singleton Tracker                                                    //
-////////////////////////////////////////////////////////////////////////////////
-
-// groupTrackerSingleton is used to track Group objects so that they can be
-// referenced by ID back over the bindings.
-var groupTrackerSingleton = &groupTracker{
-	tracked: make(map[int]*Group),
-	count:   0,
-}
-
-// groupTracker is a singleton used to keep track of extant Group objects,
-// preventing race conditions created by passing it over the bindings.
-type groupTracker struct {
-	tracked map[int]*Group
-	count   int
-	mux     sync.RWMutex
-}
-
-// make create a Group from a groupStore.Group, assigns it a unique ID, and
-// adds it to the groupChatTracker.
-func (ut *groupTracker) make(g gs.Group) *Group {
-	ut.mux.Lock()
-	defer ut.mux.Unlock()
-
-	utID := ut.count
-	ut.count++
-
-	ut.tracked[utID] = &Group{
-		g:  g,
-		id: utID,
-	}
-
-	return ut.tracked[utID]
-}
-
-// get a Group from the groupChatTracker given its ID.
-func (ut *groupTracker) get(id int) (*Group, error) {
-	ut.mux.RLock()
-	defer ut.mux.RUnlock()
-
-	g, exist := ut.tracked[id]
-	if !exist {
-		return nil, errors.Errorf(
-			"Cannot get Group for ID %d, does not exist", id)
-	}
-
-	return g, nil
-}
-
-// delete removes a Group from the groupTracker.
-func (ut *groupTracker) delete(id int) {
-	ut.mux.Lock()
-	defer ut.mux.Unlock()
-
-	delete(ut.tracked, id)
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Group Chat                                                                 //
 ////////////////////////////////////////////////////////////////////////////////
@@ -105,8 +46,7 @@ func NewGroupChat(e2eID int,
 
 	// Construct a wrapper for the request callback
 	requestCb := func(g gs.Group) {
-		newGroup := groupTrackerSingleton.make(g)
-		requestFunc.Callback(newGroup)
+		requestFunc.Callback(&Group{g: g})
 	}
 
 	// Construct a group chat manager
@@ -213,22 +153,14 @@ func (g *GroupChat) ResendRequest(groupId []byte) ([]byte, error) {
 // with the same trackedGroupId.
 //
 // Parameters:
-//  - trackedGroupId - the ID to retrieve the Group object within the backend's
-//    tracking system. This is received by GroupRequest.Callback.
-func (g *GroupChat) JoinGroup(trackedGroupId int) error {
-	// Retrieve group from singleton
-	grp, err := groupTrackerSingleton.get(trackedGroupId)
+//  - serializedGroupData - the result of calling Group.Serialize() on
+//    any Group object returned over the bindings
+func (g *GroupChat) JoinGroup(serializedGroupData []byte) error {
+	grp, err := gs.DeserializeGroup(serializedGroupData)
 	if err != nil {
 		return err
 	}
-
-	// Join group
-	err = g.m.JoinGroup(grp.g)
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return g.m.JoinGroup(grp)
 }
 
 // LeaveGroup deletes a group so a user no longer has access.
@@ -310,7 +242,7 @@ func (g *GroupChat) GetGroup(groupId []byte) (*Group, error) {
 	}
 
 	// Add to tracker and return Group object
-	return groupTrackerSingleton.make(grp), nil
+	return &Group{g: grp}, nil
 }
 
 // NumGroups returns the number of groups the user is a part of.
@@ -325,8 +257,7 @@ func (g *GroupChat) NumGroups() int {
 // Group structure contains the identifying and membership information of a
 // group chat.
 type Group struct {
-	g  gs.Group
-	id int
+	g gs.Group
 }
 
 // GetName returns the name set by the user for the group.
@@ -339,12 +270,6 @@ func (g *Group) GetID() []byte {
 	return g.g.ID.Bytes()
 }
 
-// GetTrackedID returns the tracked ID of the Group object. This is used by the
-// backend tracker.
-func (g *Group) GetTrackedID() int {
-	return g.id
-}
-
 // GetInitMessage returns initial message sent with the group request.
 func (g *Group) GetInitMessage() []byte {
 	return g.g.InitMessage
@@ -404,7 +329,7 @@ func (g *Group) Serialize() []byte {
 // GroupRequest is a bindings-layer interface that handles a group reception.
 //
 // Parameters:
-//  - trackedGroupId - a bindings layer Group object.
+//  - g - a bindings layer Group object.
 type GroupRequest interface {
 	Callback(g *Group)
 }