diff --git a/resources/static/communication_iframe/start.js b/resources/static/communication_iframe/start.js
index 4d9de7afbdf1921cabcc1e5b9dd8519d1f996d1b..506b74c0ea2a7a9561866173f9a746ddcf98e0fa 100644
--- a/resources/static/communication_iframe/start.js
+++ b/resources/static/communication_iframe/start.js
@@ -28,16 +28,7 @@
 
   var loggedInUser = undefined;
 
-  // one of two events will cause us to begin checking to
-  // see if an event shall be emitted - either an explicit
-  // loggedInUser event or page load.
-  chan.bind("loggedInUser", function(trans, email) {
-    loggedInUser = email;
-  });
-
-  chan.bind("loaded", function(trans, params) {
-    setRemoteOrigin(trans.origin);
-
+  function checkAndEmit() {
     user.getSilentAssertion(loggedInUser, function(email, assertion) {
       if (email) {
         // only send login events when the assertion is defined - when
@@ -45,15 +36,34 @@
         // when the site already has the user logged in and does not want
         // the resources or cost required to generate an assertion
         if (assertion) chan.notify({ method: 'login', params: assertion });
+        loggedInUser = email;
       } else if (loggedInUser !== null) {
         // only send logout events when loggedInUser is not null, which is an
         // indicator that the site thinks the user is logged out
         chan.notify({ method: 'logout' });
+        loggedInUser = null;
       }
     }, function(err) {
       chan.notify({ method: 'logout' });
+      loggedInUser = null;
     });
+  }
 
+  function watchState() {
+    storage.watchLoggedIn(remoteOrigin, checkAndEmit);
+  }
+
+  // one of two events will cause us to begin checking to
+  // see if an event shall be emitted - either an explicit
+  // loggedInUser event or page load.
+  chan.bind("loggedInUser", function(trans, email) {
+    loggedInUser = email;
+  });
+
+  chan.bind("loaded", function(trans, params) {
+    setRemoteOrigin(trans.origin);
+    checkAndEmit();
+    watchState();
     trans.complete();
   });
 
diff --git a/resources/static/css/style.css b/resources/static/css/style.css
index cab5f6f6f370ed8554dd055e3509186c942069f5..23781ec37d78e6dbb92f6b337e3e8432b4f6fd98 100644
--- a/resources/static/css/style.css
+++ b/resources/static/css/style.css
@@ -404,6 +404,13 @@ div.steps {
   margin-right: 0;
 }
 
+#logout_everywhere .completion_text {
+    float: right;
+    display: none;
+    color: #090;
+}
+
+
 button.delete {
   background-color: #EA7676;
   border: 1px solid #B13D3D;
diff --git a/resources/static/pages/manage_account.js b/resources/static/pages/manage_account.js
index 9bb92ea310d2570617ea49a45a78dcb5aa8d947d..59bc9ccc3154516c4956f224e02b4e13ecff9938 100644
--- a/resources/static/pages/manage_account.js
+++ b/resources/static/pages/manage_account.js
@@ -96,6 +96,11 @@ BrowserID.manageAccount = (function() {
     }
   }
 
+  function logoutEverywhere(oncomplete) {
+    storage.logoutEverywhere();
+    setTimeout(oncomplete, 0);
+  }
+
   function startEdit(event) {
     // XXX add some helpers in the dom library to find section.
     event.preventDefault();
@@ -194,6 +199,13 @@ BrowserID.manageAccount = (function() {
 
     dom.bindEvent("button.edit", "click", startEdit);
     dom.bindEvent("button.done", "click", cancelEdit);
+    dom.bindEvent("button.logout_everywhere", "click", function() {
+      logoutEverywhere(function() {
+        $("button.logout_everywhere").fadeOut(700, function() {
+          $("#logout_everywhere .completion_text").show();
+        });
+      });
+    });
     dom.bindEvent("#edit_password_form", "submit", cancelEvent(changePassword));
 
     user.checkAuthentication(function(auth_level) {
diff --git a/resources/static/shared/storage.js b/resources/static/shared/storage.js
index 0e7cfa0deb376f79c80130579555d354528f7d75..b21fbbcbe282919ab97595769a8292ce721d7dbd 100644
--- a/resources/static/shared/storage.js
+++ b/resources/static/shared/storage.js
@@ -187,9 +187,23 @@ BrowserID.Storage = (function() {
     return allInfo[origin];
   }
   function watchLoggedIn(origin, callback) {
-    throw "not yet implemented";
-  }
+    var lastState = getLoggedIn(origin);
+
+    function checkState() {
+      var currentState = getLoggedIn(origin);
+      if (lastState !== currentState) {
+        callback();
+        lastState = currentState;
+      };
+    }
 
+    // does IE8 not have addEventListener, nor does it support storage events.
+    if (window.addEventListener) window.addEventListener('storage', checkState, false);
+    else window.setInterval(checkState, 2000);
+  }
+  function logoutEverywhere() {
+    storage.loggedIn = "{}";
+  }
 
   return {
     /**
@@ -275,6 +289,12 @@ BrowserID.Storage = (function() {
      */
     watchLoggedIn: watchLoggedIn,
 
+    /** clear all logged in preferences
+     * @param {string} origin - the site to watch the status of
+     * @param {function} callback - a callback to invoke when state changes
+     */
+    logoutEverywhere: logoutEverywhere,
+
     /**
      * Clear all stored data - email addresses, key pairs, temporary key pairs,
      * site/email associations.
diff --git a/resources/views/index.ejs b/resources/views/index.ejs
index 57f1c8d7b96254292d735fb74bf6bab32639dd4a..6b1f49aec9e17322ae8d9f2f5d9c3ce2d079850c 100644
--- a/resources/views/index.ejs
+++ b/resources/views/index.ejs
@@ -21,6 +21,16 @@
             </ul>
           </section>
 
+          <section id="logout_everywhere">
+            <header class="cf buttonrow">
+                <h2>Logout from all websites</h2>
+                <div class="completion_text"> Logged Out! </div>
+                <button class="logout_everywhere">logout</button>
+            </header>
+
+            <div class="email">You can sign in again by entering your password.  None of your website accounts will be lost.</div></li>
+          </section>
+
           <section id="edit_password">
             <header class="buttonrow cf">
               <h2>Password</h2>