diff --git a/README.md b/README.md
index b080e856a7fdfe0f22328e5cd777a1d84450542d..d1f59cd4392fce9f8b2b541862e69fa684400039 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,16 @@ This repository contains the WebAssembly bindings for xxDK. It also includes
 examples and a test server to serve the compiled WebAssembly module.
 
 **Note:** If you are updating the version of Go that this repository uses, you
-need to ensure that you update the wasm_exec.js file as described
+need to ensure that you update the `wasm_exec.js` file as described
 [below](#wasm_execjs).
 
+## Updates
+
+The current semantic version of this repository is stored in `SEMVER` in
+`version.go`. When making major updates or updates that create an
+incompatibility in the storage or databases, the semantic version needs to be
+updated and an upgrade path needs to be provided.
+
 ## Building
 
 The repository can only be compiled to a WebAssembly binary using `GOOS=js` and
diff --git a/main.go b/main.go
index 0e067b2e46c0193c0f05907fa23fbd6a6e3c34d5..a7484593ddf3cef3fdb831ca1dd06da04d538548 100644
--- a/main.go
+++ b/main.go
@@ -26,6 +26,12 @@ func init() {
 	ll := wasm.NewJsConsoleLogListener(jww.LevelInfo)
 	jww.SetLogListeners(ll.Listen)
 	jww.SetStdoutThreshold(jww.LevelFatal + 1)
+
+	// Check that the WASM binary version is correct
+	err := utils.CheckAndStoreVersions()
+	if err != nil {
+		jww.FATAL.Panicf("WASM binary version error: %+v", err)
+	}
 }
 
 func main() {
diff --git a/utils/version.go b/utils/version.go
new file mode 100644
index 0000000000000000000000000000000000000000..ab26b463c72f958700840212795c6df63258d6c9
--- /dev/null
+++ b/utils/version.go
@@ -0,0 +1,97 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+//go:build js && wasm
+
+package utils
+
+import (
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/bindings"
+	"os"
+)
+
+// SEMVER is the current semantic version of xxDK WASM.
+const SEMVER = "0.0.0"
+
+// Storage keys.
+const (
+	semverKey    = "xxdkWasmSemanticVersion"
+	clientVerKey = "xxdkClientSemanticVersion"
+)
+
+// CheckAndStoreVersions checks that the stored xxDK WASM version matches the
+// current version and if not, upgrades it. It also stored the current xxDK
+// client to storage.
+//
+// On first load, only the xxDK WASM and xxDK client versions are stored.
+func CheckAndStoreVersions() error {
+	return checkAndStoreVersions(
+		SEMVER, bindings.GetVersion(), GetLocalStorage())
+}
+
+func checkAndStoreVersions(
+	currentWasmVer, currentClientVer string, ls *LocalStorage) error {
+	// Get the stored client and WASM versions, if they exists
+	storedClientVer, err := initOrLoadStoredSemver(
+		clientVerKey, currentClientVer, ls)
+	if err != nil {
+		return err
+	}
+	storedWasmVer, err := initOrLoadStoredSemver(semverKey, currentWasmVer, ls)
+	if err != nil {
+		return err
+	}
+
+	// Check if client needs an update
+	if storedClientVer != currentClientVer {
+		jww.INFO.Printf("xxDK client out of date; upgrading version: v%s → v%s",
+			storedClientVer, currentClientVer)
+	} else {
+		jww.INFO.Printf("xxDK client version is current: v%s", storedClientVer)
+	}
+
+	// Check if WASM needs an update
+	if storedWasmVer != currentWasmVer {
+		jww.INFO.Printf("xxDK WASM out of date; upgrading version: v%s → v%s",
+			storedWasmVer, currentWasmVer)
+	} else {
+		jww.INFO.Printf("xxDK WASM version is current: v%s", storedWasmVer)
+	}
+
+	// Upgrade path code goes here
+
+	// Save current versions
+	ls.SetItem(clientVerKey, []byte(currentClientVer))
+	ls.SetItem(semverKey, []byte(currentWasmVer))
+
+	return nil
+}
+
+// initOrLoadStoredSemver returns the semantic version stored at the key in
+// local storage. If no version is stored, then the current version is stored
+// and returned.
+func initOrLoadStoredSemver(
+	key, currentVersion string, ls *LocalStorage) (string, error) {
+	storedVersion, err := ls.GetItem(key)
+	if err != nil {
+		if errors.Is(err, os.ErrNotExist) {
+			// Save the current version if this is the first run
+			jww.INFO.Printf("Initialising %s to v%s", key, currentVersion)
+			ls.SetItem(key, []byte(currentVersion))
+			return currentVersion, nil
+		} else {
+			// If the item exists, but cannot be loaded, return an error
+			return "", errors.Errorf(
+				"could not load %s from storage: %+v", key, err)
+		}
+	}
+
+	// Return the stored version
+	return string(storedVersion), nil
+}
diff --git a/utils/version_test.go b/utils/version_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..f54465033749f094b03a705a552e464933bb04d5
--- /dev/null
+++ b/utils/version_test.go
@@ -0,0 +1,102 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+//go:build js && wasm
+
+package utils
+
+import (
+	"testing"
+)
+
+// Tests that checkAndStoreVersions correct initialises the client and WASM
+// versions on first run and upgrades them correctly on subsequent runs.
+func Test_checkAndStoreVersions(t *testing.T) {
+	ls := GetLocalStorage()
+	ls.Clear()
+	oldWasmVer := "0.1"
+	newWasmVer := "1.0"
+	oldClientVer := "2.5"
+	newClientVer := "2.6"
+	err := checkAndStoreVersions(oldWasmVer, oldClientVer, ls)
+	if err != nil {
+		t.Errorf("CheckAndStoreVersions error: %+v", err)
+	}
+
+	// Check client version
+	storedClientVer, err := ls.GetItem(clientVerKey)
+	if err != nil {
+		t.Errorf("Failed to get client version from storage: %+v", err)
+	}
+	if string(storedClientVer) != oldClientVer {
+		t.Errorf("Loaded client version does not match expected."+
+			"\nexpected: %s\nreceived: %s", oldClientVer, storedClientVer)
+	}
+
+	// Check WASM version
+	storedWasmVer, err := ls.GetItem(semverKey)
+	if err != nil {
+		t.Errorf("Failed to get WASM version from storage: %+v", err)
+	}
+	if string(storedWasmVer) != oldWasmVer {
+		t.Errorf("Loaded WASM version does not match expected."+
+			"\nexpected: %s\nreceived: %s", oldWasmVer, storedWasmVer)
+	}
+
+	err = checkAndStoreVersions(newWasmVer, newClientVer, ls)
+	if err != nil {
+		t.Errorf("CheckAndStoreVersions error: %+v", err)
+	}
+
+	// Check client version
+	storedClientVer, err = ls.GetItem(clientVerKey)
+	if err != nil {
+		t.Errorf("Failed to get client version from storage: %+v", err)
+	}
+	if string(storedClientVer) != newClientVer {
+		t.Errorf("Loaded client version does not match expected."+
+			"\nexpected: %s\nreceived: %s", newClientVer, storedClientVer)
+	}
+
+	// Check WASM version
+	storedWasmVer, err = ls.GetItem(semverKey)
+	if err != nil {
+		t.Errorf("Failed to get WASM version from storage: %+v", err)
+	}
+	if string(storedWasmVer) != newWasmVer {
+		t.Errorf("Loaded WASM version does not match expected."+
+			"\nexpected: %s\nreceived: %s", newWasmVer, storedWasmVer)
+	}
+}
+
+// Tests that initOrLoadStoredSemver initialises the correct version on first run
+// and returns the same version on subsequent runs.
+func Test_initOrLoadStoredSemver(t *testing.T) {
+	ls := GetLocalStorage()
+	key := "testKey"
+	oldVersion := "0.1"
+
+	loadedVersion, err := initOrLoadStoredSemver(key, oldVersion, ls)
+	if err != nil {
+		t.Errorf("Failed to intilaise version: %+v", err)
+	}
+
+	if loadedVersion != oldVersion {
+		t.Errorf("Loaded version does not match expected."+
+			"\nexpected: %s\nreceived: %s", oldVersion, loadedVersion)
+	}
+
+	loadedVersion, err = initOrLoadStoredSemver(key, "something", ls)
+	if err != nil {
+		t.Errorf("Failed to load version: %+v", err)
+	}
+
+	if loadedVersion != oldVersion {
+		t.Errorf("Loaded version does not match expected."+
+			"\nexpected: %s\nreceived: %s", oldVersion, loadedVersion)
+	}
+}