diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java
index d68f115fdc454f85013b8daecd5fd670145880cc..6b4ba6b4c23d022475c6f436050316c48ca996c7 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java
@@ -12,18 +12,19 @@ public interface ContactGroupFactory {
 	/**
 	 * Creates a group that is not shared with any contacts.
 	 */
-	Group createLocalGroup(ClientId clientId);
+	Group createLocalGroup(ClientId clientId, int clientVersion);
 
 	/**
 	 * Creates a group for the given client to share with the given contact.
 	 */
-	Group createContactGroup(ClientId clientId, Contact contact);
+	Group createContactGroup(ClientId clientId, int clientVersion,
+			Contact contact);
 
 	/**
 	 * Creates a group for the given client to share between the given authors
 	 * identified by their AuthorIds.
 	 */
-	Group createContactGroup(ClientId clientId, AuthorId authorId1,
-			AuthorId authorId2);
+	Group createContactGroup(ClientId clientId, int clientVersion,
+			AuthorId authorId1, AuthorId authorId2);
 
 }
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java
index 8a219c0c69e047878b7e6b4be70c709c5e3ae965..fe33328a358b9feda1c21fe4eda9f9411cb8e791 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java
@@ -17,6 +17,11 @@ public interface TransportPropertyManager {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.properties");
 
+	/**
+	 * The current version of the transport property client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Stores the given properties received while adding a contact - they will
 	 * be superseded by any properties synced from the contact.
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupFactory.java
index 999e1f93666933c124d492dcacd7dad1f352532a..844ded0e14863172165246aa13d534433c91df87 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupFactory.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupFactory.java
@@ -6,7 +6,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 public interface GroupFactory {
 
 	/**
-	 * Creates a group with the given client ID and descriptor.
+	 * Creates a group with the given client ID, client version and descriptor.
 	 */
-	Group createGroup(ClientId c, byte[] descriptor);
+	Group createGroup(ClientId c, int clientVersion, byte[] descriptor);
 }
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/client/ContactGroupFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/client/ContactGroupFactoryImpl.java
index 0690553479ff74cfc67c95264c193115714152a8..fba2aa745a72fca908df892714ee9305df9ef02b 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/client/ContactGroupFactoryImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/client/ContactGroupFactoryImpl.java
@@ -32,23 +32,25 @@ class ContactGroupFactoryImpl implements ContactGroupFactory {
 	}
 
 	@Override
-	public Group createLocalGroup(ClientId clientId) {
-		return groupFactory.createGroup(clientId, LOCAL_GROUP_DESCRIPTOR);
+	public Group createLocalGroup(ClientId clientId, int clientVersion) {
+		return groupFactory.createGroup(clientId, clientVersion,
+				LOCAL_GROUP_DESCRIPTOR);
 	}
 
 	@Override
-	public Group createContactGroup(ClientId clientId, Contact contact) {
+	public Group createContactGroup(ClientId clientId, int clientVersion,
+			Contact contact) {
 		AuthorId local = contact.getLocalAuthorId();
 		AuthorId remote = contact.getAuthor().getId();
 		byte[] descriptor = createGroupDescriptor(local, remote);
-		return groupFactory.createGroup(clientId, descriptor);
+		return groupFactory.createGroup(clientId, clientVersion, descriptor);
 	}
 
 	@Override
-	public Group createContactGroup(ClientId clientId, AuthorId authorId1,
-			AuthorId authorId2) {
+	public Group createContactGroup(ClientId clientId, int clientVersion,
+			AuthorId authorId1, AuthorId authorId2) {
 		byte[] descriptor = createGroupDescriptor(authorId1, authorId2);
-		return groupFactory.createGroup(clientId, descriptor);
+		return groupFactory.createGroup(clientId, clientVersion, descriptor);
 	}
 
 	private byte[] createGroupDescriptor(AuthorId local, AuthorId remote) {
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java
index 26ab19c330eaf756b87a1af7abf496efff2fc490..9f4a5bb528cb55d8c79777507199068879264788 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java
@@ -58,7 +58,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
 		this.metadataParser = metadataParser;
 		this.contactGroupFactory = contactGroupFactory;
 		this.clock = clock;
-		localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID);
+		localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID,
+				CLIENT_VERSION);
 	}
 
 	@Override
@@ -287,7 +288,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
 	}
 
 	private Group getContactGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(CLIENT_ID, c);
+		return contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, c);
 	}
 
 	private void storeMessage(Transaction txn, GroupId g, TransportId t,
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java
index 86ac6cda6735c5229bcc42defd08769d03b20c80..a28592bdce4338fe51939a39555d3cdcfecdd8a1 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java
@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.sync.ClientId;
 import org.briarproject.bramble.api.sync.Group;
 import org.briarproject.bramble.api.sync.GroupFactory;
 import org.briarproject.bramble.api.sync.GroupId;
+import org.briarproject.bramble.util.ByteUtils;
 import org.briarproject.bramble.util.StringUtils;
 
 import javax.annotation.concurrent.Immutable;
@@ -13,6 +14,7 @@ import javax.inject.Inject;
 
 import static org.briarproject.bramble.api.sync.GroupId.LABEL;
 import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
+import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
 
 @Immutable
 @NotNullByDefault
@@ -26,9 +28,12 @@ class GroupFactoryImpl implements GroupFactory {
 	}
 
 	@Override
-	public Group createGroup(ClientId c, byte[] descriptor) {
+	public Group createGroup(ClientId c, int clientVersion, byte[] descriptor) {
+		byte[] clientVersionBytes = new byte[INT_32_BYTES];
+		ByteUtils.writeUint32(clientVersion, clientVersionBytes, 0);
 		byte[] hash = crypto.hash(LABEL, new byte[] {PROTOCOL_VERSION},
-				StringUtils.toUtf8(c.getString()), descriptor);
+				StringUtils.toUtf8(c.getString()), clientVersionBytes,
+				descriptor);
 		return new Group(new GroupId(hash), c, descriptor);
 	}
 }
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java
index c2f8dc044ce634be1e760c7ece3f841a6e243717..33a738557cca792f904540098d9f2c64c4743932 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java
@@ -34,6 +34,7 @@ import java.util.Map;
 import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
 import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
 import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_ID;
+import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_VERSION;
 import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
@@ -78,7 +79,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 
 	private TransportPropertyManagerImpl createInstance() {
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID);
+			oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID,
+					CLIENT_VERSION);
 			will(returnValue(localGroup));
 		}});
 		return new TransportPropertyManagerImpl(db, clientHelper,
@@ -98,12 +100,14 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 			oneOf(db).getContacts(txn);
 			will(returnValue(contacts));
 			// The first contact's group has already been set up
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact1);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact1);
 			will(returnValue(contactGroup1));
 			oneOf(db).containsGroup(txn, contactGroup1.getId());
 			will(returnValue(true));
 			// The second contact's group hasn't been set up
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact2);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact2);
 			will(returnValue(contactGroup2));
 			oneOf(db).containsGroup(txn, contactGroup2.getId());
 			will(returnValue(false));
@@ -130,7 +134,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 
 		context.checking(new Expectations() {{
 			// Create the group and share it with the contact
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).containsGroup(txn, contactGroup.getId());
 			will(returnValue(false));
@@ -156,7 +161,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 		Group contactGroup = getGroup();
 
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).removeGroup(txn, contactGroup);
 		}});
@@ -297,7 +303,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 		context.checking(new Expectations() {{
 			oneOf(db).getContact(txn, contact.getId());
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 		}});
 		expectStoreMessage(txn, contactGroup.getId(), "foo", fooPropertiesDict,
@@ -431,13 +438,15 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(contacts));
 			// First contact: skipped because not active
 			// Second contact: no updates
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact2);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact2);
 			will(returnValue(contactGroup2));
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
 					contactGroup2.getId());
 			will(returnValue(Collections.emptyMap()));
 			// Third contact: returns an update
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact3);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact3);
 			will(returnValue(contactGroup3));
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
 					contactGroup3.getId());
@@ -507,7 +516,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 			// Store the new properties in each contact's group, version 1
 			oneOf(db).getContacts(txn);
 			will(returnValue(Collections.singletonList(contact)));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
 					contactGroup.getId());
@@ -559,7 +569,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 			// Store the merged properties in each contact's group, version 2
 			oneOf(db).getContacts(txn);
 			will(returnValue(Collections.singletonList(contact)));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
 					contactGroup.getId());
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java
index 7bb53e8435c05d56a0eec01b4eb944c4ab6a1cff..c5f3136129864c45040cfbce9bf63f5e7c5ffb88 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java
@@ -22,7 +22,6 @@ import org.briarproject.bramble.api.transport.StreamReaderFactory;
 import org.briarproject.bramble.api.transport.StreamWriterFactory;
 import org.briarproject.bramble.test.BrambleTestCase;
 import org.briarproject.bramble.test.TestUtils;
-import org.briarproject.bramble.util.StringUtils;
 import org.junit.Test;
 
 import java.io.ByteArrayInputStream;
@@ -37,6 +36,7 @@ import javax.inject.Inject;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
 import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
 import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
+import static org.briarproject.bramble.util.StringUtils.getRandomString;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -79,9 +79,11 @@ public class SyncIntegrationTest extends BrambleTestCase {
 		headerKey = TestUtils.getSecretKey();
 		streamNumber = 123;
 		// Create a group
-		ClientId clientId = new ClientId(StringUtils.getRandomString(5));
+		ClientId clientId = new ClientId(getRandomString(123));
+		int clientVersion = 1234567890;
 		byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH];
-		Group group = groupFactory.createGroup(clientId, descriptor);
+		Group group = groupFactory.createGroup(clientId, clientVersion,
+				descriptor);
 		// Add two messages to the group
 		long timestamp = System.currentTimeMillis();
 		byte[] body = "Hello world".getBytes("UTF-8");
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java
index 4ad7e99eb7d4058271b74c147a7c19f1974aedc1..bbf1da0944381d3d290a682a29c7405285cd4525 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java
@@ -17,10 +17,15 @@ import javax.annotation.Nullable;
 public interface BlogManager {
 
 	/**
-	 * Unique ID of the blog client.
+	 * The unique ID of the blog client.
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.blog");
 
+	/**
+	 * The current version of the blog client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Adds the given {@link Blog).}
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java
index 87f669bef0099f4f255b8a45fde8fbe60b78059c..e4b68bd6b42cf4576414e4f01ace74aacc66cde8 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java
@@ -5,6 +5,13 @@ import org.briarproject.briar.api.sharing.SharingManager;
 
 public interface BlogSharingManager extends SharingManager<Blog> {
 
+	/**
+	 * The unique ID of the blog sharing client.
+	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.blog.sharing");
 
+	/**
+	 * The current version of the blog sharing client.
+	 */
+	int CLIENT_VERSION = 0;
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/feed/FeedManager.java b/briar-api/src/main/java/org/briarproject/briar/api/feed/FeedManager.java
index 7d83b22c151d70e37e69e7d04272001464b10a3b..50f67963a5e2d0bdc9367e068df28d05ed39d92e 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/feed/FeedManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/feed/FeedManager.java
@@ -15,6 +15,11 @@ public interface FeedManager {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.feed");
 
+	/**
+	 * The current version of the RSS feed client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Adds an RSS feed as a new dedicated blog.
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java
index c861b4e63d72eb84c5dcae9f02e5a02353344826..8eb7eb1ad3504f31b38ccae8228873250574cfe8 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java
@@ -22,6 +22,11 @@ public interface ForumManager {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.forum");
 
+	/**
+	 * The current version of the forum client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Subscribes to a forum.
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java
index 85bdf53da858e17ccecba833e23c2655f7c6ea47..5620e024c11f99af1886f0fe51be03ae3a58138a 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java
@@ -5,6 +5,13 @@ import org.briarproject.briar.api.sharing.SharingManager;
 
 public interface ForumSharingManager extends SharingManager<Forum> {
 
+	/**
+	 * The unique ID of the forum sharing client.
+	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.forum.sharing");
 
+	/**
+	 * The current version of the forum sharing client.
+	 */
+	int CLIENT_VERSION = 0;
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionConstants.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionConstants.java
index 8ae24bc50541936caa637febb7f5ff54d6a8f042..72e6030b10b207a179abf99be29e7897af2777cb 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionConstants.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionConstants.java
@@ -86,11 +86,6 @@ public interface IntroductionConstants {
 	int TASK_ACTIVATE_CONTACT = 1;
 	int TASK_ABORT = 2;
 
-	/**
-	 * The current version of the introduction protocol.
-	 */
-	int PROTOCOL_VERSION = 0;
-
 	/**
 	 * Label for deriving the shared secret.
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java
index a9b8660813a247413c3e8f8a6e9b2186cb428382..ce9d067277fabd9aed94a254f3c86f2b47ee3775 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java
@@ -21,6 +21,11 @@ public interface IntroductionManager extends ConversationClient {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.introduction");
 
+	/**
+	 * The current version of the introduction client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Sends two initial introduction messages.
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java
index c2b80fc4625b4c87159f9c6aec881c72b239a74a..65f406a6faa8bb9274110ee54af624136982fff4 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java
@@ -18,6 +18,11 @@ public interface MessagingManager extends ConversationClient {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.messaging");
 
+	/**
+	 * The current version of the messaging client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Stores a local private message.
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/PrivateGroupManager.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/PrivateGroupManager.java
index aa4b7d45828d2a3d6e279a66f87801a940a5036c..7d08ae016dfd8e6be85c03eafe7cd35dbb9f6017 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/PrivateGroupManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/PrivateGroupManager.java
@@ -21,6 +21,11 @@ public interface PrivateGroupManager {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.privategroup");
 
+	/**
+	 * The current version of the private group client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Adds a new private group and joins it.
 	 *
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java
index 6fc4c57e440e0210515b106fbd5fa9897d5fb090..fc3ca339f30ba6f9c9822dcc9944c6728e3493bf 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java
@@ -25,6 +25,11 @@ public interface GroupInvitationManager extends ConversationClient {
 	ClientId CLIENT_ID =
 			new ClientId("org.briarproject.briar.privategroup.invitation");
 
+	/**
+	 * The current version of the private group invitation client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Sends an invitation to share the given private group with the given
 	 * contact, including an optional message.
diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java
index 6410d69bcd03fbb2ce42704777a8d983894508bd..8cf9d024a295d93fc424dbf87cb7a1a6950dc898 100644
--- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java
@@ -16,6 +16,8 @@ import javax.inject.Inject;
 
 import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
 import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -52,8 +54,8 @@ class BlogFactoryImpl implements BlogFactory {
 					rssFeed
 			);
 			byte[] descriptor = clientHelper.toByteArray(blog);
-			Group g = groupFactory
-					.createGroup(BlogManagerImpl.CLIENT_ID, descriptor);
+			Group g = groupFactory.createGroup(CLIENT_ID, CLIENT_VERSION,
+					descriptor);
 			return new Blog(g, a, rssFeed);
 		} catch (FormatException e) {
 			throw new RuntimeException(e);
diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java
index 6fa9be04f19f36a8aaa31cccbd628dd9c357547b..84c5877c20699bbb979460f8017181a16799f123 100644
--- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java
+++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java
@@ -45,6 +45,8 @@ import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIME_RECEIVED;
 import static org.briarproject.briar.api.blog.BlogConstants.KEY_TYPE;
 import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_COMMENT_LENGTH;
 import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_POST_BODY_LENGTH;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_VERSION;
 import static org.briarproject.briar.api.blog.BlogPostFactory.SIGNING_LABEL_COMMENT;
 import static org.briarproject.briar.api.blog.BlogPostFactory.SIGNING_LABEL_POST;
 import static org.briarproject.briar.api.blog.MessageType.COMMENT;
@@ -199,8 +201,8 @@ class BlogPostValidator extends BdfMessageValidator {
 		checkLength(signature, 1, MAX_SIGNATURE_LENGTH);
 
 		// Get and Validate the Wrapped Message
-		Group wGroup = groupFactory
-				.createGroup(BlogManagerImpl.CLIENT_ID, descriptor);
+		Group wGroup = groupFactory.createGroup(CLIENT_ID, CLIENT_VERSION,
+				descriptor);
 		Blog wBlog = blogFactory.parseBlog(wGroup);
 		BdfList wBodyList = BdfList.of(POST.getInt(), content, signature);
 		byte[] wBody = clientHelper.toByteArray(wBodyList);
@@ -262,8 +264,8 @@ class BlogPostValidator extends BdfMessageValidator {
 		MessageId parentId = new MessageId(parentIdBytes);
 
 		// Get and Validate the Wrapped Comment
-		Group wGroup = groupFactory
-				.createGroup(BlogManagerImpl.CLIENT_ID, descriptor);
+		Group wGroup = groupFactory.createGroup(CLIENT_ID, CLIENT_VERSION,
+				descriptor);
 		BdfList wBodyList = BdfList.of(COMMENT.getInt(), comment, pOriginalId,
 				oldId, signature);
 		byte[] wBody = clientHelper.toByteArray(wBodyList);
diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java
index 3857f1fb5572cc5eb78f74474d503ff1603b8e8e..f4d94413d9634fd6861b5799a77e849682c55d99 100644
--- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java
@@ -496,7 +496,7 @@ class FeedManagerImpl implements FeedManager, Client, EventListener,
 	}
 
 	private Group getLocalGroup() {
-		return contactGroupFactory.createLocalGroup(CLIENT_ID);
+		return contactGroupFactory.createLocalGroup(CLIENT_ID, CLIENT_VERSION);
 	}
 
 }
diff --git a/briar-core/src/main/java/org/briarproject/briar/forum/ForumFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/forum/ForumFactoryImpl.java
index 5570d52542fcc8eed76d7bd51bbb8ae973dd32a7..d540661ec65a10b3b69efbe01bfb40e01f036fb6 100644
--- a/briar-core/src/main/java/org/briarproject/briar/forum/ForumFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/forum/ForumFactoryImpl.java
@@ -18,6 +18,7 @@ import javax.inject.Inject;
 import static org.briarproject.briar.api.forum.ForumConstants.FORUM_SALT_LENGTH;
 import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
 import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID;
+import static org.briarproject.briar.api.forum.ForumManager.CLIENT_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -52,7 +53,8 @@ class ForumFactoryImpl implements ForumFactory {
 		try {
 			BdfList forum = BdfList.of(name, salt);
 			byte[] descriptor = clientHelper.toByteArray(forum);
-			Group g = groupFactory.createGroup(CLIENT_ID, descriptor);
+			Group g = groupFactory.createGroup(CLIENT_ID, CLIENT_VERSION,
+					descriptor);
 			return new Forum(g, name, salt);
 		} catch (FormatException e) {
 			throw new AssertionError(e);
diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java
index aa8928985867ddd119931c3b06cd1821aff2f1eb..1bf8ea37a82c7ea00c276632813a88d47fe78063 100644
--- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java
+++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java
@@ -76,7 +76,6 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_
 import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_SIGNATURE;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_TIME;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_TRANSPORT;
-import static org.briarproject.briar.api.introduction.IntroductionConstants.PROTOCOL_VERSION;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US;
@@ -97,6 +96,7 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE;
+import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -435,7 +435,7 @@ class IntroduceeManager {
 		// The shared secret is derived from the local ephemeral key pair
 		// and the remote ephemeral public key
 		byte[][] inputs = {
-				new byte[] {PROTOCOL_VERSION},
+				new byte[] {CLIENT_VERSION},
 				alice ? ourPublicKeyBytes : theirPublicKeyBytes,
 				alice ? theirPublicKeyBytes : ourPublicKeyBytes
 		};
diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java
index 8aadc03d72eb4016826986fe36b0248ab36e7914..050d2b9f4430bcf38f950ea6c3dd941d0ac44cd2 100644
--- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java
+++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java
@@ -7,6 +7,7 @@ import org.briarproject.bramble.api.sync.Group;
 import javax.inject.Inject;
 
 import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID;
+import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION;
 
 class IntroductionGroupFactory {
 
@@ -16,14 +17,16 @@ class IntroductionGroupFactory {
 	@Inject
 	IntroductionGroupFactory(ContactGroupFactory contactGroupFactory) {
 		this.contactGroupFactory = contactGroupFactory;
-		localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID);
+		localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID,
+				CLIENT_VERSION);
 	}
 
 	Group createIntroductionGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(CLIENT_ID, c);
+		return contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, c);
 	}
 
-	public Group createLocalGroup() {
+	Group createLocalGroup() {
 		return localGroup;
 	}
 
diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java
index 2305dd47bed4b5c0e251add9fad57a5fd7acb519..c67d5913568770b3d45cf6b0e6d163a86073fbac 100644
--- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java
@@ -79,7 +79,8 @@ class MessagingManagerImpl extends ConversationClientImpl
 
 	@Override
 	public Group getContactGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(CLIENT_ID, c);
+		return contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, c);
 	}
 
 	@Override
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupFactoryImpl.java
index 4a19e68ebbe127840874063cc135a902953e5f80..bcf7846d62188ae676433a6ce6defa14d2cf1b30 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupFactoryImpl.java
@@ -20,6 +20,7 @@ import javax.inject.Inject;
 import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH;
 import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
 import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID;
+import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -64,7 +65,8 @@ class PrivateGroupFactoryImpl implements PrivateGroupFactory {
 					salt
 			);
 			byte[] descriptor = clientHelper.toByteArray(group);
-			Group g = groupFactory.createGroup(CLIENT_ID, descriptor);
+			Group g = groupFactory.createGroup(CLIENT_ID, CLIENT_VERSION,
+					descriptor);
 			return new PrivateGroup(g, name, author, salt);
 		} catch (FormatException e) {
 			throw new RuntimeException(e);
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationFactoryImpl.java
index d527674737daa3f52466a8cb5c51b58e9d7fcee5..29ca211f6debe399d920fe954aebc30be956fef1 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationFactoryImpl.java
@@ -17,6 +17,7 @@ import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
 import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID;
+import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -52,7 +53,7 @@ class GroupInvitationFactoryImpl implements GroupInvitationFactory {
 	public BdfList createInviteToken(AuthorId creatorId, AuthorId memberId,
 			GroupId privateGroupId, long timestamp) {
 		Group contactGroup = contactGroupFactory.createContactGroup(CLIENT_ID,
-				creatorId, memberId);
+				CLIENT_VERSION, creatorId, memberId);
 		return BdfList.of(
 				timestamp,
 				contactGroup.getId(),
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 1ae598c837aa6796dde6257e50a8baa561f33a48..0125b5e53ea5c3dead9346f5fa24a22948068535 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
@@ -132,7 +132,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
 
 	@Override
 	public Group getContactGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(CLIENT_ID, c);
+		return contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, c);
 	}
 
 	@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 f095aba4664968cffa4150e7e969c7a868d6d676..4c7863cd5b631bbaf9cd10dd1ee9d53d5417a4e1 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
@@ -51,6 +51,11 @@ class BlogSharingManagerImpl extends SharingManagerImpl<Blog>
 		return CLIENT_ID;
 	}
 
+	@Override
+	protected int getClientVersion() {
+		return CLIENT_VERSION;
+	}
+
 	/**
 	 * This is called during each startup for each existing Contact.
 	 */
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 c91fac76e6b687d0ee892de225620bf24dfb844b..528743b9cc6ba65d939f8db3c27ab7014d8e3b36 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
@@ -38,6 +38,11 @@ class ForumSharingManagerImpl extends SharingManagerImpl<Forum>
 		return CLIENT_ID;
 	}
 
+	@Override
+	protected int getClientVersion() {
+		return 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/SharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
index 75ab728ff85b16f00b0a8989b6ef58f611c674b8..b70fb74eaf3939733355483a232c8fcd50f9fbd0 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
@@ -80,6 +80,8 @@ abstract class SharingManagerImpl<S extends Shareable>
 
 	protected abstract ClientId getClientId();
 
+	protected abstract int getClientVersion();
+
 	@Override
 	public void createLocalState(Transaction txn) throws DbException {
 		// Ensure we've set things up for any pre-existing contacts
@@ -113,7 +115,8 @@ abstract class SharingManagerImpl<S extends Shareable>
 
 	@Override
 	public Group getContactGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(getClientId(), c);
+		return contactGroupFactory.createContactGroup(getClientId(),
+				getClientVersion(), c);
 	}
 
 	@Override
diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
index 988e3d48b932b19f8aa14ac7e9f17902e1531b64..3a7877a7802f23db87e6bc8797ee25364bf8efbf 100644
--- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
@@ -8,7 +8,6 @@ import org.briarproject.bramble.api.data.BdfList;
 import org.briarproject.bramble.api.data.MetadataEncoder;
 import org.briarproject.bramble.api.identity.Author;
 import org.briarproject.bramble.api.identity.AuthorId;
-import org.briarproject.bramble.api.sync.ClientId;
 import org.briarproject.bramble.api.sync.Group;
 import org.briarproject.bramble.api.sync.GroupFactory;
 import org.briarproject.bramble.api.sync.GroupId;
@@ -40,6 +39,8 @@ import static org.briarproject.briar.api.blog.BlogConstants.KEY_PARENT_MSG_ID;
 import static org.briarproject.briar.api.blog.BlogConstants.KEY_PUBLIC_KEY;
 import static org.briarproject.briar.api.blog.BlogConstants.KEY_READ;
 import static org.briarproject.briar.api.blog.BlogConstants.KEY_RSS_FEED;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_VERSION;
 import static org.briarproject.briar.api.blog.BlogPostFactory.SIGNING_LABEL_COMMENT;
 import static org.briarproject.briar.api.blog.BlogPostFactory.SIGNING_LABEL_POST;
 import static org.briarproject.briar.api.blog.MessageType.COMMENT;
@@ -54,7 +55,6 @@ public class BlogPostValidatorTest extends BriarTestCase {
 	private final Mockery context = new Mockery();
 	private final Blog blog, rssBlog;
 	private final BdfDictionary authorDict;
-	private final ClientId clientId;
 	private final byte[] descriptor;
 	private final Group group;
 	private final Message message;
@@ -69,9 +69,8 @@ public class BlogPostValidatorTest extends BriarTestCase {
 
 	public BlogPostValidatorTest() {
 		GroupId groupId = new GroupId(TestUtils.getRandomId());
-		clientId = BlogManagerImpl.CLIENT_ID;
 		descriptor = TestUtils.getRandomBytes(42);
-		group = new Group(groupId, clientId, descriptor);
+		group = new Group(groupId, CLIENT_ID, descriptor);
 		AuthorId authorId =
 				new AuthorId(TestUtils.getRandomBytes(AuthorId.LENGTH));
 		byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
@@ -215,7 +214,8 @@ public class BlogPostValidatorTest extends BriarTestCase {
 		byte[] originalBody = TestUtils.getRandomBytes(42);
 
 		context.checking(new Expectations() {{
-			oneOf(groupFactory).createGroup(clientId, descriptor);
+			oneOf(groupFactory).createGroup(CLIENT_ID, CLIENT_VERSION,
+					descriptor);
 			will(returnValue(b.getGroup()));
 			oneOf(blogFactory).parseBlog(b.getGroup());
 			will(returnValue(b));
@@ -258,7 +258,8 @@ public class BlogPostValidatorTest extends BriarTestCase {
 		byte[] originalBody = TestUtils.getRandomBytes(42);
 
 		context.checking(new Expectations() {{
-			oneOf(groupFactory).createGroup(clientId, descriptor);
+			oneOf(groupFactory).createGroup(CLIENT_ID, CLIENT_VERSION,
+					descriptor);
 			will(returnValue(blog.getGroup()));
 			oneOf(clientHelper).toByteArray(originalList);
 			will(returnValue(originalBody));
diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java
index e8e914dc88924ec6af7936ac70af442dcf88c5ac..2f7953311f1fdb0aba6934210aa2a990c011df9a 100644
--- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java
@@ -42,6 +42,7 @@ import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
 import static org.briarproject.bramble.test.TestUtils.getRandomId;
 import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEEDS;
 import static org.briarproject.briar.api.feed.FeedManager.CLIENT_ID;
+import static org.briarproject.briar.api.feed.FeedManager.CLIENT_VERSION;
 
 public class FeedManagerImplTest extends BrambleMockTestCase {
 
@@ -133,7 +134,8 @@ public class FeedManagerImplTest extends BrambleMockTestCase {
 
 	private void expectGetLocalGroup() {
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID);
+			oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID,
+					CLIENT_VERSION);
 			will(returnValue(localGroup));
 		}});
 	}
diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java
index d6478286fc962ec8c903cb378ffc00cad21c2ab7..896bdc2a31bec4946f57b39732c61f1dd4d81321 100644
--- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java
@@ -65,7 +65,6 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_
 import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LABEL;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.NONCE;
-import static org.briarproject.briar.api.introduction.IntroductionConstants.PROTOCOL_VERSION;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.SHARED_SECRET_LABEL;
@@ -76,6 +75,7 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.TRAN
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE;
+import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION;
 import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -755,7 +755,7 @@ public class IntroductionIntegrationTest
 
 		// Nonce 1
 		byte[][] inputs = {
-				new byte[] {PROTOCOL_VERSION},
+				new byte[] {CLIENT_VERSION},
 				eKeyPair1.getPublic().getEncoded(),
 				eKeyPair2.getPublic().getEncoded()
 		};
@@ -794,7 +794,7 @@ public class IntroductionIntegrationTest
 		// replace ephemeral key pair and recalculate matching keys and nonce
 		KeyPair eKeyPair1f = crypto.generateAgreementKeyPair();
 		byte[][] fakeInputs = {
-				new byte[] {PROTOCOL_VERSION},
+				new byte[] {CLIENT_VERSION},
 				eKeyPair1f.getPublic().getEncoded(),
 				eKeyPair2.getPublic().getEncoded()
 		};
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 50167d6e27636a48e1b005bb1809e536e3ccf994..c0e3b116b4c15ae5ffbc5c14fbc024aa879754e5 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
@@ -52,6 +52,7 @@ import static org.briarproject.bramble.util.StringUtils.getRandomString;
 import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH;
 import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
 import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID;
+import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.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;
@@ -162,7 +163,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 	private void expectAddingContact(Contact c, boolean contactExists)
 			throws Exception {
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, c);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, c);
 			will(returnValue(contactGroup));
 			oneOf(db).containsGroup(txn, contactGroup.getId());
 			will(returnValue(contactExists));
@@ -188,7 +190,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 
 	private void expectAddingMember(GroupId g, Contact c) throws Exception {
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, c);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, c);
 			will(returnValue(contactGroup));
 		}});
 		expectGetSession(noResults, new SessionId(g.getBytes()),
@@ -243,7 +246,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 	@Test
 	public void testRemovingContact() throws Exception {
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).removeGroup(txn, contactGroup);
 		}});
@@ -457,7 +461,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 		}});
 		expectCreateStorageId();
@@ -488,7 +493,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(sessionParser)
 					.parseCreatorSession(contactGroup.getId(), bdfSession);
@@ -516,7 +522,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).endTransaction(txn);
 		}});
@@ -567,7 +574,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(sessionParser)
 					.parseInviteeSession(contactGroup.getId(), bdfSession);
@@ -588,7 +596,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(sessionParser)
 					.parsePeerSession(contactGroup.getId(), bdfSession);
@@ -612,7 +621,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).endTransaction(txn);
 		}});
@@ -650,7 +660,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(messageParser).getMessagesVisibleInUiQuery();
 			will(returnValue(query));
@@ -726,7 +737,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContacts(txn);
 			will(returnValue(Collections.singletonList(contact)));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
 					contactGroup.getId(), query);
@@ -793,7 +805,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			throws Exception {
 		expectGetSession(oneResult, sessionId, contactGroup.getId());
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).startTransaction(true);
 			will(returnValue(txn));
@@ -847,11 +860,14 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 		context.checking(new Expectations() {{
 			oneOf(db).getContacts(txn);
 			will(returnValue(contacts));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact2);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact2);
 			will(returnValue(contactGroup2));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact3);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact3);
 			will(returnValue(contactGroup3));
 			// session 1
 			oneOf(sessionParser).getRole(bdfSession);
diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java
index 8a7a974a817a66ccbc27f28bc12a44ffbdb82b26..37bbe16e19261f980bee6d036b07a0f50254e2c6 100644
--- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java
@@ -32,6 +32,7 @@ import java.util.Collection;
 import java.util.List;
 
 import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_VERSION;
 import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -125,7 +126,7 @@ public class BlogSharingIntegrationTest
 
 		// get sharing group and assert group message count
 		GroupId g = contactGroupFactory.createContactGroup(CLIENT_ID,
-				contact1From0).getId();
+				CLIENT_VERSION, contact1From0).getId();
 		assertGroupCount(messageTracker0, g, 1, 0);
 
 		// sync first request message
@@ -200,7 +201,7 @@ public class BlogSharingIntegrationTest
 
 		// get sharing group and assert group message count
 		GroupId g = contactGroupFactory.createContactGroup(CLIENT_ID,
-				contact1From0).getId();
+				CLIENT_VERSION, contact1From0).getId();
 		assertGroupCount(messageTracker0, g, 1, 0);
 
 		// sync first request message
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 a7c76401723561a33efdd7dec370bfbcf5b697a9..22e9bbf6198502557237954f6d9a427354a2827f 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
@@ -39,6 +39,7 @@ import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
 import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
 import static org.briarproject.bramble.test.TestUtils.getRandomId;
 import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_VERSION;
 import static org.briarproject.briar.sharing.SharingConstants.GROUP_KEY_CONTACT_ID;
 
 public class BlogSharingManagerImplTest extends BrambleMockTestCase {
@@ -152,7 +153,8 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 		context.checking(new Expectations() {{
 			oneOf(db).getContacts(txn);
 			will(returnValue(contacts));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).containsGroup(txn, contactGroup.getId());
 			will(returnValue(false));
@@ -185,8 +187,8 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 				new Message(new MessageId(getRandomId()), contactGroup.getId(),
 						42L, getRandomBytes(1337));
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory)
-					.createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(sessionParser)
 					.getSessionQuery(new SessionId(blog.getId().getBytes()));
@@ -220,7 +222,8 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 		context.checking(new Expectations() {{
 			oneOf(db).getContacts(txn);
 			will(returnValue(contacts));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(sessionParser)
 					.getSessionQuery(new SessionId(blog.getId().getBytes()));
diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java
index 01cd70589fb3f01b3c9102cf2711faf404dc599c..bbc83660a006de207252894a6088eb52cd373308 100644
--- a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java
@@ -38,6 +38,8 @@ import java.util.List;
 
 import static junit.framework.Assert.assertNotNull;
 import static org.briarproject.bramble.util.StringUtils.getRandomString;
+import static org.briarproject.briar.api.forum.ForumSharingManager.CLIENT_ID;
+import static org.briarproject.briar.api.forum.ForumSharingManager.CLIENT_VERSION;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -399,9 +401,8 @@ public class ForumSharingIntegrationTest
 		assertTrue(listener0.responseReceived);
 
 		// response and invitation got tracked
-		Group group = contactGroupFactory
-				.createContactGroup(ForumSharingManager.CLIENT_ID,
-						contact0From1);
+		Group group = contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, contact0From1);
 		assertEquals(2, c1.getMessageTracker().getGroupCount(group.getId())
 				.getMsgCount());
 
@@ -432,9 +433,8 @@ public class ForumSharingIntegrationTest
 		assertEquals(1, forumSharingManager1.getInvitations().size());
 
 		// assert that the invitation arrived
-		Group group = contactGroupFactory
-				.createContactGroup(ForumSharingManager.CLIENT_ID,
-						contact0From1);
+		Group group = contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, contact0From1);
 		assertEquals(1, c1.getMessageTracker().getGroupCount(group.getId())
 				.getMsgCount());