diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx
index 12eef6e913de6118f4ebe4df8ff90178996208a3..9e924629eaf182bc8d379abbace113144d36c431 100644
--- a/src/containers/blocks.jsx
+++ b/src/containers/blocks.jsx
@@ -12,6 +12,7 @@ import Prompt from './prompt.jsx';
 import BlocksComponent from '../components/blocks/blocks.jsx';
 import ExtensionLibrary from './extension-library.jsx';
 import CustomProcedures from './custom-procedures.jsx';
+import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
 
 import {connect} from 'react-redux';
 import {updateToolbox} from '../reducers/toolbox';
@@ -415,7 +416,9 @@ const mapDispatchToProps = dispatch => ({
     }
 });
 
-export default connect(
-    mapStateToProps,
-    mapDispatchToProps
-)(Blocks);
+export default errorBoundaryHOC('Blocks')(
+    connect(
+        mapStateToProps,
+        mapDispatchToProps
+    )(Blocks)
+);
diff --git a/src/containers/costume-tab.jsx b/src/containers/costume-tab.jsx
index 0a360ba33720d75acf8ea0f577596b39b4df8ea4..8f203e63352c6709ec0b171071a6a38417e74e3c 100644
--- a/src/containers/costume-tab.jsx
+++ b/src/containers/costume-tab.jsx
@@ -11,6 +11,7 @@ import BackdropLibrary from './backdrop-library.jsx';
 import CameraModal from './camera-modal.jsx';
 import {connect} from 'react-redux';
 import {handleFileUpload, costumeUpload} from '../lib/file-uploader.js';
+import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
 
 import {
     closeCameraCapture,
@@ -367,7 +368,9 @@ const mapDispatchToProps = dispatch => ({
     }
 });
 
-export default injectIntl(connect(
-    mapStateToProps,
-    mapDispatchToProps
-)(CostumeTab));
+export default errorBoundaryHOC('Costume Tab')(
+    injectIntl(connect(
+        mapStateToProps,
+        mapDispatchToProps
+    )(CostumeTab))
+);
diff --git a/src/containers/error-boundary.jsx b/src/containers/error-boundary.jsx
index 0c855285777c3c33f2e08f26988be4368bcdb70b..c140d0ee78836632b9368960903905472bed82bd 100644
--- a/src/containers/error-boundary.jsx
+++ b/src/containers/error-boundary.jsx
@@ -4,6 +4,7 @@ import platform from 'platform';
 import BrowserModalComponent from '../components/browser-modal/browser-modal.jsx';
 import CrashMessageComponent from '../components/crash-message/crash-message.jsx';
 import log from '../lib/log.js';
+import supportedBrowser from '../lib/supported-browser';
 import analytics from '../lib/analytics';
 
 class ErrorBoundary extends React.Component {
@@ -20,14 +21,27 @@ class ErrorBoundary extends React.Component {
             stack: 'Unknown stack',
             message: 'Unknown error'
         };
+
         // Display fallback UI
         this.setState({hasError: true});
+
+        // Log errors to analytics, separating supported browsers from unsupported.
+        if (supportedBrowser()) {
+            analytics.event({
+                category: 'error',
+                action: this.props.action,
+                label: error.message
+            });
+        } else {
+            analytics.event({
+                category: 'Unsupported Browser Error',
+                action: `(Unsupported Browser) ${this.props.action}`,
+                label: `${platform.name} ${error.message}`
+            });
+        }
+
+        // Log error locally for debugging as well.
         log.error(`Unhandled Error: ${error.stack}\nComponent stack: ${info.componentStack}`);
-        analytics.event({
-            category: 'error',
-            action: 'Fatal Error',
-            label: error.message
-        });
     }
 
     handleBack () {
@@ -40,21 +54,17 @@ class ErrorBoundary extends React.Component {
 
     render () {
         if (this.state.hasError) {
-            // don't use array.includes because that's something that causes IE to crash.
-            if (
-                platform.name === 'IE' ||
-                platform.name === 'Opera' ||
-                platform.name === 'Opera Mini' ||
-                platform.name === 'Silk') {
-                return <BrowserModalComponent onBack={this.handleBack} />;
+            if (supportedBrowser()) {
+                return <CrashMessageComponent onReload={this.handleReload} />;
             }
-            return <CrashMessageComponent onReload={this.handleReload} />;
+            return <BrowserModalComponent onBack={this.handleBack} />;
         }
         return this.props.children;
     }
 }
 
 ErrorBoundary.propTypes = {
+    action: PropTypes.string.isRequired, // Used for defining tracking action
     children: PropTypes.node
 };
 
diff --git a/src/containers/preview-modal.jsx b/src/containers/preview-modal.jsx
index 2ed9e75c556b1abe6e6f2439f9ef0c8d0254ff39..a1a8a3c54979a98adf96e949c27f80732f8380ff 100644
--- a/src/containers/preview-modal.jsx
+++ b/src/containers/preview-modal.jsx
@@ -2,10 +2,10 @@ import bindAll from 'lodash.bindall';
 import PropTypes from 'prop-types';
 import React from 'react';
 import {connect} from 'react-redux';
-import platform from 'platform';
 
 import PreviewModalComponent from '../components/preview-modal/preview-modal.jsx';
 import BrowserModalComponent from '../components/browser-modal/browser-modal.jsx';
+import supportedBrowser from '../lib/supported-browser';
 
 import {
     closePreviewInfo,
@@ -35,18 +35,8 @@ class PreviewModal extends React.Component {
     handleViewProject () {
         this.props.onViewProject();
     }
-    supportedBrowser () {
-        if (
-            platform.name === 'IE' ||
-            platform.name === 'Opera' ||
-            platform.name === 'Opera Mini' ||
-            platform.name === 'Silk') {
-            return false;
-        }
-        return true;
-    }
     render () {
-        return (this.supportedBrowser() ?
+        return (supportedBrowser() ?
             <PreviewModalComponent
                 previewing={this.state.previewing}
                 onCancel={this.handleCancel}
diff --git a/src/containers/sound-tab.jsx b/src/containers/sound-tab.jsx
index ab4c9062bdebc5fa1b5055919a0df50bc1c3f3a3..e39a2b6d15f99e642dde3d02bcccead248c32ebf 100644
--- a/src/containers/sound-tab.jsx
+++ b/src/containers/sound-tab.jsx
@@ -17,6 +17,7 @@ import SoundLibrary from './sound-library.jsx';
 
 import soundLibraryContent from '../lib/libraries/sounds.json';
 import {handleFileUpload, soundUpload} from '../lib/file-uploader.js';
+import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
 
 import {connect} from 'react-redux';
 
@@ -260,7 +261,9 @@ const mapDispatchToProps = dispatch => ({
     }
 });
 
-export default injectIntl(connect(
-    mapStateToProps,
-    mapDispatchToProps
-)(SoundTab));
+export default errorBoundaryHOC('Sound Tab')(
+    injectIntl(connect(
+        mapStateToProps,
+        mapDispatchToProps
+    )(SoundTab))
+);
diff --git a/src/lib/app-state-hoc.jsx b/src/lib/app-state-hoc.jsx
index 6070c436be4d4c891873f6cf649bccfdd415e2de..91d4069f098426c10e53560ee78f6facd5f384f2 100644
--- a/src/lib/app-state-hoc.jsx
+++ b/src/lib/app-state-hoc.jsx
@@ -71,7 +71,7 @@ const AppStateHOC = function (WrappedComponent) {
             return (
                 <Provider store={this.store}>
                     <IntlProvider>
-                        <ErrorBoundary>
+                        <ErrorBoundary action="Top Level App">
                             <WrappedComponent {...this.props} />
                         </ErrorBoundary>
                     </IntlProvider>
diff --git a/src/lib/error-boundary-hoc.jsx b/src/lib/error-boundary-hoc.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..bdb6c8f6794b4ed60d101fa96633ad3836ed8d6b
--- /dev/null
+++ b/src/lib/error-boundary-hoc.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import ErrorBoundary from '../containers/error-boundary.jsx';
+
+/*
+ * Higher Order Component to provide error boundary for wrapped component.
+ * A curried function, call like errorHOC(<tracking label>)(<Component>).
+ * @param {string} action - Label for GA tracking of errors.
+ * @returns {function} a function that accepts a component to wrap.
+ */
+const ErrorBoundaryHOC = function (action){
+    /**
+     * The function to be called with a React component to wrap it.
+     * @param {React.Component} WrappedComponent - Component to wrap with an error boundary.
+     * @returns {React.Component} the component wrapped with an error boundary.
+     */
+    return function (WrappedComponent) {
+        const ErrorBoundaryWrapper = props => (
+            <ErrorBoundary action={action}>
+                <WrappedComponent {...props} />
+            </ErrorBoundary>
+        );
+        return ErrorBoundaryWrapper;
+    };
+};
+
+export default ErrorBoundaryHOC;
diff --git a/src/lib/supported-browser.js b/src/lib/supported-browser.js
new file mode 100644
index 0000000000000000000000000000000000000000..507fb1dcfce06fe6dbe181c1a9ed4b838bcd31ce
--- /dev/null
+++ b/src/lib/supported-browser.js
@@ -0,0 +1,16 @@
+import platform from 'platform';
+
+/**
+ * Helper function to determine if the browser is supported.
+ * @returns {boolean} False if the platform is definitely not supported.
+ */
+export default function () {
+    if (platform.name === 'IE' ||
+        platform.name === 'Opera' ||
+        platform.name === 'Opera Mini' ||
+        platform.name === 'Silk') {
+        return false;
+    }
+    // @todo Should also test for versions of supported browsers
+    return true;
+}