diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java
index 3083387b6bf1f76f393b6dc6d2066c67f32e8e77..3ab61521d8342c044b48a83c56438ca1a42afd87 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java
@@ -9,6 +9,7 @@ import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.event.Event;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.ClientId;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.bramble.api.system.Clock;
 import org.briarproject.briar.api.blog.Blog;
@@ -22,6 +23,9 @@ import org.briarproject.briar.api.sharing.InvitationRequest;
 import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_VERSION;
+
 @Immutable
 @NotNullByDefault
 class BlogProtocolEngineImpl extends ProtocolEngineImpl<Blog> {
@@ -31,13 +35,14 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl<Blog> {
 			invitationFactory;
 
 	@Inject
-	BlogProtocolEngineImpl(DatabaseComponent db,
-			ClientHelper clientHelper, MessageEncoder messageEncoder,
-			MessageParser<Blog> messageParser, MessageTracker messageTracker,
-			Clock clock, BlogManager blogManager,
+	BlogProtocolEngineImpl(DatabaseComponent db, ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
+			MessageEncoder messageEncoder, MessageParser<Blog> messageParser,
+			MessageTracker messageTracker, Clock clock, BlogManager blogManager,
 			InvitationFactory<Blog, BlogInvitationResponse> invitationFactory) {
-		super(db, clientHelper, messageEncoder, messageParser, messageTracker,
-				clock);
+		super(db, clientHelper, clientVersioningManager, messageEncoder,
+				messageParser, messageTracker, clock, CLIENT_ID,
+				CLIENT_VERSION);
 		this.blogManager = blogManager;
 		this.invitationFactory = invitationFactory;
 	}
@@ -46,8 +51,8 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl<Blog> {
 	Event getInvitationRequestReceivedEvent(InviteMessage<Blog> m,
 			ContactId contactId, boolean available, boolean canBeOpened) {
 		InvitationRequest<Blog> request = invitationFactory
-						.createInvitationRequest(false, false, true, false, m,
-								contactId, available, canBeOpened);
+				.createInvitationRequest(false, false, true, false, m,
+						contactId, available, canBeOpened);
 		return new BlogInvitationRequestReceivedEvent(m.getShareable(),
 				contactId, request);
 	}
@@ -74,7 +79,7 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl<Blog> {
 
 	@Override
 	protected ClientId getShareableClientId() {
-		return BlogManager.CLIENT_ID;
+		return CLIENT_ID;
 	}
 
 	@Override
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java
index 7a92f1c5f1fcc15bb7c12fd8d6f5fa0303813103..41554bcf4999fa601014b011663b39d814da9ffe 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java
@@ -12,6 +12,7 @@ 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.ClientId;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.briar.api.blog.Blog;
 import org.briarproject.briar.api.blog.BlogInvitationResponse;
 import org.briarproject.briar.api.blog.BlogManager;
@@ -32,6 +33,7 @@ class BlogSharingManagerImpl extends SharingManagerImpl<Blog>
 
 	@Inject
 	BlogSharingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
 			MetadataParser metadataParser, MessageParser<Blog> messageParser,
 			SessionEncoder sessionEncoder, SessionParser sessionParser,
 			MessageTracker messageTracker,
@@ -39,9 +41,9 @@ class BlogSharingManagerImpl extends SharingManagerImpl<Blog>
 			ProtocolEngine<Blog> engine,
 			InvitationFactory<Blog, BlogInvitationResponse> invitationFactory,
 			IdentityManager identityManager, BlogManager blogManager) {
-		super(db, clientHelper, metadataParser, messageParser, sessionEncoder,
-				sessionParser, messageTracker, contactGroupFactory, engine,
-				invitationFactory);
+		super(db, clientHelper, clientVersioningManager, metadataParser,
+				messageParser, sessionEncoder, sessionParser, messageTracker,
+				contactGroupFactory, engine, invitationFactory);
 		this.identityManager = identityManager;
 		this.blogManager = blogManager;
 	}
@@ -56,6 +58,16 @@ class BlogSharingManagerImpl extends SharingManagerImpl<Blog>
 		return CLIENT_VERSION;
 	}
 
+	@Override
+	protected ClientId getShareableClientId() {
+		return BlogManager.CLIENT_ID;
+	}
+
+	@Override
+	protected int getShareableClientVersion() {
+		return BlogManager.CLIENT_VERSION;
+	}
+
 	@Override
 	public void addingContact(Transaction txn, Contact c) throws DbException {
 		// Create a group to share with the contact
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumProtocolEngineImpl.java
index 9fb695e50718ca5686841a8a133184bdd0a0d7a2..90ad6888d9bedebc2ddc12ee3c1101479b29d08c 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumProtocolEngineImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumProtocolEngineImpl.java
@@ -9,6 +9,7 @@ import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.event.Event;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.ClientId;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.bramble.api.system.Clock;
 import org.briarproject.briar.api.client.MessageTracker;
@@ -22,6 +23,9 @@ import org.briarproject.briar.api.sharing.InvitationRequest;
 import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
+import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID;
+import static org.briarproject.briar.api.forum.ForumManager.CLIENT_VERSION;
+
 @Immutable
 @NotNullByDefault
 class ForumProtocolEngineImpl extends ProtocolEngineImpl<Forum> {
@@ -32,12 +36,15 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl<Forum> {
 
 	@Inject
 	ForumProtocolEngineImpl(DatabaseComponent db,
-			ClientHelper clientHelper, MessageEncoder messageEncoder,
-			MessageParser<Forum> messageParser, MessageTracker messageTracker,
-			Clock clock, ForumManager forumManager,
+			ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
+			MessageEncoder messageEncoder, MessageParser<Forum> messageParser,
+			MessageTracker messageTracker, Clock clock,
+			ForumManager forumManager,
 			InvitationFactory<Forum, ForumInvitationResponse> invitationFactory) {
-		super(db, clientHelper, messageEncoder, messageParser, messageTracker,
-				clock);
+		super(db, clientHelper, clientVersioningManager, messageEncoder,
+				messageParser, messageTracker, clock, CLIENT_ID,
+				CLIENT_VERSION);
 		this.forumManager = forumManager;
 		this.invitationFactory = invitationFactory;
 	}
@@ -46,8 +53,8 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl<Forum> {
 	Event getInvitationRequestReceivedEvent(InviteMessage<Forum> m,
 			ContactId contactId, boolean available, boolean canBeOpened) {
 		InvitationRequest<Forum> request = invitationFactory
-						.createInvitationRequest(false, false, true, false, m,
-								contactId, available, canBeOpened);
+				.createInvitationRequest(false, false, true, false, m,
+						contactId, available, canBeOpened);
 		return new ForumInvitationRequestReceivedEvent(m.getShareable(),
 				contactId, request);
 	}
@@ -74,7 +81,7 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl<Forum> {
 
 	@Override
 	protected ClientId getShareableClientId() {
-		return ForumManager.CLIENT_ID;
+		return CLIENT_ID;
 	}
 
 	@Override
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumSharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumSharingManagerImpl.java
index 528743b9cc6ba65d939f8db3c27ab7014d8e3b36..2f1ac5efbd403b5c16f5feb3b003962348f9d155 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumSharingManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumSharingManagerImpl.java
@@ -8,9 +8,11 @@ import org.briarproject.bramble.api.db.DbException;
 import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.ClientId;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.briar.api.client.MessageTracker;
 import org.briarproject.briar.api.forum.Forum;
 import org.briarproject.briar.api.forum.ForumInvitationResponse;
+import org.briarproject.briar.api.forum.ForumManager;
 import org.briarproject.briar.api.forum.ForumManager.RemoveForumHook;
 import org.briarproject.briar.api.forum.ForumSharingManager;
 
@@ -22,15 +24,16 @@ class ForumSharingManagerImpl extends SharingManagerImpl<Forum>
 
 	@Inject
 	ForumSharingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
 			MetadataParser metadataParser, MessageParser<Forum> messageParser,
 			SessionEncoder sessionEncoder, SessionParser sessionParser,
 			MessageTracker messageTracker,
 			ContactGroupFactory contactGroupFactory,
 			ProtocolEngine<Forum> engine,
 			InvitationFactory<Forum, ForumInvitationResponse> invitationFactory) {
-		super(db, clientHelper, metadataParser, messageParser, sessionEncoder,
-				sessionParser, messageTracker, contactGroupFactory, engine,
-				invitationFactory);
+		super(db, clientHelper, clientVersioningManager, metadataParser,
+				messageParser, sessionEncoder, sessionParser, messageTracker,
+				contactGroupFactory, engine, invitationFactory);
 	}
 
 	@Override
@@ -43,6 +46,16 @@ class ForumSharingManagerImpl extends SharingManagerImpl<Forum>
 		return CLIENT_VERSION;
 	}
 
+	@Override
+	protected ClientId getShareableClientId() {
+		return ForumManager.CLIENT_ID;
+	}
+
+	@Override
+	protected int getShareableClientVersion() {
+		return ForumManager.CLIENT_VERSION;
+	}
+
 	@Override
 	public void removingForum(Transaction txn, Forum f) throws DbException {
 		removingShareable(txn, f);
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java
index e6a7976d5829b21478ae15dbb11d476cb740b7bf..6097c61aaa605737878c223ddae671e0bd3f9a67 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java
@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.event.Event;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.ClientId;
+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;
@@ -52,19 +53,27 @@ abstract class ProtocolEngineImpl<S extends Shareable>
 	protected final ClientHelper clientHelper;
 	protected final MessageParser<S> messageParser;
 
+	private final ClientVersioningManager clientVersioningManager;
 	private final MessageEncoder messageEncoder;
 	private final MessageTracker messageTracker;
 	private final Clock clock;
+	private final ClientId shareableClientId;
+	private final int shareableClientVersion;
 
 	ProtocolEngineImpl(DatabaseComponent db, ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
 			MessageEncoder messageEncoder, MessageParser<S> messageParser,
-			MessageTracker messageTracker, Clock clock) {
+			MessageTracker messageTracker, Clock clock,
+			ClientId shareableClientId, int shareableClientVersion) {
 		this.db = db;
 		this.clientHelper = clientHelper;
+		this.clientVersioningManager = clientVersioningManager;
 		this.messageEncoder = messageEncoder;
 		this.messageParser = messageParser;
 		this.messageTracker = messageTracker;
 		this.clock = clock;
+		this.shareableClientId = shareableClientId;
+		this.shareableClientVersion = shareableClientVersion;
 	}
 
 	@Override
@@ -598,9 +607,13 @@ abstract class ProtocolEngineImpl<S extends Shareable>
 	}
 
 	private void setShareableVisibility(Transaction txn, Session session,
-			Visibility v) throws DbException, FormatException {
+			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.getShareableId(), v);
+		Visibility client = clientVersioningManager.getClientVisibility(txn,
+				contactId, shareableClientId, shareableClientVersion);
+		Visibility min = Visibility.min(preferred, client);
+		db.setGroupVisibility(txn, contactId, session.getShareableId(), min);
 	}
 
 	private ContactId getContactId(Transaction txn, GroupId contactGroupId)
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionEncoderImpl.java
index 7cf2bf139d67495092dec01dc158674aec217a63..641731a4aa9180cbb7dcb62545866ddce137b014 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionEncoderImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/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.sharing.SharingConstants.SESSION_KEY_INVITE_TIMESTAMP;
+import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_IS_SESSION;
 import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
 import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
 import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LOCAL_TIMESTAMP;
@@ -27,6 +28,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.getShareableId());
 		d.put(SESSION_KEY_SHAREABLE_ID, s.getShareableId());
 		MessageId lastLocalMessageId = s.getLastLocalMessageId();
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java
index a82aed3eca199a2eb8eb2924375595a88ba42a0e..eec97355f4db745ea8fb54712cd73717698de051 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java
@@ -11,6 +11,8 @@ interface SessionParser {
 
 	BdfDictionary getSessionQuery(SessionId s);
 
+	BdfDictionary getAllSessionsQuery();
+
 	Session parseSession(GroupId contactGroupId, BdfDictionary d)
 			throws FormatException;
 
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java
index 62d9c44b12b276ea27655471b916451597ceedcb..ee0c06f61f32d6acb9149d6664b927cde30eb14f 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java
@@ -13,6 +13,7 @@ import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
 import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_INVITE_TIMESTAMP;
+import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_IS_SESSION;
 import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
 import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
 import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LOCAL_TIMESTAMP;
@@ -33,6 +34,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 Session parseSession(GroupId contactGroupId,
 			BdfDictionary d) throws FormatException {
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java
index d98099e27b2ff30a024ce7a2efbe4b72c01c26e1..f2522d1a9bb05a51a2d68d2a7f29db9153d832a4 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java
@@ -18,6 +18,7 @@ interface SharingConstants {
 	String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
 
 	// Session keys
+	String SESSION_KEY_IS_SESSION = "isSession";
 	String SESSION_KEY_STATE = "state";
 	String SESSION_KEY_SESSION_ID = "sessionId";
 	String SESSION_KEY_SHAREABLE_ID = "shareableId";
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
index 711e3875e5081687e2689044e9e9c5eeaa51a7f1..d249fc1f6051571898b7d16fcc4fcd3c274e3fc9 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
@@ -16,7 +16,10 @@ import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.Client;
 import org.briarproject.bramble.api.sync.ClientId;
+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;
@@ -37,9 +40,11 @@ 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 static java.util.logging.Level.INFO;
 import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
 import static org.briarproject.briar.sharing.MessageType.ABORT;
 import static org.briarproject.briar.sharing.MessageType.ACCEPT;
@@ -52,8 +57,13 @@ import static org.briarproject.briar.sharing.State.SHARING;
 @NotNullByDefault
 abstract class SharingManagerImpl<S extends Shareable>
 		extends ConversationClientImpl
-		implements SharingManager<S>, Client, ContactHook {
+		implements SharingManager<S>, Client, ContactHook,
+		ClientVersioningHook {
 
+	private static final Logger LOG =
+			Logger.getLogger(SharingManagerImpl.class.getName());
+
+	private final ClientVersioningManager clientVersioningManager;
 	private final MessageParser<S> messageParser;
 	private final SessionEncoder sessionEncoder;
 	private final SessionParser sessionParser;
@@ -62,12 +72,14 @@ abstract class SharingManagerImpl<S extends Shareable>
 	private final InvitationFactory<S, ?> invitationFactory;
 
 	SharingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
+			ClientVersioningManager clientVersioningManager,
 			MetadataParser metadataParser, MessageParser<S> messageParser,
 			SessionEncoder sessionEncoder, SessionParser sessionParser,
 			MessageTracker messageTracker,
 			ContactGroupFactory contactGroupFactory, ProtocolEngine<S> engine,
 			InvitationFactory<S, ?> invitationFactory) {
 		super(db, clientHelper, metadataParser, messageTracker);
+		this.clientVersioningManager = clientVersioningManager;
 		this.messageParser = messageParser;
 		this.sessionEncoder = sessionEncoder;
 		this.sessionParser = sessionParser;
@@ -80,6 +92,10 @@ abstract class SharingManagerImpl<S extends Shareable>
 
 	protected abstract int getClientVersion();
 
+	protected abstract ClientId getShareableClientId();
+
+	protected abstract int getShareableClientVersion();
+
 	@Override
 	public void createLocalState(Transaction txn) throws DbException {
 		// Create a local group to indicate that we've set this client up
@@ -93,18 +109,22 @@ abstract class SharingManagerImpl<S extends Shareable>
 
 	@Override
 	public void addingContact(Transaction txn, Contact c) throws DbException {
+		// Create a group to share with the contact
+		Group g = getContactGroup(c);
+		// Store the group and share it with the contact
+		db.addGroup(txn, g);
+		Visibility client = clientVersioningManager.getClientVisibility(txn,
+				c.getId(), getClientId(), getClientVersion());
+		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());
 		try {
-			// Create a group to share with the contact
-			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);
-			// Attach the contact ID to the group
-			BdfDictionary meta = new BdfDictionary();
-			meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt());
 			clientHelper.mergeGroupMetadata(txn, g.getId(), meta);
 		} catch (FormatException e) {
-			throw new DbException(e);
+			throw new AssertionError(e);
 		}
 	}
 
@@ -156,9 +176,13 @@ abstract class SharingManagerImpl<S extends Shareable>
 				getSessionId(shareable.getId()));
 		if (existingSession != null) return;
 
-		// Add and share the shareable with the contact
+		// Add the shareable
 		db.addGroup(txn, shareable.getGroup());
-		db.setGroupVisibility(txn, c.getId(), shareable.getId(), SHARED);
+
+		// Apply the client's visibility
+		Visibility client = clientVersioningManager.getClientVisibility(txn,
+				c.getId(), getShareableClientId(), getShareableClientVersion());
+		db.setGroupVisibility(txn, c.getId(), shareable.getId(), client);
 
 		// Initialize session in sharing state
 		Session session = new Session(SHARING, contactGroupId,
@@ -420,6 +444,7 @@ abstract class SharingManagerImpl<S extends Shareable>
 		Transaction txn = db.startTransaction(true);
 		try {
 			for (Contact c : db.getContacts(txn)) {
+				// FIXME: Check the session for the preferred visibility?
 				if (db.getGroupVisibility(txn, c.getId(), g) == SHARED)
 					contacts.add(c);
 			}
@@ -480,6 +505,58 @@ abstract class SharingManagerImpl<S extends Shareable>
 		}
 	}
 
+	@Override
+	public void onClientVisibilityChanging(Transaction txn, Contact c,
+			Visibility v) throws DbException {
+		// Apply the client's visibility to the contact group
+		Group g = getContactGroup(c);
+		if (LOG.isLoggable(INFO))
+			LOG.info("Applying visibility " + v + " to contact group");
+		db.setGroupVisibility(txn, c.getId(), g.getId(), v);
+	}
+
+	ClientVersioningHook getShareableClientVersioningHook() {
+		return this::onShareableClientVisibilityChanging;
+	}
+
+	// Versioning hook for the shareable client
+	private void onShareableClientVisibilityChanging(Transaction txn, Contact c,
+			Visibility client) throws DbException {
+		try {
+			Collection<Group> shareables = db.getGroups(txn,
+					getShareableClientId(), getShareableClientVersion());
+			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 shareable, 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()) {
+			Session s = sessionParser.parseSession(contactGroupId, d);
+			m.put(s.getShareableId(), s.getState().getVisibility());
+		}
+		return m;
+	}
+
 	private static class StoredSession {
 
 		private final MessageId storageId;
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingModule.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingModule.java
index 4dfe78d8d33b8528cc38f9de660122fae04f3ca4..b31bfe68c7ca19bcdc56fab97ab3337dbd4ce10e 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingModule.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingModule.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.blog.Blog;
@@ -73,6 +74,7 @@ public class SharingModule {
 			LifecycleManager lifecycleManager, ContactManager contactManager,
 			ValidationManager validationManager,
 			ConversationManager conversationManager, BlogManager blogManager,
+			ClientVersioningManager clientVersioningManager,
 			BlogSharingManagerImpl blogSharingManager) {
 		lifecycleManager.registerClient(blogSharingManager);
 		contactManager.registerContactHook(blogSharingManager);
@@ -81,6 +83,18 @@ public class SharingModule {
 				blogSharingManager);
 		conversationManager.registerConversationClient(blogSharingManager);
 		blogManager.registerRemoveBlogHook(blogSharingManager);
+		clientVersioningManager.registerClient(BlogSharingManager.CLIENT_ID,
+				BlogSharingManager.CLIENT_VERSION);
+		clientVersioningManager.registerClientVersioningHook(
+				BlogSharingManager.CLIENT_ID, BlogSharingManager.CLIENT_VERSION,
+				blogSharingManager);
+		// The blog sharing manager handles client visibility changes for the
+		// blog manager
+		clientVersioningManager.registerClient(BlogManager.CLIENT_ID,
+				BlogManager.CLIENT_VERSION);
+		clientVersioningManager.registerClientVersioningHook(
+				BlogManager.CLIENT_ID, BlogManager.CLIENT_VERSION,
+				blogSharingManager.getShareableClientVersioningHook());
 		return blogSharingManager;
 	}
 
@@ -123,6 +137,7 @@ public class SharingModule {
 			LifecycleManager lifecycleManager, ContactManager contactManager,
 			ValidationManager validationManager,
 			ConversationManager conversationManager, ForumManager forumManager,
+			ClientVersioningManager clientVersioningManager,
 			ForumSharingManagerImpl forumSharingManager) {
 		lifecycleManager.registerClient(forumSharingManager);
 		contactManager.registerContactHook(forumSharingManager);
@@ -131,6 +146,18 @@ public class SharingModule {
 				ForumSharingManager.CLIENT_VERSION, forumSharingManager);
 		conversationManager.registerConversationClient(forumSharingManager);
 		forumManager.registerRemoveForumHook(forumSharingManager);
+		clientVersioningManager.registerClient(ForumSharingManager.CLIENT_ID,
+				ForumSharingManager.CLIENT_VERSION);
+		clientVersioningManager.registerClientVersioningHook(
+				ForumSharingManager.CLIENT_ID,
+				ForumSharingManager.CLIENT_VERSION, forumSharingManager);
+		// The forum sharing manager handles client visibility changes for the
+		// forum manager
+		clientVersioningManager.registerClient(ForumManager.CLIENT_ID,
+				ForumManager.CLIENT_VERSION);
+		clientVersioningManager.registerClientVersioningHook(
+				ForumManager.CLIENT_ID, ForumManager.CLIENT_VERSION,
+				forumSharingManager.getShareableClientVersioningHook());
 		return forumSharingManager;
 	}
 
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/State.java b/briar-core/src/main/java/org/briarproject/briar/sharing/State.java
index ade7d7a248787123e6a10bd8cfcc43cc4ba51210..2d0ed97660d9af2cbb2c79b4e47cde5e2537b01c 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/State.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/State.java
@@ -2,26 +2,41 @@ package org.briarproject.briar.sharing;
 
 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 State {
 
-	START(0), LOCAL_INVITED(1), REMOTE_INVITED(2), SHARING(3), LOCAL_LEFT(4),
-	REMOTE_HANGING(5);
+	START(0, INVISIBLE),
+	LOCAL_INVITED(1, INVISIBLE),
+	REMOTE_INVITED(2, VISIBLE),
+	SHARING(3, SHARED),
+	LOCAL_LEFT(4, INVISIBLE),
+	REMOTE_HANGING(5, INVISIBLE);
 
 	private final int value;
+	private final Visibility visibility;
 
-	State(int value) {
+	State(int value, Visibility visibility) {
 		this.value = value;
+		this.visibility = visibility;
 	}
 
 	public int getValue() {
 		return value;
 	}
 
+	public Visibility getVisibility() {
+		return visibility;
+	}
+
 	public boolean canInvite() {
 		return this == START;
 	}
diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java
index 8a7a3775f05d90ec1db2d1b1dc56671708a2c3af..5b109533c9545aff783accf1e242dc52146c3a65 100644
--- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java
@@ -14,6 +14,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.identity.LocalAuthor;
+import org.briarproject.bramble.api.sync.ClientVersioningManager;
 import org.briarproject.bramble.api.sync.Group;
 import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.sync.MessageId;
@@ -24,7 +25,6 @@ import org.briarproject.briar.api.blog.BlogManager;
 import org.briarproject.briar.api.client.MessageTracker;
 import org.briarproject.briar.api.client.SessionId;
 import org.jmock.Expectations;
-import org.jmock.Mockery;
 import org.junit.Test;
 
 import java.util.Collection;
@@ -44,12 +44,13 @@ import static org.briarproject.briar.sharing.SharingConstants.GROUP_KEY_CONTACT_
 
 public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 
-	private final Mockery context = new Mockery();
 	private final BlogSharingManagerImpl blogSharingManager;
 	private final DatabaseComponent db = context.mock(DatabaseComponent.class);
 	private final IdentityManager identityManager =
 			context.mock(IdentityManager.class);
 	private final ClientHelper clientHelper = context.mock(ClientHelper.class);
+	private final ClientVersioningManager clientVersioningManager =
+			context.mock(ClientVersioningManager.class);
 	private final SessionEncoder sessionEncoder =
 			context.mock(SessionEncoder.class);
 	private final SessionParser sessionParser =
@@ -80,14 +81,15 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 	@SuppressWarnings("unchecked")
 	public BlogSharingManagerImplTest() {
 		MetadataParser metadataParser = context.mock(MetadataParser.class);
-		MessageTracker messageTracker = context.mock(MessageTracker.class);
 		MessageParser<Blog> messageParser = context.mock(MessageParser.class);
+		MessageTracker messageTracker = context.mock(MessageTracker.class);
 		InvitationFactory<Blog, BlogInvitationResponse> invitationFactory =
 				context.mock(InvitationFactory.class);
 		blogSharingManager = new BlogSharingManagerImpl(db, clientHelper,
-				metadataParser, messageParser, sessionEncoder, sessionParser,
-				messageTracker, contactGroupFactory, engine, invitationFactory,
-				identityManager, blogManager);
+				clientVersioningManager, metadataParser, messageParser,
+				sessionEncoder, sessionParser, messageTracker,
+				contactGroupFactory, engine, invitationFactory, identityManager,
+				blogManager);
 	}
 
 	@Test
@@ -124,6 +126,9 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).addGroup(txn, contactGroup);
+			oneOf(clientVersioningManager).getClientVisibility(txn, contactId,
+					CLIENT_ID, CLIENT_VERSION);
+			will(returnValue(SHARED));
 			oneOf(db).setGroupVisibility(txn, contactId, contactGroup.getId(),
 					SHARED);
 			// Attach the contact ID to the group
@@ -207,6 +212,10 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(sessions));
 			if (sessions.size() == 0) {
 				oneOf(db).addGroup(txn, blog.getGroup());
+				oneOf(clientVersioningManager).getClientVisibility(txn,
+						contactId, BlogManager.CLIENT_ID,
+						BlogManager.CLIENT_VERSION);
+				will(returnValue(SHARED));
 				oneOf(db).setGroupVisibility(txn, contact.getId(),
 						blog.getGroup().getId(), SHARED);
 				oneOf(clientHelper)
diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java
index ebd3f2238336d10729680d58936c661cb4b9f184..bb955313b508c3dd9ff1ca283c4a2a8af418c417 100644
--- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java
@@ -256,6 +256,8 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
 		sync0To2(1, true);
 		sync1To0(1, true);
 		sync2To0(1, true);
+		sync0To1(1, true);
+		sync0To2(1, true);
 	}
 
 	protected void addContacts1And2() throws Exception {
@@ -269,6 +271,7 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
 		// Sync initial client versioning updates
 		sync1To2(1, true);
 		sync2To1(1, true);
+		sync1To2(1, true);
 	}
 
 	@After