diff --git a/res/css/_components.scss b/res/css/_components.scss
index fe331504f2..c82dedc069 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -77,7 +77,6 @@
 @import "./views/elements/_Dropdown.scss";
 @import "./views/elements/_EditableItemList.scss";
 @import "./views/elements/_Field.scss";
-@import "./views/elements/_HexVerify.scss";
 @import "./views/elements/_ImageView.scss";
 @import "./views/elements/_InlineSpinner.scss";
 @import "./views/elements/_ManageIntegsButton.scss";
@@ -156,6 +155,7 @@
 @import "./views/settings/tabs/_SecuritySettingsTab.scss";
 @import "./views/settings/tabs/_SettingsTab.scss";
 @import "./views/settings/tabs/_VoiceSettingsTab.scss";
+@import "./views/verification/_VerificationShowSas.scss";
 @import "./views/voip/_CallView.scss";
 @import "./views/voip/_IncomingCallbox.scss";
 @import "./views/voip/_VideoView.scss";
diff --git a/res/css/views/elements/_HexVerify.scss b/res/css/views/verification/_VerificationShowSas.scss
similarity index 78%
rename from res/css/views/elements/_HexVerify.scss
rename to res/css/views/verification/_VerificationShowSas.scss
index 3f3ee4b7ea..32ccf6b0bb 100644
--- a/res/css/views/elements/_HexVerify.scss
+++ b/res/css/views/verification/_VerificationShowSas.scss
@@ -14,21 +14,9 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-.mx_HexVerify {
+.mx_VerificationShowSas_sas {
     text-align: center;
-}
-
-.mx_HexVerify_pair {
-    display: inline-block;
     font-weight: bold;
     padding-left: 3px;
     padding-right: 3px;
 }
-
-.mx_HexVerify_pair_verified {
-    color: $accent-color;
-}
-
-.mx_HexVerify_pair:hover{
-    color: $accent-color;
-}
diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js
index 882a913452..f283eb84a5 100644
--- a/src/MatrixClientPeg.js
+++ b/src/MatrixClientPeg.js
@@ -135,14 +135,7 @@ class MatrixClientPeg {
         const opts = utils.deepCopy(this.opts);
         // the react sdk doesn't work without this, so don't allow
         opts.pendingEventOrdering = "detached";
-
-        const LAZY_LOADING_FEATURE = "feature_lazyloading";
-        if (SettingsStore.isFeatureEnabled(LAZY_LOADING_FEATURE)) {
-            const userId = this.matrixClient.credentials.userId;
-            if (phasedRollOutExpiredForUser(userId, LAZY_LOADING_FEATURE, Date.now())) {
-                opts.lazyLoadMembers = true;
-            }
-        }
+        opts.lazyLoadMembers = true;
 
         // Connect the matrix client to the dispatcher
         MatrixActionCreators.start(this.matrixClient);
diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js
index 0ae9b032d1..bd49f8acd4 100644
--- a/src/components/structures/LeftPanel.js
+++ b/src/components/structures/LeftPanel.js
@@ -190,10 +190,13 @@ const LeftPanel = React.createClass({
 
         const tagPanelEnabled = SettingsStore.getValue("TagPanel.enableTagPanel");
         let tagPanelContainer;
+
+        const isCustomTagsEnabled = SettingsStore.isFeatureEnabled("feature_custom_tags");
+
         if (tagPanelEnabled) {
             tagPanelContainer = (<div className="mx_LeftPanel_tagPanelContainer">
                 <TagPanel />
-                <CustomRoomTagPanel />
+                { isCustomTagsEnabled ? <CustomRoomTagPanel /> : undefined }
                 <TagPanelButtons />
             </div>);
         }
diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js
index e5b82baa92..712d8d2b4e 100644
--- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js
+++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js
@@ -19,6 +19,8 @@ import sdk from '../../../../index';
 import MatrixClientPeg from '../../../../MatrixClientPeg';
 import Modal from '../../../../Modal';
 
+import { MatrixClient } from 'matrix-js-sdk';
+
 import { _t } from '../../../../languageHandler';
 
 const RESTORE_TYPE_PASSPHRASE = 0;
@@ -88,7 +90,7 @@ export default React.createClass({
         });
         try {
             const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithPassword(
-                this.state.passPhrase, undefined, undefined, this.state.backupInfo.version,
+                this.state.passPhrase, undefined, undefined, this.state.backupInfo,
             );
             this.setState({
                 loading: false,
@@ -107,11 +109,11 @@ export default React.createClass({
         this.setState({
             loading: true,
             restoreError: null,
-            restoreType: RESTORE_TYPE_PASSPHRASE,
+            restoreType: RESTORE_TYPE_RECOVERYKEY,
         });
         try {
             const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithRecoveryKey(
-                this.state.recoveryKey, undefined, undefined, this.state.backupInfo.version,
+                this.state.recoveryKey, undefined, undefined, this.state.backupInfo,
             );
             this.setState({
                 loading: false,
@@ -185,32 +187,31 @@ export default React.createClass({
             title = _t("Error");
             content = _t("Unable to load backup status");
         } else if (this.state.restoreError) {
-            title = _t("Error");
-            content = _t("Unable to restore backup");
+            if (this.state.restoreError.errcode === MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY) {
+                if (this.state.restoreType === RESTORE_TYPE_RECOVERYKEY) {
+                    title = _t("Recovery Key Mismatch");
+                    content = <div>
+                        <p>{_t(
+                            "Backup could not be decrypted with this key: " +
+                            "please verify that you entered the correct recovery key.",
+                        )}</p>
+                    </div>;
+                } else {
+                    title = _t("Incorrect Recovery Passphrase");
+                    content = <div>
+                        <p>{_t(
+                            "Backup could not be decrypted with this passphrase: " +
+                            "please verify that you entered the correct recovery passphrase.",
+                        )}</p>
+                    </div>;
+                }
+            } else {
+                title = _t("Error");
+                content = _t("Unable to restore backup");
+            }
         } else if (this.state.backupInfo === null) {
             title = _t("Error");
             content = _t("No backup found!");
-        } else if (
-            this.state.recoverInfo &&
-            this.state.recoverInfo.imported === 0 &&
-            this.state.recoverInfo.total > 0
-        ) {
-            title = _t("Error Restoring Backup");
-            if (this.state.restoreType === RESTORE_TYPE_RECOVERYKEY) {
-                content = <div>
-                    <p>{_t(
-                        "Backup could not be decrypted with this key: " +
-                        "please verify that you entered the correct recovery key.",
-                    )}</p>
-                </div>;
-            } else {
-                content = <div>
-                    <p>{_t(
-                        "Backup could not be decrypted with this passphrase: " +
-                        "please verify that you entered the correct recovery passphrase.",
-                    )}</p>
-                </div>;
-            }
         } else if (this.state.recoverInfo) {
             title = _t("Backup Restored");
             let failedToDecrypt;
diff --git a/src/components/views/elements/HexVerify.js b/src/components/views/elements/HexVerify.js
deleted file mode 100644
index 86ead3adc1..0000000000
--- a/src/components/views/elements/HexVerify.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-Copyright 2019 New Vector Ltd.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import React from "react";
-import PropTypes from "prop-types";
-import classnames from 'classnames';
-
-import sdk from '../../../index';
-
-class HexVerifyPair extends React.Component {
-    static propTypes = {
-        text: PropTypes.string.isRequired,
-        index: PropTypes.number,
-        verified: PropTypes.bool,
-        onChange: PropTypes.func.isRequired,
-    }
-
-    _onClick = () => {
-        this.setState({verified: !this.props.verified});
-        this.props.onChange(this.props.index, !this.props.verified);
-    }
-
-    render() {
-        const classNames = {
-            mx_HexVerify_pair: true,
-            mx_HexVerify_pair_verified: this.props.verified,
-        };
-        const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton');
-        return <AccessibleButton className={classnames(classNames)}
-            onClick={this._onClick}
-        >
-            {this.props.text}
-        </AccessibleButton>;
-    }
-}
-
-/*
- * Helps a user verify a hexadecimal code matches one displayed
- * elsewhere (eg. on a different device)
- */
-export default class HexVerify extends React.Component {
-    static propTypes = {
-        text: PropTypes.string.isRequired,
-        onVerifiedStateChange: PropTypes.func,
-    }
-
-    static defaultProps = {
-        onVerifiedStateChange: function() {},
-    }
-
-    constructor(props) {
-        super(props);
-        this.state = {
-            pairsVerified: [],
-        };
-        for (let i = 0; i < props.text.length; i += 2) {
-            this.state.pairsVerified.push(false);
-        }
-    }
-
-    _onPairChange = (index, newVal) => {
-        const oldVerified = this.state.pairsVerified.reduce((acc, val) => {
-            return acc && val;
-        }, true);
-        const newPairsVerified = this.state.pairsVerified.slice(0);
-        newPairsVerified[index] = newVal;
-        const newVerified = newPairsVerified.reduce((acc, val) => {
-            return acc && val;
-        }, true);
-        this.setState({pairsVerified: newPairsVerified});
-        if (oldVerified !== newVerified) {
-            this.props.onVerifiedStateChange(newVerified);
-        }
-    }
-
-    render() {
-        const pairs = [];
-
-        for (let i = 0; i < this.props.text.length / 2; ++i) {
-            pairs.push(<HexVerifyPair key={i} index={i}
-                text={this.props.text.substr(i * 2, 2)}
-                verified={this.state.pairsVerified[i]}
-                onChange={this._onPairChange}
-            />);
-        }
-        return <div className="mx_HexVerify">
-            {pairs}
-        </div>;
-    }
-}
diff --git a/src/components/views/elements/ToggleSwitch.js b/src/components/views/elements/ToggleSwitch.js
index 19c87aab56..0d8b3d042f 100644
--- a/src/components/views/elements/ToggleSwitch.js
+++ b/src/components/views/elements/ToggleSwitch.js
@@ -38,6 +38,12 @@ export default class ToggleSwitch extends React.Component {
         };
     }
 
+    componentWillReceiveProps(nextProps) {
+        if (nextProps.checked !== this.state.checked) {
+            this.setState({checked: nextProps.checked});
+        }
+    }
+
     _onClick = (e) => {
         e.stopPropagation();
         e.preventDefault();
diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js
index 8418ab6d6f..56eb4b713d 100644
--- a/src/components/views/rooms/RoomList.js
+++ b/src/components/views/rooms/RoomList.js
@@ -172,11 +172,14 @@ module.exports = React.createClass({
             this._delayedRefreshRoomList();
         });
 
-        this._customTagStoreToken = CustomRoomTagStore.addListener(() => {
-            this.setState({
-                customTags: CustomRoomTagStore.getTags(),
+
+        if (SettingsStore.isFeatureEnabled("feature_custom_tags")) {
+            this._customTagStoreToken = CustomRoomTagStore.addListener(() => {
+                this.setState({
+                    customTags: CustomRoomTagStore.getTags(),
+                });
             });
-        });
+        }
 
         this.refreshRoomList();
 
@@ -728,7 +731,8 @@ module.exports = React.createClass({
         ];
         const tagSubLists = Object.keys(this.state.lists)
             .filter((tagName) => {
-                return this.state.customTags[tagName] && !tagName.match(STANDARD_TAGS_REGEX);
+                return (!this.state.customTags || this.state.customTags[tagName]) &&
+                    !tagName.match(STANDARD_TAGS_REGEX);
             }).map((tagName) => {
                 return {
                     list: this.state.lists[tagName],
diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js
index 15856a75f3..cbbca42927 100644
--- a/src/components/views/settings/KeyBackupPanel.js
+++ b/src/components/views/settings/KeyBackupPanel.js
@@ -250,19 +250,26 @@ export default class KeyBackupPanel extends React.PureComponent {
                 backupSigStatuses = _t("Backup is not signed by any of your devices");
             }
 
+            let trustedLocally;
+            if (this.state.backupSigStatus.trusted_locally) {
+                trustedLocally = _t("This backup is trusted because it has been restored on this device");
+            }
+
             return <div>
-                {_t("Backup version: ")}{this.state.backupInfo.version}<br />
-                {_t("Algorithm: ")}{this.state.backupInfo.algorithm}<br />
-                {clientBackupStatus}<br />
+                <div>{_t("Backup version: ")}{this.state.backupInfo.version}</div>
+                <div>{_t("Algorithm: ")}{this.state.backupInfo.algorithm}</div>
+                <div>{clientBackupStatus}</div>
                 {uploadStatus}
-                <div>{backupSigStatuses}</div><br />
-                <br />
-                <AccessibleButton kind="primary" onClick={this._restoreBackup}>
-                    { _t("Restore backup") }
-                </AccessibleButton>&nbsp;&nbsp;&nbsp;
-                <AccessibleButton kind="danger" onClick={this._deleteBackup}>
-                    { _t("Delete backup") }
-                </AccessibleButton>
+                <div>{backupSigStatuses}</div>
+                <div>{trustedLocally}</div>
+                <p>
+                    <AccessibleButton kind="primary" onClick={this._restoreBackup}>
+                        { _t("Restore backup") }
+                    </AccessibleButton>&nbsp;&nbsp;&nbsp;
+                    <AccessibleButton kind="danger" onClick={this._deleteBackup}>
+                        { _t("Delete backup") }
+                    </AccessibleButton>
+                </p>
             </div>;
         } else {
             return <div>
diff --git a/src/components/views/settings/tabs/LabsSettingsTab.js b/src/components/views/settings/tabs/LabsSettingsTab.js
index fc64c1bd04..e06f87460b 100644
--- a/src/components/views/settings/tabs/LabsSettingsTab.js
+++ b/src/components/views/settings/tabs/LabsSettingsTab.js
@@ -18,9 +18,7 @@ import React from 'react';
 import {_t} from "../../../../languageHandler";
 import PropTypes from "prop-types";
 import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore";
-import MatrixClientPeg from "../../../../MatrixClientPeg";
 import LabelledToggleSwitch from "../../elements/LabelledToggleSwitch";
-const Modal = require("../../../../Modal");
 const sdk = require("../../../../index");
 
 export class LabsSettingToggle extends React.Component {
@@ -28,38 +26,7 @@ export class LabsSettingToggle extends React.Component {
         featureId: PropTypes.string.isRequired,
     };
 
-    async _onLazyLoadChanging(enabling) {
-        // don't prevent turning LL off when not supported
-        if (enabling) {
-            const supported = await MatrixClientPeg.get().doesServerSupportLazyLoading();
-            if (!supported) {
-                await new Promise((resolve) => {
-                    const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
-                    Modal.createDialog(QuestionDialog, {
-                        title: _t("Lazy loading members not supported"),
-                        description:
-                            <div>
-                                { _t("Lazy loading is not supported by your " +
-                                    "current homeserver.") }
-                            </div>,
-                        button: _t("OK"),
-                        onFinished: resolve,
-                    });
-                });
-                return false;
-            }
-        }
-        return true;
-    }
-
     _onChange = async (checked) => {
-        if (this.props.featureId === "feature_lazyloading") {
-            const confirmed = await this._onLazyLoadChanging(checked);
-            if (!confirmed) {
-                return;
-            }
-        }
-
         await SettingsStore.setFeatureEnabled(this.props.featureId, checked);
         this.forceUpdate();
     };
diff --git a/src/components/views/settings/tabs/SecurityRoomSettingsTab.js b/src/components/views/settings/tabs/SecurityRoomSettingsTab.js
index df6648c4a6..593e8151d2 100644
--- a/src/components/views/settings/tabs/SecurityRoomSettingsTab.js
+++ b/src/components/views/settings/tabs/SecurityRoomSettingsTab.js
@@ -27,8 +27,27 @@ export default class SecurityRoomSettingsTab extends React.Component {
         roomId: PropTypes.string.isRequired,
     };
 
+    constructor() {
+        super();
+
+        this.state = {
+            joinRule: "invite",
+            guestAccess: "can_join",
+            history: "shared",
+            encrypted: false,
+        };
+    }
+
     componentWillMount(): void {
         MatrixClientPeg.get().on("RoomState.events", this._onStateEvent);
+
+        const room = MatrixClientPeg.get().getRoom(this.props.roomId);
+        const state = room.currentState;
+        const joinRule = state.getStateEvents("m.room.join_rules", "").getContent()['join_rule'];
+        const guestAccess = state.getStateEvents("m.room.guest_access", "").getContent()['guest_access'];
+        const history = state.getStateEvents("m.room.history_visibility", "").getContent()['history_visibility'];
+        const encrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.roomId);
+        this.setState({joinRule, guestAccess, history, encrypted});
     }
 
     componentWillUnmount(): void {
@@ -46,19 +65,37 @@ export default class SecurityRoomSettingsTab extends React.Component {
     };
 
     _onEncryptionChange = (e) => {
+        const beforeEncrypted = this.state.encrypted;
+        this.setState({encrypted: true});
         MatrixClientPeg.get().sendStateEvent(
             this.props.roomId, "m.room.encryption",
             { algorithm: "m.megolm.v1.aes-sha2" },
-        );
+        ).catch((e) => {
+            console.error(e);
+            this.setState({encrypted: beforeEncrypted});
+        });
     };
 
     _fixGuestAccess = (e) => {
         e.preventDefault();
         e.stopPropagation();
 
+        const joinRule = "invite";
+        const guestAccess = "can_join";
+
+        const beforeJoinRule = this.state.joinRule;
+        const beforeGuestAccess = this.state.guestAccess;
+        this.setState({joinRule, guestAccess});
+
         const client = MatrixClientPeg.get();
-        client.sendStateEvent(this.props.roomId, "m.room.join_rules", {join_rule: "invite"}, "");
-        client.sendStateEvent(this.props.roomId, "m.room.guest_access", {guest_access: "can_join"}, "");
+        client.sendStateEvent(this.props.roomId, "m.room.join_rules", {join_rule: joinRule}, "").catch((e) => {
+            console.error(e);
+            this.setState({joinRule: beforeJoinRule});
+        });
+        client.sendStateEvent(this.props.roomId, "m.room.guest_access", {guest_access: guestAccess}, "").catch((e) => {
+            console.error(e);
+            this.setState({guestAccess: beforeGuestAccess});
+        });
     };
 
     _onRoomAccessRadioToggle = (ev) => {
@@ -92,24 +129,39 @@ export default class SecurityRoomSettingsTab extends React.Component {
                 break;
         }
 
+        const beforeJoinRule = this.state.joinRule;
+        const beforeGuestAccess = this.state.guestAccess;
+        this.setState({joinRule, guestAccess});
+
         const client = MatrixClientPeg.get();
-        client.sendStateEvent(this.props.roomId, "m.room.join_rules", {join_rule: joinRule}, "");
-        client.sendStateEvent(this.props.roomId, "m.room.guest_access", {guest_access: guestAccess}, "");
+        client.sendStateEvent(this.props.roomId, "m.room.join_rules", {join_rule: joinRule}, "").catch((e) => {
+            console.error(e);
+            this.setState({joinRule: beforeJoinRule});
+        });
+        client.sendStateEvent(this.props.roomId, "m.room.guest_access", {guest_access: guestAccess}, "").catch((e) => {
+            console.error(e);
+            this.setState({guestAccess: beforeGuestAccess});
+        });
     };
 
     _onHistoryRadioToggle = (ev) => {
+        const beforeHistory = this.state.history;
+        this.setState({history: ev.target.value});
         MatrixClientPeg.get().sendStateEvent(this.props.roomId, "m.room.history_visibility", {
             history_visibility: ev.target.value,
-        }, "");
+        }, "").catch((e) => {
+            console.error(e);
+            this.setState({history: beforeHistory});
+        });
     };
 
     _renderRoomAccess() {
         const client = MatrixClientPeg.get();
         const room = client.getRoom(this.props.roomId);
-        const joinRule = room.currentState.getStateEvents("m.room.join_rules", "").getContent()['join_rule'];
-        const guestAccess = room.currentState.getStateEvents("m.room.guest_access", "").getContent()['guest_access'];
+        const joinRule = this.state.joinRule;
+        const guestAccess = this.state.guestAccess;
         const aliasEvents = room.currentState.getStateEvents("m.room.aliases") || [];
-        const hasAliases = aliasEvents.includes((ev) => (ev.getContent().aliases || []).length);
+        const hasAliases = !!aliasEvents.find((ev) => (ev.getContent().aliases || []).length > 0);
 
         const canChangeAccess = room.currentState.mayClientSendStateEvent("m.room.join_rules", client)
             && room.currentState.mayClientSendStateEvent("m.room.guest_access", client);
@@ -170,9 +222,8 @@ export default class SecurityRoomSettingsTab extends React.Component {
 
     _renderHistory() {
         const client = MatrixClientPeg.get();
-        const room = client.getRoom(this.props.roomId);
-        const state = room.currentState;
-        const history = state.getStateEvents("m.room.history_visibility", "").getContent()['history_visibility'];
+        const history = this.state.history;
+        const state = client.getRoom(this.props.roomId).currentState;
         const canChangeHistory = state.mayClientSendStateEvent('m.room.history_visibility', client);
 
         return (
@@ -218,7 +269,7 @@ export default class SecurityRoomSettingsTab extends React.Component {
 
         const client = MatrixClientPeg.get();
         const room = client.getRoom(this.props.roomId);
-        const isEncrypted = client.isRoomEncrypted(this.props.roomId);
+        const isEncrypted = this.state.encrypted;
         const hasEncryptionPermission = room.currentState.mayClientSendStateEvent("m.room.encryption", client);
         const canEnableEncryption = !isEncrypted && hasEncryptionPermission;
 
diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js
index 6f3209989e..0224571d9e 100644
--- a/src/components/views/verification/VerificationShowSas.js
+++ b/src/components/views/verification/VerificationShowSas.js
@@ -28,19 +28,11 @@ export default class VerificationShowSas extends React.Component {
 
     constructor() {
         super();
-        this.state = {
-            sasVerified: false,
-        };
-    }
-
-    _onVerifiedStateChange = (newVal) => {
-        this.setState({sasVerified: newVal});
     }
 
     render() {
         const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
-        const HexVerify = sdk.getComponent('views.elements.HexVerify');
-        return <div>
+        return <div className="mx_VerificationShowSas">
             <p>{_t(
                 "Verify this user by confirming the following number appears on their screen.",
             )}</p>
@@ -48,15 +40,11 @@ export default class VerificationShowSas extends React.Component {
                 "For maximum security, we recommend you do this in person or use another " +
                 "trusted means of communication.",
             )}</p>
-            <HexVerify text={this.props.sas}
-                onVerifiedStateChange={this._onVerifiedStateChange}
-            />
-            <p>{_t(
-                "To continue, click on each pair to confirm it's correct.",
-            )}</p>
+            <div className="mx_VerificationShowSas_sas">
+                {this.props.sas}
+            </div>
             <DialogButtons onPrimaryButtonClick={this.props.onDone}
                 primaryButton={_t("Continue")}
-                primaryDisabled={!this.state.sasVerified}
                 hasCancel={true}
                 onCancel={this.props.onCancel}
             />
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 244db0aca9..621a00066a 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -270,7 +270,7 @@
     "Failed to join room": "Failed to join room",
     "Message Pinning": "Message Pinning",
     "Custom user status messages": "Custom user status messages",
-    "Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view",
+    "Group & filter rooms by custom tags (refresh to apply changes)": "Group & filter rooms by custom tags (refresh to apply changes)",
     "Backup of encryption keys to server": "Backup of encryption keys to server",
     "Render simple counters in room header": "Render simple counters in room header",
     "Two-way device verification using short text": "Two-way device verification using short text",
@@ -391,6 +391,7 @@
     "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>",
     "Verify...": "Verify...",
     "Backup is not signed by any of your devices": "Backup is not signed by any of your devices",
+    "This backup is trusted because it has been restored on this device": "This backup is trusted because it has been restored on this device",
     "Backup version: ": "Backup version: ",
     "Algorithm: ": "Algorithm: ",
     "Restore backup": "Restore backup",
@@ -482,8 +483,6 @@
     "Identity Server is": "Identity Server is",
     "Access Token:": "Access Token:",
     "click to reveal": "click to reveal",
-    "Lazy loading members not supported": "Lazy loading members not supported",
-    "Lazy loading is not supported by your current homeserver.": "Lazy loading is not supported by your current homeserver.",
     "Labs": "Labs",
     "Notifications": "Notifications",
     "Start automatically after system login": "Start automatically after system login",
@@ -1101,11 +1100,12 @@
     "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.",
     "Unknown devices": "Unknown devices",
     "Unable to load backup status": "Unable to load backup status",
+    "Recovery Key Mismatch": "Recovery Key Mismatch",
+    "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.",
+    "Incorrect Recovery Passphrase": "Incorrect Recovery Passphrase",
+    "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.",
     "Unable to restore backup": "Unable to restore backup",
     "No backup found!": "No backup found!",
-    "Error Restoring Backup": "Error Restoring Backup",
-    "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.",
-    "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.",
     "Backup Restored": "Backup Restored",
     "Failed to decrypt %(failedCount)s sessions!": "Failed to decrypt %(failedCount)s sessions!",
     "Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys",
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index c5de7298de..02c2bad14b 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -21,7 +21,6 @@ import {
     NotificationBodyEnabledController,
     NotificationsEnabledController,
 } from "./controllers/NotificationControllers";
-import LazyLoadingController from "./controllers/LazyLoadingController";
 import CustomStatusController from "./controllers/CustomStatusController";
 
 // These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
@@ -100,12 +99,11 @@ export const SETTINGS = {
         default: false,
         controller: new CustomStatusController(),
     },
-    "feature_lazyloading": {
+    "feature_custom_tags": {
         isFeature: true,
-        displayName: _td("Increase performance by only loading room members on first view"),
+        displayName: _td("Group & filter rooms by custom tags (refresh to apply changes)"),
         supportedLevels: LEVELS_FEATURE,
-        controller: new LazyLoadingController(),
-        default: true,
+        default: false,
     },
     "feature_keybackup": {
         isFeature: true,
diff --git a/src/settings/controllers/LazyLoadingController.js b/src/settings/controllers/LazyLoadingController.js
deleted file mode 100644
index 90f095c9ca..0000000000
--- a/src/settings/controllers/LazyLoadingController.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-Copyright 2018 New Vector
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import SettingController from "./SettingController";
-import MatrixClientPeg from "../../MatrixClientPeg";
-import PlatformPeg from "../../PlatformPeg";
-
-export default class LazyLoadingController extends SettingController {
-    async onChange(level, roomId, newValue) {
-        if (!PlatformPeg.get()) return;
-
-        MatrixClientPeg.get().stopClient();
-        await MatrixClientPeg.get().store.deleteAllData();
-        PlatformPeg.get().reload();
-    }
-}
diff --git a/src/stores/CustomRoomTagStore.js b/src/stores/CustomRoomTagStore.js
index 9795abadc6..0f7f99aad9 100644
--- a/src/stores/CustomRoomTagStore.js
+++ b/src/stores/CustomRoomTagStore.js
@@ -18,6 +18,7 @@ import * as RoomNotifs from '../RoomNotifs';
 import RoomListStore from './RoomListStore';
 import EventEmitter from 'events';
 import { throttle } from "lodash";
+import SettingsStore from "../settings/SettingsStore";
 
 const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority|server_notice)|im\.vector\.fake\.(invite|recent|direct|archived))$/;
 
@@ -50,6 +51,7 @@ class CustomRoomTagStore extends EventEmitter {
         super();
         // Initialise state
         this._state = {tags: {}};
+
         // as RoomListStore gets updated by every timeline event
         // throttle this to only run every 500ms
         this._getUpdatedTags = throttle(
@@ -133,6 +135,10 @@ class CustomRoomTagStore extends EventEmitter {
     }
 
     _getUpdatedTags() {
+        if (!SettingsStore.isFeatureEnabled("feature_custom_tags")) {
+            return;
+        }
+
         const newTagNames = Object.keys(RoomListStore.getRoomLists())
             .filter((tagName) => {
                 return !tagName.match(STANDARD_TAGS_REGEX);
diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js
index 61e17821bd..d98adc5cae 100644
--- a/src/stores/RoomListStore.js
+++ b/src/stores/RoomListStore.js
@@ -202,6 +202,8 @@ class RoomListStore extends Store {
         // If somehow we dispatched a RoomListActions.tagRoom.failure before a MatrixActions.sync
         if (!this._matrixClient) return;
 
+        const isCustomTagsEnabled = SettingsStore.isFeatureEnabled("feature_custom_tags");
+
         this._matrixClient.getRooms().forEach((room, index) => {
             const myUserId = this._matrixClient.getUserId();
             const membership = room.getMyMembership();
@@ -226,7 +228,7 @@ class RoomListStore extends Store {
 
                 // ignore any m. tag names we don't know about
                 tagNames = tagNames.filter((t) => {
-                    return !t.startsWith('m.') || lists[t] !== undefined;
+                    return (isCustomTagsEnabled && !t.startsWith('m.')) || lists[t] !== undefined;
                 });
 
                 if (tagNames.length) {