diff --git a/example/rp/index.html b/example/rp/index.html
index fa60c2b2e8c2a55fa1c568a443364417ba54ffc5..3d4740668c1de345c3fae0d8b97abe2a24f122f0 100644
--- a/example/rp/index.html
+++ b/example/rp/index.html
@@ -73,6 +73,10 @@ pre {
       <input type="checkbox" id="siteLogo">
       <label for="siteLogo">Supply Site Logo</label><br />
     </li>
+    </li><li>
+      <input type="checkbox" id="returnTo">
+      <label for="returnTo">Supply returnTo</label><br />
+    </li>
     </li><li>
       <input type="text" id="requiredEmail" width="80">
       <label for="requiredEmail">Require a specific email</label><br />
@@ -193,6 +197,7 @@ $(document).ready(function() {
       termsOfService: $('#termsOfService').attr('checked') ? "/TOS.html" : undefined,
       siteName: $('#siteName').attr('checked') ? "Persona Test Relying Party" : undefined,
       siteLogo: $('#siteLogo').attr('checked') ? "/i/logo.png" : undefined,
+      returnTo: $('#returnTo').attr('checked') ? "/postVerificationReturn.html" : undefined,
       requiredEmail: requiredEmail,
       oncancel: function() {
         loggit("oncancel");
diff --git a/example/rp/postVerificationReturn.html b/example/rp/postVerificationReturn.html
new file mode 100644
index 0000000000000000000000000000000000000000..518c7abbcd7e3073215336abff5adfb523c97815
--- /dev/null
+++ b/example/rp/postVerificationReturn.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<html>
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="initial-scale=1.0; maximum-scale=1.0; width=device-width;">
+<title>
+Persona Relying Party Post Verification Return
+</title>
+<style type="text/css">
+
+body { margin: auto; font: 13px/1.5 Helvetica, Arial, 'Liberation Sans', FreeSans, sans-serif; }
+a:link, a:visited { font-style: italic; text-decoration: none; color: #008; }
+a:hover { border-bottom: 2px solid black ; }
+.title { font-size: 2em; font-weight: bold; text-align: center; margin: 1.5em auto 1.5em auto; }
+.intro { font-size: 1.2em;  }
+.specify, .session { font-size: 1.1em; padding-top: 2em; }
+body div { width: 600px; margin: auto; }
+
+pre {
+  font-family: 'lucida console', monaco, 'andale mono', 'bitstream vera sans mono', consolas, monospace;
+  border: 3px solid #666;
+  -moz-border-radius: 4px;
+  -webkit-border-radius: 4px;
+  border-radius: 4px;
+  padding: .5em;
+  margin: .5em;
+  color: #ccc;
+  background-color: #333;
+/*  white-space: pre;*/
+  font-size: .9em;
+  word-wrap: break-word;
+}
+
+.specify ul { padding-left: 0px; }
+.specify li { list-style: none; }
+
+@media screen and (max-width: 640px) {
+  .intro, .output, .step {
+    width: 90%;
+  }
+}
+
+</style>
+</head>
+<body>
+<div class="title">
+  Persona Relying Party Post Verification Return
+</div>
+
+<div class="intro">
+  This is part of a RP for testing, it is the returnTo for post-verification redirect.
+  <p>
+    <a href="/">Return to RP Test Page</a>
+  </p>
+</div>
+
+<div class="loginEvents">
+  <h2>logins</h2>
+  <pre> ... </pre>
+</div>
+
+
+<div class="readiness">
+  <h2>readiness</h2>
+  <pre> ... </pre>
+</div>
+
+</body>
+
+<script src="jquery-min.js"></script>
+<script src="https://browserid.org/include.js"></script>
+<script>
+
+try {
+  var storage = localStorage;
+}
+catch(e) {
+  // Fx with cookies disabled with blow up when trying to access localStorage.
+  storage = {};
+}
+
+
+function loggit() {
+  try {
+    console.log.apply(console, arguments);
+  } catch(e) {}
+}
+
+var serial = 1;
+
+// a function to check an assertion against the server
+function checkAssertion(assertion) {
+  $.ajax({
+    url: "/process_assertion",
+    type: "post",
+    dataType: "json",
+    data: {
+      assertion: assertion,
+      audience: window.location.protocol + "//" + window.location.host
+    },
+    success: function(data, textStatus, jqXHR) {
+      var old = $(".loginEvents > pre").text() + "\n";
+      $(".loginEvents > pre").text(old + JSON.stringify(data, null, 4));
+    },
+    error: function(jqXHR, textStatus, errorThrown) {
+      var resp = jqXHR.responseText ? JSON.parse(jqXHR.responseText) : errorThrown;
+      $(".loginEvents > pre").text(resp);
+    }
+  });
+};
+
+navigator.id.watch({
+  loggedInEmail: (storage.loggedInUser === 'null') ? null : storage.loggedInUser,
+  onready: function () {
+    loggit("onready");
+    var txt = serial++ + ' navigator.id ready at ' + (new Date).toString();
+    $(".readiness > pre").text(txt);
+
+  },
+  onlogin: function (assertion) {
+    loggit("onlogin");
+    var txt = serial++ + ' got assertion at ' + (new Date).toString();
+    $(".loginEvents > pre").text(txt);
+
+    checkAssertion(assertion);
+
+    $(".specify button.assertion").removeAttr('disabled');
+  },
+  onlogout: function () {
+    loggit("onlogout");
+    var txt = serial++ + ' logout callback invoked at ' + (new Date).toString();
+    $(".logoutEvents > pre").text(txt);
+  }
+});
+
+</script>
+
+</html>
diff --git a/resources/static/dialog/controllers/dialog.js b/resources/static/dialog/controllers/dialog.js
index ec3a1d365735b200f93d315c0d916df4ed936f18..36e66dca60e3ccc6310246344cb029f22d637376 100644
--- a/resources/static/dialog/controllers/dialog.js
+++ b/resources/static/dialog/controllers/dialog.js
@@ -186,17 +186,11 @@ BrowserID.Modules.Dialog = (function() {
 
         // returnTo is used for post verification redirection.  Redirect back
         // to the path specified by the RP.
-        var returnTo;
         if (paramsFromRP.returnTo) {
-          returnTo = fixupAbsolutePath(origin_url, paramsFromRP.returnTo);
-        }
-        else {
-          // Native implementations will be behind on the returnTo feature.  Until
-          // they are ready, set the returnTo to be the origin_url;
-          returnTo = origin_url;
+          var returnTo = fixupAbsolutePath(origin_url, paramsFromRP.returnTo);
+          user.setReturnTo(returnTo);
         }
 
-        user.setReturnTo(returnTo);
 
         if (hash.indexOf("#CREATE_EMAIL=") === 0) {
           var email = hash.replace(/#CREATE_EMAIL=/, "");
diff --git a/resources/static/include_js/include.js b/resources/static/include_js/include.js
index b4da74e0cd095e51a08e0c5831b9c88d40d07e3f..f935a32684b746fbb490d6d05e493bbcc107410d 100644
--- a/resources/static/include_js/include.js
+++ b/resources/static/include_js/include.js
@@ -1070,7 +1070,7 @@
       if (commChan) commChan.notify({ method: 'dialog_running' });
 
       // returnTo is used for post-email-verification redirect
-      if (!options.returnTo) options.returnTo = document.location.href;
+      if (!options.returnTo) options.returnTo = document.location.pathname;
 
       w = WinChan.open({
         url: ipServer + '/sign_in',
diff --git a/resources/static/pages/verify_secondary_address.js b/resources/static/pages/verify_secondary_address.js
index 881a9304133d004c29446446b82b483a662d7382..47ce8d191a3679971729c5a5988580d69c763e96 100644
--- a/resources/static/pages/verify_secondary_address.js
+++ b/resources/static/pages/verify_secondary_address.js
@@ -34,8 +34,8 @@ BrowserID.verifySecondaryAddress = (function() {
   function showRegistrationInfo(info) {
     dom.setInner("#email", info.email);
 
-    if (info.origin) {
-      dom.setInner(".website", info.origin);
+    if (info.returnTo) {
+      dom.setInner(".website", info.returnTo);
       dom.show(".siteinfo");
     }
   }
@@ -84,7 +84,7 @@ BrowserID.verifySecondaryAddress = (function() {
   function startVerification(oncomplete) {
     user.tokenInfo(token, function(info) {
       if (info) {
-        redirectTo = info.origin;
+        redirectTo = info.returnTo;
         showRegistrationInfo(info);
 
         needsPassword = info.needs_password;
diff --git a/resources/static/shared/storage.js b/resources/static/shared/storage.js
index 7f055c069e5df2c03c27361ad853604ba82b5db0..7b4e768ac2d2ab3d37e36365fed4b919fd3c039b 100644
--- a/resources/static/shared/storage.js
+++ b/resources/static/shared/storage.js
@@ -146,30 +146,50 @@ BrowserID.Storage = (function() {
     }
   }
 
-  function setReturnTo(origin) {
+  function setReturnTo(returnToURL) {
     storage.returnTo = JSON.stringify({
       at: new Date().toString(),
-      origin: origin
+      url: returnToURL
     });
   }
 
   function getReturnTo() {
-    var origin;
+    var returnToURL;
 
+    // XXX - The transitional code is to make sure any emails that were staged using
+    // the old setStagedOnBehalfOf still work with the new API.  This should be
+    // able to be removed by mid-July 2012.
     try {
-      var staged = JSON.parse(storage.returnTo || storage.stagedOnBehalfOf);
+      // BEGIN TRANSITIONAL CODE
+      if (storage.returnTo) {
+      // END TRANSITIONAL CODE
+        var staged = JSON.parse(storage.returnTo);
+
+        if (staged) {
+          if ((new Date() - new Date(staged.at)) > (5 * 60 * 1000)) throw "stale";
+          if (typeof(staged.url) !== 'string') throw "malformed";
+          returnToURL = staged.url;
+        }
+      // BEGIN TRANSITIONAL CODE
+      }
+      else if(storage.stagedOnBehalfOf) {
+        var staged = JSON.parse(storage.stagedOnBehalfOf);
 
-      if (staged) {
-        if ((new Date() - new Date(staged.at)) > (5 * 60 * 1000)) throw "stale";
-        if (typeof(staged.origin) !== 'string') throw "malformed";
-        origin = staged.origin;
+        if (staged) {
+          if ((new Date() - new Date(staged.at)) > (5 * 60 * 1000)) throw "stale";
+          if (typeof(staged.origin) !== 'string') throw "malformed";
+          returnToURL = staged.origin;
+        }
       }
+      // END TRANSITIONAL CODE
     } catch (x) {
       storage.removeItem("returnTo");
+      // BEGIN TRANSITIONAL CODE
       storage.removeItem("stagedOnBehalfOf");
+      // END TRANSITIONAL CODE
     }
 
-    return origin;
+    return returnToURL;
   }
 
   function siteSet(site, key, value) {
diff --git a/resources/static/shared/user.js b/resources/static/shared/user.js
index 2d293c7e0d80790903ad6d6b1778a5e17e31706e..0eda75118ec733971c52d64458e5195ed90d3740 100644
--- a/resources/static/shared/user.js
+++ b/resources/static/shared/user.js
@@ -282,7 +282,8 @@ BrowserID.User = (function() {
     },
 
     /**
-     * Create a user account - this creates an user account that must be verified.  * @method createSecondaryUser
+     * Create a user account - this creates an user account that must be verified.
+     * @method createSecondaryUser
      * @param {string} email
      * @param {string} password
      * @param {function} [onComplete] - Called on completion.
@@ -486,10 +487,10 @@ BrowserID.User = (function() {
     tokenInfo: function(token, onComplete, onFailure) {
       network.emailForVerificationToken(token, function (info) {
         if(info) {
-          info = _.extend(info, { origin: storage.getReturnTo() });
+          info = _.extend(info, { returnTo: storage.getReturnTo() });
         }
 
-        onComplete && onComplete(info);
+        complete(onComplete, info);
       }, onFailure);
 
     },
@@ -512,7 +513,7 @@ BrowserID.User = (function() {
             var result = invalidInfo;
 
             if(valid) {
-              result = _.extend({ valid: valid, origin: storage.getReturnTo() }, info);
+              result = _.extend({ valid: valid, returnTo: storage.getReturnTo() }, info);
               storage.setReturnTo("");
             }
 
@@ -882,7 +883,7 @@ BrowserID.User = (function() {
             var result = invalidInfo;
 
             if(valid) {
-              result = _.extend({ valid: valid, origin: storage.getReturnTo() }, info);
+              result = _.extend({ valid: valid, returnTo: storage.getReturnTo() }, info);
               storage.setReturnTo("");
             }
 
diff --git a/resources/static/test/cases/shared/user.js b/resources/static/test/cases/shared/user.js
index 9da4f8474665ec7be3f35a6e1e5f8e7be80c5dbd..5fdc5529ea9be7bac3e0eb767a0970a335034e67 100644
--- a/resources/static/test/cases/shared/user.js
+++ b/resources/static/test/cases/shared/user.js
@@ -371,20 +371,20 @@ var jwcrypto = require("./lib/jwcrypto");
     }, 500);
   });
 
-  asyncTest("tokenInfo with a good token and origin info, expect origin in results", function() {
+  asyncTest("tokenInfo with a good token and returnTo info, expect returnTo in results", function() {
     storage.setReturnTo(testOrigin);
 
     lib.tokenInfo("token", function(info) {
       equal(info.email, TEST_EMAIL, "correct email");
-      equal(info.origin, testOrigin, "correct origin");
+      equal(info.returnTo, testOrigin, "correct returnTo");
       start();
     }, testHelpers.unexpectedXHRFailure);
   });
 
-  asyncTest("tokenInfo with a bad token without site info, no site in results", function() {
+  asyncTest("tokenInfo with a bad token without returnTo info, no returnTo in results", function() {
     lib.tokenInfo("token", function(info) {
       equal(info.email, TEST_EMAIL, "correct email");
-      equal(typeof info.origin, "undefined", "origin is undefined");
+      equal(typeof info.returnTo, "undefined", "returnTo is undefined");
       start();
     }, testHelpers.unexpectedXHRFailure);
   });
@@ -400,7 +400,7 @@ var jwcrypto = require("./lib/jwcrypto");
 
       ok(info.valid, "token was valid");
       equal(info.email, TEST_EMAIL, "email part of info");
-      equal(info.origin, testOrigin, "origin in info");
+      equal(info.returnTo, testOrigin, "returnTo in info");
       equal(storage.getReturnTo(), "", "initiating origin was removed");
 
       start();
@@ -754,14 +754,14 @@ var jwcrypto = require("./lib/jwcrypto");
     }, 500);
   });
 
-  asyncTest("verifyEmail with a good token - callback with email, origin, valid", function() {
+  asyncTest("verifyEmail with a good token - callback with email, returnTo, valid", function() {
     storage.setReturnTo(testOrigin);
     lib.verifyEmail("token", "password", function onSuccess(info) {
 
       ok(info.valid, "token was valid");
       equal(info.email, TEST_EMAIL, "email part of info");
-      equal(info.origin, testOrigin, "origin in info");
-      equal(storage.getReturnTo(), "", "initiating origin was removed");
+      equal(info.returnTo, testOrigin, "returnTo in info");
+      equal(storage.getReturnTo(), "", "initiating returnTo was removed");
 
       start();
     }, testHelpers.unexpectedXHRFailure);