diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java
index c68f7b662513be4804cfbabc8eee086ad6b6205d..c37c267251932db3b62f57ef021f300ad7dfbe81 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java
@@ -10,6 +10,7 @@ import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.identity.IdentityManager;
 import org.briarproject.bramble.api.identity.LocalAuthor;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.sync.Group;
 import org.briarproject.bramble.api.sync.Group.Visibility;
 import org.briarproject.bramble.api.sync.GroupId;
@@ -28,6 +29,8 @@ import java.util.Map;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
 
+import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID;
+import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_VERSION;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID;
 import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
 import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE;
@@ -45,6 +48,7 @@ abstract class AbstractProtocolEngine<S extends Session>
 	protected final PrivateGroupFactory privateGroupFactory;
 	protected final MessageTracker messageTracker;
 
+	private final ClientVersioningManager clientVersioningManager;
 	private final GroupMessageFactory groupMessageFactory;
 	private final IdentityManager identityManager;
 	private final MessageParser messageParser;
@@ -52,6 +56,7 @@ abstract class AbstractProtocolEngine<S extends Session>
 	private final Clock clock;
 
 	AbstractProtocolEngine(DatabaseComponent db, ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
 			PrivateGroupManager privateGroupManager,
 			PrivateGroupFactory privateGroupFactory,
 			GroupMessageFactory groupMessageFactory,
@@ -60,6 +65,7 @@ abstract class AbstractProtocolEngine<S extends Session>
 			Clock clock) {
 		this.db = db;
 		this.clientHelper = clientHelper;
+		this.clientVersioningManager = clientVersioningManager;
 		this.privateGroupManager = privateGroupManager;
 		this.privateGroupFactory = privateGroupFactory;
 		this.groupMessageFactory = groupMessageFactory;
@@ -90,10 +96,14 @@ abstract class AbstractProtocolEngine<S extends Session>
 		return expected != null && dependency.equals(expected);
 	}
 
-	void setPrivateGroupVisibility(Transaction txn, S session, Visibility v)
-			throws DbException, FormatException {
+	void setPrivateGroupVisibility(Transaction txn, S session,
+			Visibility preferred) throws DbException, FormatException {
+		// Apply min of preferred visibility and client's visibility
 		ContactId contactId = getContactId(txn, session.getContactGroupId());
-		db.setGroupVisibility(txn, contactId, session.getPrivateGroupId(), v);
+		Visibility client = clientVersioningManager.getClientVisibility(txn,
+				contactId, CLIENT_ID, CLIENT_VERSION);
+		Visibility min = Visibility.min(preferred, client);
+		db.setGroupVisibility(txn, contactId, session.getPrivateGroupId(), min);
 	}
 
 	Message sendInviteMessage(Transaction txn, S session,
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java
index ec5315a6d07745b2552156a99905b306889d6c43..62030a09b79b546c6c31128be4440fc10c694197 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java
@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.db.DbException;
 import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.identity.IdentityManager;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.system.Clock;
 import org.briarproject.briar.api.client.MessageTracker;
@@ -36,15 +37,16 @@ import static org.briarproject.briar.privategroup.invitation.CreatorState.START;
 class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> {
 
 	CreatorProtocolEngine(DatabaseComponent db, ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
 			PrivateGroupManager privateGroupManager,
 			PrivateGroupFactory privateGroupFactory,
 			GroupMessageFactory groupMessageFactory,
 			IdentityManager identityManager, MessageParser messageParser,
 			MessageEncoder messageEncoder, MessageTracker messageTracker,
 			Clock clock) {
-		super(db, clientHelper, privateGroupManager, privateGroupFactory,
-				groupMessageFactory, identityManager, messageParser,
-				messageEncoder, messageTracker, clock);
+		super(db, clientHelper, clientVersioningManager, privateGroupManager,
+				privateGroupFactory, groupMessageFactory, identityManager,
+				messageParser, messageEncoder, messageTracker, clock);
 	}
 
 	@Override
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorState.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorState.java
index 4afe89c4d8319b410f1ab4be1b945446e2db30a0..6fe69a08c9227bf9e9433813aa9c354a6fa2a70b 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorState.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorState.java
@@ -2,19 +2,30 @@ package org.briarproject.briar.privategroup.invitation;
 
 import org.briarproject.bramble.api.FormatException;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.bramble.api.sync.Group.Visibility;
 
 import javax.annotation.concurrent.Immutable;
 
+import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
+import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
+
 @Immutable
 @NotNullByDefault
 enum CreatorState implements State {
 
-	START(0), INVITED(1), JOINED(2), LEFT(3), DISSOLVED(4), ERROR(5);
+	START(0, INVISIBLE),
+	INVITED(1, INVISIBLE),
+	JOINED(2, SHARED),
+	LEFT(3, INVISIBLE),
+	DISSOLVED(4, INVISIBLE),
+	ERROR(5, INVISIBLE);
 
 	private final int value;
+	private final Visibility visibility;
 
-	CreatorState(int value) {
+	CreatorState(int value, Visibility visibility) {
 		this.value = value;
+		this.visibility = visibility;
 	}
 
 	@Override
@@ -22,6 +33,11 @@ enum CreatorState implements State {
 		return value;
 	}
 
+	@Override
+	public Visibility getVisibility() {
+		return visibility;
+	}
+
 	static CreatorState fromValue(int value) throws FormatException {
 		for (CreatorState s : values()) if (s.value == value) return s;
 		throw new FormatException();
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java
index a9a6ef0929eadae2009d368e7bb51c8c9ecfff75..90c0fcd29935080e3bd6ed89405ae7ce74cd95b2 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java
@@ -15,6 +15,7 @@ interface GroupInvitationConstants {
 	String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
 
 	// Session keys
+	String SESSION_KEY_IS_SESSION = "isSession";
 	String SESSION_KEY_SESSION_ID = "sessionId";
 	String SESSION_KEY_PRIVATE_GROUP_ID = "privateGroupId";
 	String SESSION_KEY_LAST_LOCAL_MESSAGE_ID = "lastLocalMessageId";
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java
index 5ae9a3f81bb5cf2535e1585fa42ecbd9ab6e07f3..6275fad7039712b96ea80ab3a5ad6fbd6dbbda4c 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java
@@ -16,7 +16,10 @@ import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.identity.Author;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.Client;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
+import org.briarproject.bramble.api.sync.ClientVersioningManager.ClientVersioningHook;
 import org.briarproject.bramble.api.sync.Group;
+import org.briarproject.bramble.api.sync.Group.Visibility;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.sync.MessageId;
@@ -36,15 +39,17 @@ import org.briarproject.briar.client.ConversationClientImpl;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.logging.Logger;
 
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
-import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
+import static java.util.logging.Level.INFO;
 import static org.briarproject.briar.privategroup.invitation.CreatorState.START;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID;
 import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
@@ -59,8 +64,12 @@ import static org.briarproject.briar.privategroup.invitation.Role.PEER;
 @NotNullByDefault
 class GroupInvitationManagerImpl extends ConversationClientImpl
 		implements GroupInvitationManager, Client, ContactHook,
-		PrivateGroupHook {
+		PrivateGroupHook, ClientVersioningHook {
 
+	private static final Logger LOG =
+			Logger.getLogger(GroupInvitationManagerImpl.class.getName());
+
+	private final ClientVersioningManager clientVersioningManager;
 	private final ContactGroupFactory contactGroupFactory;
 	private final PrivateGroupFactory privateGroupFactory;
 	private final PrivateGroupManager privateGroupManager;
@@ -73,8 +82,9 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
 
 	@Inject
 	GroupInvitationManagerImpl(DatabaseComponent db,
-			ClientHelper clientHelper, MetadataParser metadataParser,
-			MessageTracker messageTracker,
+			ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
+			MetadataParser metadataParser, MessageTracker messageTracker,
 			ContactGroupFactory contactGroupFactory,
 			PrivateGroupFactory privateGroupFactory,
 			PrivateGroupManager privateGroupManager,
@@ -82,6 +92,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
 			SessionEncoder sessionEncoder,
 			ProtocolEngineFactory engineFactory) {
 		super(db, clientHelper, metadataParser, messageTracker);
+		this.clientVersioningManager = clientVersioningManager;
 		this.contactGroupFactory = contactGroupFactory;
 		this.privateGroupFactory = privateGroupFactory;
 		this.privateGroupManager = privateGroupManager;
@@ -110,7 +121,11 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
 		Group g = getContactGroup(c);
 		// Store the group and share it with the contact
 		db.addGroup(txn, g);
-		db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED);
+		Visibility client = clientVersioningManager.getClientVisibility(txn,
+				c.getId(), CLIENT_ID, CLIENT_VERSION);
+		if (LOG.isLoggable(INFO))
+			LOG.info("Applying visibility " + client + " to new contact group");
+		db.setGroupVisibility(txn, c.getId(), g.getId(), client);
 		// Attach the contact ID to the group
 		BdfDictionary meta = new BdfDictionary();
 		meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt());
@@ -565,6 +580,72 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
 		}
 	}
 
+	@Override
+	public void onClientVisibilityChanging(Transaction txn, Contact c,
+			Visibility v) throws DbException {
+		// Apply the client's visibility to the contact group
+		if (LOG.isLoggable(INFO))
+			LOG.info("Applying visibility " + v + " to contact group");
+		Group g = getContactGroup(c);
+		db.setGroupVisibility(txn, c.getId(), g.getId(), v);
+	}
+
+	ClientVersioningHook getPrivateGroupClientVersioningHook() {
+		return this::onPrivateGroupClientVisibilityChanging;
+	}
+
+	private void onPrivateGroupClientVisibilityChanging(Transaction txn,
+			Contact c, Visibility client) throws DbException {
+		try {
+			Collection<Group> shareables =
+					db.getGroups(txn, PrivateGroupManager.CLIENT_ID,
+							PrivateGroupManager.CLIENT_VERSION);
+			Map<GroupId, Visibility> m = getPreferredVisibilities(txn, c);
+			for (Group g : shareables) {
+				Visibility preferred = m.get(g.getId());
+				if (preferred == null) continue; // No session for this group
+				// Apply min of preferred visibility and client's visibility
+				Visibility min = Visibility.min(preferred, client);
+				if (LOG.isLoggable(INFO)) {
+					LOG.info("Applying visibility " + min
+							+ " to private group, preferred " + preferred
+							+ ", client " + client);
+				}
+				db.setGroupVisibility(txn, c.getId(), g.getId(), min);
+			}
+		} catch (FormatException e) {
+			throw new DbException(e);
+		}
+	}
+
+	private Map<GroupId, Visibility> getPreferredVisibilities(Transaction txn,
+			Contact c) throws DbException, FormatException {
+		GroupId contactGroupId = getContactGroup(c).getId();
+		BdfDictionary query = sessionParser.getAllSessionsQuery();
+		Map<MessageId, BdfDictionary> results = clientHelper
+				.getMessageMetadataAsDictionary(txn, contactGroupId, query);
+		Map<GroupId, Visibility> m = new HashMap<>();
+		for (BdfDictionary d : results.values()) {
+			Role role = sessionParser.getRole(d);
+			if (role == CREATOR) {
+				CreatorSession s =
+						sessionParser.parseCreatorSession(contactGroupId, d);
+				m.put(s.getPrivateGroupId(), s.getState().getVisibility());
+			} else if (role == INVITEE) {
+				InviteeSession s =
+						sessionParser.parseInviteeSession(contactGroupId, d);
+				m.put(s.getPrivateGroupId(), s.getState().getVisibility());
+			} else if (role == PEER) {
+				PeerSession s =
+						sessionParser.parsePeerSession(contactGroupId, d);
+				m.put(s.getPrivateGroupId(), s.getState().getVisibility());
+			} else {
+				throw new AssertionError();
+			}
+		}
+		return m;
+	}
+
 	private static class StoredSession {
 
 		private final MessageId storageId;
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java
index 178cafdd0956128adfb73fda060651f280f793c3..f02287574328dfade4ccf0a23c888ef00d011a1c 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.client.ClientHelper;
 import org.briarproject.bramble.api.contact.ContactManager;
 import org.briarproject.bramble.api.data.MetadataEncoder;
 import org.briarproject.bramble.api.lifecycle.LifecycleManager;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.sync.ValidationManager;
 import org.briarproject.bramble.api.system.Clock;
 import org.briarproject.briar.api.messaging.ConversationManager;
@@ -38,13 +39,25 @@ public class GroupInvitationModule {
 			LifecycleManager lifecycleManager,
 			ValidationManager validationManager, ContactManager contactManager,
 			PrivateGroupManager privateGroupManager,
-			ConversationManager conversationManager) {
+			ConversationManager conversationManager,
+			ClientVersioningManager clientVersioningManager) {
 		lifecycleManager.registerClient(groupInvitationManager);
 		validationManager.registerIncomingMessageHook(CLIENT_ID, CLIENT_VERSION,
 				groupInvitationManager);
 		contactManager.registerContactHook(groupInvitationManager);
 		privateGroupManager.registerPrivateGroupHook(groupInvitationManager);
 		conversationManager.registerConversationClient(groupInvitationManager);
+		clientVersioningManager.registerClient(CLIENT_ID, CLIENT_VERSION);
+		clientVersioningManager.registerClientVersioningHook(CLIENT_ID,
+				CLIENT_VERSION, groupInvitationManager);
+		// The group invitation manager handles client visibility changes for
+		// the private group manager
+		clientVersioningManager.registerClient(PrivateGroupManager.CLIENT_ID,
+				PrivateGroupManager.CLIENT_VERSION);
+		clientVersioningManager.registerClientVersioningHook(
+				PrivateGroupManager.CLIENT_ID,
+				PrivateGroupManager.CLIENT_VERSION,
+				groupInvitationManager.getPrivateGroupClientVersioningHook());
 		return groupInvitationManager;
 	}
 
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java
index f181d1f7764a5507ad6e8725bf56902e4e02eece..064c1d59367b1cfd761a3bd4a11a61e671f6b8ea 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java
@@ -9,6 +9,7 @@ import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.identity.Author;
 import org.briarproject.bramble.api.identity.IdentityManager;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.bramble.api.system.Clock;
@@ -41,15 +42,16 @@ import static org.briarproject.briar.privategroup.invitation.InviteeState.START;
 class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
 
 	InviteeProtocolEngine(DatabaseComponent db, ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
 			PrivateGroupManager privateGroupManager,
 			PrivateGroupFactory privateGroupFactory,
 			GroupMessageFactory groupMessageFactory,
 			IdentityManager identityManager, MessageParser messageParser,
 			MessageEncoder messageEncoder, MessageTracker messageTracker,
 			Clock clock) {
-		super(db, clientHelper, privateGroupManager, privateGroupFactory,
-				groupMessageFactory, identityManager, messageParser,
-				messageEncoder, messageTracker, clock);
+		super(db, clientHelper, clientVersioningManager, privateGroupManager,
+				privateGroupFactory, groupMessageFactory, identityManager,
+				messageParser, messageEncoder, messageTracker, clock);
 	}
 
 	@Override
@@ -212,6 +214,12 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
 			throws DbException {
 		// Send a LEAVE message
 		Message sent = sendLeaveMessage(txn, s, false);
+		try {
+			// Make the private group invisible to the contact
+			setPrivateGroupVisibility(txn, s, INVISIBLE);
+		} catch (FormatException e) {
+			throw new DbException(e); // Invalid group metadata
+		}
 		// Move to the LEFT state
 		return new InviteeSession(s.getContactGroupId(), s.getPrivateGroupId(),
 				sent.getId(), s.getLastRemoteMessageId(), sent.getTimestamp(),
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeState.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeState.java
index 7fa69e6af9c1c6113a70a92edf86b48d31b80dd6..f347ca06188cae611e91fa3c08700f7bdae7bdbf 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeState.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeState.java
@@ -2,20 +2,32 @@ package org.briarproject.briar.privategroup.invitation;
 
 import org.briarproject.bramble.api.FormatException;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.bramble.api.sync.Group.Visibility;
 
 import javax.annotation.concurrent.Immutable;
 
+import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
+import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
+import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
+
 @Immutable
 @NotNullByDefault
 enum InviteeState implements State {
 
-	START(0), INVITED(1), ACCEPTED(2), JOINED(3), LEFT(4), DISSOLVED(5),
-	ERROR(6);
+	START(0, INVISIBLE),
+	INVITED(1, INVISIBLE),
+	ACCEPTED(2, VISIBLE),
+	JOINED(3, SHARED),
+	LEFT(4, INVISIBLE),
+	DISSOLVED(5, INVISIBLE),
+	ERROR(6, INVISIBLE);
 
 	private final int value;
+	private final Visibility visibility;
 
-	InviteeState(int value) {
+	InviteeState(int value, Visibility visibility) {
 		this.value = value;
+		this.visibility = visibility;
 	}
 
 	@Override
@@ -23,6 +35,11 @@ enum InviteeState implements State {
 		return value;
 	}
 
+	@Override
+	public Visibility getVisibility() {
+		return visibility;
+	}
+
 	static InviteeState fromValue(int value) throws FormatException {
 		for (InviteeState s : values()) if (s.value == value) return s;
 		throw new FormatException();
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java
index c1908735fde51d986fd5646dcc79296bae0c13d5..5a7f1c6c3a80a1f2bb9ef088a4e32bf7b0312aa6 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java
@@ -9,6 +9,7 @@ import org.briarproject.bramble.api.db.DbException;
 import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.identity.IdentityManager;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.system.Clock;
 import org.briarproject.briar.api.client.MessageTracker;
@@ -36,15 +37,16 @@ import static org.briarproject.briar.privategroup.invitation.PeerState.START;
 class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> {
 
 	PeerProtocolEngine(DatabaseComponent db, ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
 			PrivateGroupManager privateGroupManager,
 			PrivateGroupFactory privateGroupFactory,
 			GroupMessageFactory groupMessageFactory,
 			IdentityManager identityManager, MessageParser messageParser,
 			MessageEncoder messageEncoder, MessageTracker messageTracker,
 			Clock clock) {
-		super(db, clientHelper, privateGroupManager, privateGroupFactory,
-				groupMessageFactory, identityManager, messageParser,
-				messageEncoder, messageTracker, clock);
+		super(db, clientHelper, clientVersioningManager, privateGroupManager,
+				privateGroupFactory, groupMessageFactory, identityManager,
+				messageParser, messageEncoder, messageTracker, clock);
 	}
 
 	@Override
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerState.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerState.java
index 94f9d19afe624a57645bde631c98219c062761e8..041528266eb99a42dfa40fd39584b7b783e0a9cc 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerState.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerState.java
@@ -2,20 +2,32 @@ package org.briarproject.briar.privategroup.invitation;
 
 import org.briarproject.bramble.api.FormatException;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.bramble.api.sync.Group.Visibility;
 
 import javax.annotation.concurrent.Immutable;
 
+import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
+import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
+import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
+
 @Immutable
 @NotNullByDefault
 enum PeerState implements State {
 
-	START(0), AWAIT_MEMBER(1), NEITHER_JOINED(2), LOCAL_JOINED(3),
-	BOTH_JOINED(4), LOCAL_LEFT(5), ERROR(6);
+	START(0, INVISIBLE),
+	AWAIT_MEMBER(1, INVISIBLE),
+	NEITHER_JOINED(2, INVISIBLE),
+	LOCAL_JOINED(3, VISIBLE),
+	BOTH_JOINED(4, SHARED),
+	LOCAL_LEFT(5, INVISIBLE),
+	ERROR(6, INVISIBLE);
 
 	private final int value;
+	private final Visibility visibility;
 
-	PeerState(int value) {
+	PeerState(int value, Visibility visibility) {
 		this.value = value;
+		this.visibility = visibility;
 	}
 
 	@Override
@@ -23,6 +35,11 @@ enum PeerState implements State {
 		return value;
 	}
 
+	@Override
+	public Visibility getVisibility() {
+		return visibility;
+	}
+
 	static PeerState fromValue(int value) throws FormatException {
 		for (PeerState s : values()) if (s.value == value) return s;
 		throw new FormatException();
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java
index af3bbe81673944079a40db128630757507390689..801d16d06ebd3948523ae88f50a1ea6254cceb52 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.client.ClientHelper;
 import org.briarproject.bramble.api.db.DatabaseComponent;
 import org.briarproject.bramble.api.identity.IdentityManager;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.system.Clock;
 import org.briarproject.briar.api.client.MessageTracker;
 import org.briarproject.briar.api.privategroup.GroupMessageFactory;
@@ -19,6 +20,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory {
 
 	private final DatabaseComponent db;
 	private final ClientHelper clientHelper;
+	private final ClientVersioningManager clientVersioningManager;
 	private final PrivateGroupManager privateGroupManager;
 	private final PrivateGroupFactory privateGroupFactory;
 	private final GroupMessageFactory groupMessageFactory;
@@ -30,6 +32,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory {
 
 	@Inject
 	ProtocolEngineFactoryImpl(DatabaseComponent db, ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
 			PrivateGroupManager privateGroupManager,
 			PrivateGroupFactory privateGroupFactory,
 			GroupMessageFactory groupMessageFactory,
@@ -38,6 +41,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory {
 			Clock clock) {
 		this.db = db;
 		this.clientHelper = clientHelper;
+		this.clientVersioningManager = clientVersioningManager;
 		this.privateGroupManager = privateGroupManager;
 		this.privateGroupFactory = privateGroupFactory;
 		this.groupMessageFactory = groupMessageFactory;
@@ -50,21 +54,24 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory {
 
 	@Override
 	public ProtocolEngine<CreatorSession> createCreatorEngine() {
-		return new CreatorProtocolEngine(db, clientHelper, privateGroupManager,
+		return new CreatorProtocolEngine(db, clientHelper,
+				clientVersioningManager, privateGroupManager,
 				privateGroupFactory, groupMessageFactory, identityManager,
 				messageParser, messageEncoder, messageTracker, clock);
 	}
 
 	@Override
 	public ProtocolEngine<InviteeSession> createInviteeEngine() {
-		return new InviteeProtocolEngine(db, clientHelper, privateGroupManager,
+		return new InviteeProtocolEngine(db, clientHelper,
+				clientVersioningManager, privateGroupManager,
 				privateGroupFactory, groupMessageFactory, identityManager,
 				messageParser, messageEncoder, messageTracker, clock);
 	}
 
 	@Override
 	public ProtocolEngine<PeerSession> createPeerEngine() {
-		return new PeerProtocolEngine(db, clientHelper, privateGroupManager,
+		return new PeerProtocolEngine(db, clientHelper,
+				clientVersioningManager, privateGroupManager,
 				privateGroupFactory, groupMessageFactory, identityManager,
 				messageParser, messageEncoder, messageTracker, clock);
 	}
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionEncoderImpl.java
index 78e36bf3a5b15732e6298678cc71d10b026d003e..86fe5e3a044e52dc295e1660726812ac76d8a328 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionEncoderImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionEncoderImpl.java
@@ -9,6 +9,7 @@ import javax.inject.Inject;
 
 import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_INVITE_TIMESTAMP;
+import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_IS_SESSION;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LOCAL_TIMESTAMP;
@@ -28,6 +29,7 @@ class SessionEncoderImpl implements SessionEncoder {
 	@Override
 	public BdfDictionary encodeSession(Session s) {
 		BdfDictionary d = new BdfDictionary();
+		d.put(SESSION_KEY_IS_SESSION, true);
 		d.put(SESSION_KEY_SESSION_ID, s.getPrivateGroupId());
 		d.put(SESSION_KEY_PRIVATE_GROUP_ID, s.getPrivateGroupId());
 		MessageId lastLocalMessageId = s.getLastLocalMessageId();
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java
index baf0de80e2f392f270c1e57ce52e94d6de5dd061..152ed067e32c879d111df13e7f5c2442d6fe7e65 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java
@@ -11,6 +11,8 @@ interface SessionParser {
 
 	BdfDictionary getSessionQuery(SessionId s);
 
+	BdfDictionary getAllSessionsQuery();
+
 	Role getRole(BdfDictionary d) throws FormatException;
 
 	CreatorSession parseCreatorSession(GroupId contactGroupId, BdfDictionary d)
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java
index e8813b6dcd50082ea577c4229c5f6a9a1d2795fd..19a424d707e460cf8f023e42d1cb7a4dab028543 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java
@@ -13,6 +13,7 @@ import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_INVITE_TIMESTAMP;
+import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_IS_SESSION;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LOCAL_TIMESTAMP;
@@ -37,6 +38,11 @@ class SessionParserImpl implements SessionParser {
 		return BdfDictionary.of(new BdfEntry(SESSION_KEY_SESSION_ID, s));
 	}
 
+	@Override
+	public BdfDictionary getAllSessionsQuery() {
+		return BdfDictionary.of(new BdfEntry(SESSION_KEY_IS_SESSION, true));
+	}
+
 	@Override
 	public Role getRole(BdfDictionary d) throws FormatException {
 		return Role.fromValue(d.getLong(SESSION_KEY_ROLE).intValue());
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/State.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/State.java
index 46df85efdc5dff661db8862eb557b514fe16a6e9..2313f96c7e0cf5c3620b116ebceef9d6b18d2650 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/State.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/State.java
@@ -1,6 +1,10 @@
 package org.briarproject.briar.privategroup.invitation;
 
+import org.briarproject.bramble.api.sync.Group.Visibility;
+
 interface State {
 
 	int getValue();
+
+	Visibility getVisibility();
 }
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java
index 3ae2fb61e436bea964045b0b681ca19ac4460308..8c8056512f5f5d406405b9ab5504e3c80b0ac84f 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java
@@ -10,7 +10,9 @@ import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.identity.Author;
 import org.briarproject.bramble.api.identity.AuthorId;
 import org.briarproject.bramble.api.identity.IdentityManager;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.sync.Group;
+import org.briarproject.bramble.api.sync.Group.Visibility;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.sync.MessageId;
@@ -24,6 +26,7 @@ import org.briarproject.briar.api.privategroup.PrivateGroupManager;
 import org.jmock.Expectations;
 
 import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
+import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
 import static org.briarproject.bramble.test.TestUtils.getAuthor;
 import static org.briarproject.bramble.test.TestUtils.getGroup;
 import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
@@ -47,6 +50,8 @@ public abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
 			context.mock(DatabaseComponent.class);
 	protected final ClientHelper clientHelper =
 			context.mock(ClientHelper.class);
+	protected final ClientVersioningManager clientVersioningManager =
+			context.mock(ClientVersioningManager.class);
 	protected final PrivateGroupFactory privateGroupFactory =
 			context.mock(PrivateGroupFactory.class);
 	protected final PrivateGroupManager privateGroupManager =
@@ -181,10 +186,13 @@ public abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
 		}});
 	}
 
-	protected void expectSetPrivateGroupVisibility(Group.Visibility v)
+	protected void expectSetPrivateGroupVisibility(Visibility v)
 			throws Exception {
 		expectGetContactId();
 		context.checking(new Expectations() {{
+			oneOf(clientVersioningManager).getClientVisibility(txn, contactId,
+					CLIENT_ID, CLIENT_VERSION);
+			will(returnValue(SHARED));
 			oneOf(db).setGroupVisibility(txn, contactId, privateGroupId, v);
 		}});
 	}
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java
index 22e64a9f98378e79d0ee242d9f24dbcca51474e3..c1b2bd9b2718b124e10455022425241c4a805dd8 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java
@@ -19,9 +19,10 @@ import static org.junit.Assert.assertEquals;
 public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
 
 	private final CreatorProtocolEngine engine =
-			new CreatorProtocolEngine(db, clientHelper, privateGroupManager,
-					privateGroupFactory, groupMessageFactory, identityManager,
-					messageParser, messageEncoder, messageTracker, clock);
+			new CreatorProtocolEngine(db, clientHelper, clientVersioningManager,
+					privateGroupManager, privateGroupFactory,
+					groupMessageFactory, identityManager, messageParser,
+					messageEncoder, messageTracker, clock);
 
 	private CreatorSession getDefaultSession(CreatorState state) {
 		return new CreatorSession(contactGroupId, privateGroupId,
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java
index 1a7ae0857de7c10c104e5607e9845692e096bc10..e7db720c76355ff246156d83c65698e66e14c1d9 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java
@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.db.Metadata;
 import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.identity.Author;
 import org.briarproject.bramble.api.identity.AuthorId;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.sync.Group;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.Message;
@@ -69,6 +70,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 
 	private final DatabaseComponent db = context.mock(DatabaseComponent.class);
 	private final ClientHelper clientHelper = context.mock(ClientHelper.class);
+	private final ClientVersioningManager clientVersioningManager =
+			context.mock(ClientVersioningManager.class);
 	private final ContactGroupFactory contactGroupFactory =
 			context.mock(ContactGroupFactory.class);
 	private final PrivateGroupFactory privateGroupFactory =
@@ -140,11 +143,11 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 		}});
 		MetadataParser metadataParser = context.mock(MetadataParser.class);
 		MessageTracker messageTracker = context.mock(MessageTracker.class);
-		groupInvitationManager =
-				new GroupInvitationManagerImpl(db, clientHelper, metadataParser,
-						messageTracker, contactGroupFactory,
-						privateGroupFactory, privateGroupManager, messageParser,
-						sessionParser, sessionEncoder, engineFactory);
+		groupInvitationManager = new GroupInvitationManagerImpl(db,
+				clientHelper, clientVersioningManager, metadataParser,
+				messageTracker, contactGroupFactory, privateGroupFactory,
+				privateGroupManager, messageParser, sessionParser,
+				sessionEncoder, engineFactory);
 	}
 
 	@Test
@@ -184,6 +187,9 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 					CLIENT_VERSION, c);
 			will(returnValue(contactGroup));
 			oneOf(db).addGroup(txn, contactGroup);
+			oneOf(clientVersioningManager).getClientVisibility(txn, contactId,
+					CLIENT_ID, CLIENT_VERSION);
+			will(returnValue(SHARED));
 			oneOf(db).setGroupVisibility(txn, c.getId(), contactGroup.getId(),
 					SHARED);
 			oneOf(clientHelper)
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java
index 0030945428d217b1cca9b42cfc186636259373cc..f398d3a7fd4711ffd6b9cecebc206fe2930f6133 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java
@@ -38,9 +38,10 @@ import static org.junit.Assert.assertTrue;
 public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
 
 	private final InviteeProtocolEngine engine =
-			new InviteeProtocolEngine(db, clientHelper, privateGroupManager,
-					privateGroupFactory, groupMessageFactory, identityManager,
-					messageParser, messageEncoder, messageTracker, clock);
+			new InviteeProtocolEngine(db, clientHelper, clientVersioningManager,
+					privateGroupManager, privateGroupFactory,
+					groupMessageFactory, identityManager, messageParser,
+					messageEncoder, messageTracker, clock);
 	private final LocalAuthor localAuthor = getLocalAuthor();
 
 	private InviteeSession getDefaultSession(InviteeState state) {
@@ -238,6 +239,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
 	@Test
 	public void testOnLeaveActionFromAccepted() throws Exception {
 		expectSendLeaveMessage(false);
+		expectSetPrivateGroupVisibility(INVISIBLE);
 		InviteeSession session = getDefaultSession(ACCEPTED);
 		InviteeSession newSession = engine.onLeaveAction(txn, session);
 
@@ -249,6 +251,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
 	@Test
 	public void testOnLeaveActionFromJoined() throws Exception {
 		expectSendLeaveMessage(false);
+		expectSetPrivateGroupVisibility(INVISIBLE);
 		InviteeSession session = getDefaultSession(JOINED);
 		InviteeSession newSession = engine.onLeaveAction(txn, session);
 
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java
index d5d53168fa57a672bcdd48e187b08b9bbb6065df..05c0920c545c3b97c83f9553ab2034cee77a8774 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java
@@ -24,9 +24,10 @@ import static org.junit.Assert.assertTrue;
 public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
 
 	private final PeerProtocolEngine engine =
-			new PeerProtocolEngine(db, clientHelper, privateGroupManager,
-					privateGroupFactory, groupMessageFactory, identityManager,
-					messageParser, messageEncoder, messageTracker, clock);
+			new PeerProtocolEngine(db, clientHelper, clientVersioningManager,
+					privateGroupManager, privateGroupFactory,
+					groupMessageFactory, identityManager, messageParser,
+					messageEncoder, messageTracker, clock);
 
 	private PeerSession getDefaultSession(PeerState state) {
 		return new PeerSession(contactGroupId, privateGroupId,