Lazy Registration - Ajax Patterns

Lazy Registration

From Ajax Patterns

(Difference between revisions)
Revision as of 00:39, 20 November 2005
Mahemoff (Talk | contribs)

← Previous diff
Revision as of 08:55, 15 July 2011
93.72.193.157 (Talk | contribs)
External Link
Next diff →
Line 1: Line 1:
-'''Evidence:''' 2/3+'''Evidence:''' 1/3
-'''Tags:''' Dynamic Live Real-Time Validation+'''Tags:''' Account Authentication Customisation Customization Incremental Login Password Personalisation Personalization Profiling Registration User Verification
<!-- =================================================================== --> <!-- =================================================================== -->
 +
 +
= In A Blink = = In A Blink =
-Diagram: ticks and crosses, a "validating ..." message next to a recent field, a modified field.+User interacts with E-Commerce site, then logs in later.
<!-- =================================================================== --> <!-- =================================================================== -->
Line 13: Line 15:
= Goal Story = = Goal Story =
-Tracy is applying for a new online brokerage account. Upon declaring her place of residence, some additional regulation-related questions appear, specific to her region. Several asset classes can be traded. She ticks a box to indicate she want to trade in bonds, and further questions specifically for that asset class. She then clicks on another box, for options. A moment later, a warning appears that new users can only trade in one of options or bonds. After further refinement, she successfully submits the form and sees it fade into a welcome message.+It's Saturday afternoon, and Stuart is busy planning the evening's activities. He visits a band listings website, where he clicks on a map to zoom into his local area. Even though he's never visited the site before, a profile is already being constructed, which he can see on the top of the site. At this stage, the profile guesses at his location based on his actions so far. As he browses some of the jazz bands, the profile starts to show an increasing preference for jazz bands, and some of the ads reflect that. Since the jazz thing is a one-off idea, he goes into his profile and tweaks some of those genre preferences, but leaves the location alone as that was correctly guessed. Finally, he decides to make a booking, at which point he establishes a password for future access to the same profile and also his address, which is posted back to the profile.
<!-- =================================================================== --> <!-- =================================================================== -->
Line 19: Line 21:
= Problem = = Problem =
-How can the user submit data as quickly as possible?+How can the user customize the site, while deferring formal registration?
<!-- =================================================================== --> <!-- =================================================================== -->
Line 25: Line 27:
= Forces = = Forces =
-* Most data submission tasks require some flexibility. A particular answer for one item will necessitate further questions. Often, this must occur server-side, where business logic and data usually reside.+* Public websites thrive on registered users. Registered users receive personalised content, which means the website is able to deliver greater value per user. And registered users can also receive more focused advertising material.
-* Most data submission requires validation. This must occur server-side to prevent browser-side manipulation of inputs.+* For non-public websites, such as extranets used by external customers, registration may be a necessity.
-* Users get frustrated waiting for data to be validated and continuously refining data upon each explicit submission.+* Most users don't like giving their personal information to a web server. They have concerns about their own privacy and the security of the information. Furthermore, the registration process is often time-consuming.
 +* Many users spend time familiarising themselves with a site before registering. In some cases, a user might interact with a site for years before formally establishing an account. There is a lot of valuable information that can be gained from this interaction, which will benefit both the website owner and the user.
 +* Users may be willing to provide some information about themselves in order to access a service, but not all the information the system can potentially store.
 + 
 +<!-- ------------------------------------------------------------------- -->
<!-- =================================================================== --> <!-- =================================================================== -->
Line 33: Line 39:
= Solution = = Solution =
-<span class="solution">Validate and modify a form throughout the entire interaction, instead of waiting for an explicit submission.</span> Each significant user event results in some browser-side processing, often leading to an [[XMLHttpRequest Call]]. The form may then be modified as a result.+<span class="solution">Accumulate bits of information about the user as they interact, with formal registration occurring later on.</span> As soon as the user visits the website, a user account is immediately created for them, with auto-generated ID, and set in a cookie which will remain in the browser. It doesn't matter if they never return&mdash;unused IDs can be cleared after a few months.
-Modifying the form is similar to responding to a [[Microlink]] - there's usually a server call followed by some [[Page Rearrangement]]. Typical modifications:+As the user interacts with the application, the account accumulates data. In many cases, the data is explicitly contributed by the user, and it's advisable to expose this kind of information so the user can actually populate it. In this way, the initial profile may be seen as a structure with lots of holes. As the user interacts with the system, some parts of the structure are filled in automatically and others are added by the user themselves. The user is also free to correct any of the filled-in data at any time.
-* New controls appear.+
-* Controls become disabled.+
-* Information and error messages appear.+
-The result is a more interactive form. The usr doesn't have to wait for a page reload to find out if a form field is invalid, because it's validated as soon as they enter the value. Due to the asynchronous nature of [[XMLHttpRequest Call]], the validation occurs as a background process, while the user carries on entering data further down the form. If there's an error, the user will find out about it while filling out a field further down the form. As long as errors don't happen too often, that's no great inconvenience.+Two particularly notable "holes" are a unique user identifier and a password. It is this combination of attributes that allows the user to access the profile afterwards from another machine or a different browser. They will also allow the profile to survive any deletion of cookies in the user's browser. So, while the pattern is generally about gradual accumulation of profile data, there remains a significant milestone in the user-application relationship, the moment at which user ID and password are established.
-Validation doesn't always occur at field level though. Sometimes, it's the combination of data that's a problem. This can be handled by checking validation rules only when the user's provided any input for all related fields. A validation error can result in a general, form-level, error message or a message next to one or more of the offending fields.+Do the user ID and password have to be provided simultaneously? No, even that can be incremental, if you use a little trick: use an email address as the unique identifier. In fact, this is fairly common nowadays. Email is usually required anyway, and it's unique, so why not make it the user ID? In the context of Lazy Registration, though, there's an additional benefit: the email might be accumulated in the natural flow of events&mdash;the site might add the user to an announcements list, for example. In some cases, the email might even be verified during this process.
-A [[Live Form]] usually ends with an [[Explicit Submission]], allowing the user to confirm everything's valid. Note, that unlike a conventional form, the [[Explicit Submission]] does not perform a standard HTTP form submission, but posts the contents as an [[XMLHttpRequest Call]].+Sceptics may wonder why a user would want to actively work with their profile. The answer was formulated in a web usability pattern called
 + 
 +<blockquote>Determine what users consider to be a "valuable" carrot. Offer the end user a portion of that carrot before you request personal information. The content is withheld ("the stick") until the requested information is provided.</blockquote>
 + 
 +Thus, users will only enter information if there is a perceived benefit to them. There is plenty of evidence this occurs&mdash;witness the social bookmarking phenomenon, where thousands of users make public their personal links. By exposing their profile, many of those users are hoping the system will point them in the direction of related resources they haven't heard of yet. That possibility, in turn, encourages them to add even more links, so as to avoid seeing known resources appear. Admittedly, del.icio.us is a rather techno-centric community at this stage, but there is also evidence of this approach further afield, as discussed in the real-world examples.
 + 
 +Now, it's clear that some systems have used this pattern for years, so what does it have to do with Ajax? Lazy Registration aims for a smooth approach, where the barrier is low for each new user contribution. So you want to sign up for the website's mailing list? Great, the summary profile is already on the side menu, just make sure your email's right. See what happened? With Ajax, there's no need to break the flow. No more "Just go over there for a few minutes, then come back here, and if you're lucky, you might be looking at something similar to what you can see now." That's a big win for websites aiming to drop the barrier of registration and it's great for users too.
 + 
 +If some of these techniques seem underhanded, you should be aware that they are manifestations of the technology at hand. It's standard practice for websites to collect data about users. The pattern here is actually about empowering users&mdash;instead of secretly building up a corpus of data on a user, you invite them to add value to their own experience by contributing the data themselves.
 + 
 +The following technologies are involved in implementing Lazy Registration:
 +* '''Database:''' You clearly need a persistent data store in order to capture user profiles and associate them with the session ID that's stored.
 +* '''XMLHttpRequest:''' Judicious use of [[XMLHttpRequest Call]]s are the key to the smooth interaction mode which you are seeking to achieve with this pattern.
 +* '''Cookie Manipulation and Session Tracking:''' A cookie must reside in the user's browser, associated with your domain and identifying a unique session ID, which can serve as a key on the server-side to locate details about the user each time they access the website.
 + 
 +In conventional applications, the cookie is pushed from the browser as a header in the response. That's fine for Ajaxian Lazy Registration when the user first accesses the system, though sometimes it may be convenient to use a more Ajax-oriented approach. The first such approach is to [http://www.netspade.com/articles/javascript/cookies.xml manipulate the cookie in JavaScript]. The second is to set the cookie using the response from an [[XMLHttpRequest Call]], which all browsers are apparently happy to deal with in the same way as they deal with cookies in regular page reloads.
 +In practice, you're unlikely to be playing with cookies anyway. Most modern environments contain session-tracking frameworks that do the low-level cookie manipulation for you (see also [[Direct Login]]). They generally use either URL-rewriting or cookie manipulation, and you need the latter to make this pattern work most effectively. Since responses from XMLHttpRequest set cookies in the same way as entire page reloads, you should be able to change session data while servicing [[XMLHttpRequest Call]]s.
<!-- =================================================================== --> <!-- =================================================================== -->
Line 50: Line 69:
= Decisions = = Decisions =
-<!-- -------------------------------------------------------------------- -->+== What kind of data will the profile contain? ==
 + 
 +Usability and functionality concerns will drive decisions on what data is accumulated. By envisioning how users will interact with the website, you can decide what kind of data must be there to support the interaction. For example:
 +* Do you want to provide localised ads? You'll need to know where the user lives.
 +* Do you want to use collaborative filtering? You'll need to capture the user's preferences.
 + 
 +In addition, consider that some Ajax applications are used all day long by users, such as employees working on an intranet website. For that reason, the profile might also contain preferences similar to those on conventional desktop applications. Many options will be application-specific, but a few generic examples include:
 +* Enabling and disabling visual effects, such as [[One-Second Spotlight]].
 +* Setting [[Heartbeat]]-related parameters, e.g. how long will timeout be, will the system prompt the user when it's coming up.
 +* Customising [[Status Area]] display.
 + 
 +No question about it, many companies like to accumulate as much data as they can get their hands on. Especially so in an economy where storage is trivially cheap. When a company is acquired, you can see tangible evidence that such data is worth something to someone. It's na&iuml;ve to assume that usability concerns are all that drive data collection, however, it's important to be aware that laws and regulations apply, as should ethical standards.
 + 
 +== How can the profile be accumulated? ==
 + 
 +You might know what data you need, but are users willing to give it to you? This comes back to the carrot-and-stick argument: you need to provide users a service that will make it worthwhile for them to provide that data. In addition, you need to communicate the benefit, and you must be able to assure them that the data will be safe and secure.
 + 
 +The least imaginitive way to gain user data is to pay them for it, or more deviously, pay others for it. Giving away a CD in exchange for data was well and dandy during the dotcom boom, but you'll have to do better than that today. Give the user a service they really need. For example:
 +* If you want the user to provide their address, provide localised search features.
 +* If you want the user to rate your product, provide recommendations based on their ratings.
 + 
 +== How much data should be stored in cookies? ==
 + 
 +How much you store in cookies depends on your general approach to the Ajax implementation: is the application browser-centric or server-centric? A browser-centric choice would be to pack as much as possible in the browser's local state, optimising performance while running a full-fledged JavaScript application, with a little server-side synchronisation. A server-centric approach would rely only on data held server-side, with the browser accessing additional data using [[XMLHttpRequest Call]]s on a need-to-know basis.
 + 
 +One special concern is the security of cookies. If users access the application from a public PC, there's the risk of unauthorised access. In this case, it's especially advisable not to store sensitive information in the browser and offer the possibility of cleaning cookies at the end of the session. (For example, the "I'm on a public terminal" option.)
<!-- =================================================================== --> <!-- =================================================================== -->
Line 56: Line 100:
= Real-World Examples = = Real-World Examples =
-== WPLicense ==+== Amazon.com ==
-WPLicense is a WordPress plugin allowing users to specify a copyright license for their blog content. Refer to the [[Cross-Domain Mediator]] for details on the plugin and the Code Examples below for a walkthrough of its [[Live Search]] implementation.+[http://amazon.com Amazon] has recently begun incorporating Ajaxian techniques, but was relying on Lazy Registration a long time prior. Visit [http://amazon.com Amazon] as a new user, browse for just a few seconds, and here's what you'll see before even beginning to register or log in:
 +* Shopping cart, which you can add items to.
 +* Recently Viewed Items
 +* Page You Made - showing recent views and books related to those.
 +* Ability to update your history, by deleting items you viewed.
 +* Ability to turn off "Page You Made".
 +* Ability to search for a friend's public wishlist.
-== Betfair ==+== Kayak ==
-[http://betfair.com Betfair] lets the user make a bet using a [[Live Form]]. You can try this even as a non-registered user, by opening up a bet from the [[Drilldown]] menu. There are three columns on the page: the left column shows the current bet topic within the [[Drilldown]], the centre column shows odds for all candidates, and the right column shows your stake in this bet. Clicking on a candidate causes it to appear in your stake form, where you can then set how much you're placing. As you change your stake, there's also a [[Status Area]] that shows your total liability. Also, another column shows your profit if each event occurs. There are also some "meta" controls. For instance, clicking on "Back All" creates an editable row for every candidate.+[http://kayak.com Kayak] is a travel search engine which retains queries you've made. A query is history is available for non-registered users, and it becomes part of your profile once registered.
-== MoveableType Comment Hack ==+== Palmsphere ==
-[http://www.simiandesign.com/blog-fu/2005/07/ajax_comments_b.php#comments Simian Design] is a blog where you can add comments, Ajax style. As you type into the textbox, a live preview appears underneath and takes markup into account. Clicking on Preview or Post, the text fades and an animated [[Progress Indicator]] bar shows the server is processing. The result is then embedded in the page with some [[Page Rearrangement]].+[http://palmsphere.com/store/home Palmsphere] showcases Palm applications for download and purchase. Each item has a "Favourite" button&mdash;if checked, the item is one of your "Favourites". The Favourites list is summarised in your "Member Center" area, even if you've never registered, and retained in a cookie for the next time you visit.
 +== Madgex ==
 +
 +[http://www.90percentofeverything.com/2009/03/16/signup-forms-must-die-heres-how-we-killed-ours/ View Madgex Lazy Registration Demo] Madgex is a whitelabel job board platform provider, used on about 150 job boards world wide. The new version of their platform provides lazy registration facilities, allowing job seekers to set up email alerts, apply for jobs, save their CV and save their cover letter without having to set up a password. When they choose to register, all the collected information and settings are revealed to them.
<!-- -------------------------------------------------------------------- --> <!-- -------------------------------------------------------------------- -->
= Code Examples = = Code Examples =
-== WPLicense ==+== Ajax Shop Demo ==
-[[WPLicense]] is a form with a live component. Initially, the "License Type" field simply shows the current license, if any. But when the user clicks on the update link, a new block opens up and a conversation between the browser and server ensues to establish the precise details of the license. (More precisely, the conversation is between the browser and the Creative Commons website - see the corresponding example in [[Cross-Domain Mediator]]). Each license type has associated questions, so the license options are fetched according to the user's license type selection.+The [http://ajaxify.com/run/shop Ajax Shop Demo] illustrates the kind of user-interface described by this pattern.
-When the user launches the plugin, a PHP function begins by drawing the Live Form. In this case, the form is ultimately submitted as a conventional POST upload, so the form has a conventional declaration:+Running the demo, you'll notice a few things:
 +* After the page initially loads, everything runs smoothly within the browser.
 +* You can add items to your cart before registering.
 +* The application guesses your favourite category by watching what you're looking at. If you prefer, you can override the application's guess, and the appliction will no longer attempt to adjust it.
 +* By offering you the ability to send the cart contents to your email address, the application provides an incentive to add your email to the profile, without actually registering yet.
 +* The password and email verification process itself is unintrusive - the main flow of the site is uninterrupted. Even while you're waiting for verification mail, you can continue to play around with the main content.
-<pre>+To keep things simple, it doesn't actually use a persistent data store&mdash;all information is held in the session. That's definitely not advisable for a real system, because you don't want to store passwords and other sensitive data there. Also, it means the user in theory could bypass the email verification by inspecting the cookie. Nevertheless, the application demonstrates lazy registration from the user's perspective, and the underlying code provides some illustration of what's required to develop such an application.
- <form name="license_options" method="post" action="' . $_SERVER[REQUEST_URI] . '">+
- ...+
- <input type="submit" value="save" />+
- <input type="reset" value="cancel" id="cancel" />+
- ...+
- </form>+
-</pre>+
-The current license is shown, loaded with initial values, along with the link that triggers the cross-domain mediation to update the license setting.+Here, I'll point out how a few of the features were achieved.
 + 
 +=== Retrieval of Categories and Items ===
 + 
 +The application maintains the flow by avoiding any page reloads when categories and items are accessed. No information about categories or items are hard-coded; generic REST services are used to extract the data, and its rendered locally in JavaScript.
 + 
 +=== Cart Management ===
 + 
 +Again, the only real relevance of cart management is that page reloads are avoided. The cart contents are tracked in the session, so they should be present when the user resumes using the website. When the user adds something to the cart, the JavaScript cart is ''not'' directly altered. Instead, the new item is posted to the server as XML:
 + 
 + function onAddItemClicked(item) {
 + var vars = {
 + command: 'add',
 + item: item
 + }
 + ajaxCaller.postForXML("cart.phtml", vars, onCartResponse);
 + }
 + 
 +Likewise, when the cart is cleared:
 + 
 + function onCartClearClicked() {
 + var vars = {
 + command: 'clear'
 + }
 + ajaxCaller.postForXML("cart.phtml", vars, onCartResponse);
 + }
 + 
 +For both operations, the server retrieves the session cart and alters its state:
 + 
 + $cart = $_SESSION['cart'];
 +
 + if (isset($_POST["command"])) {
 + if ($_POST["command"] == "add") {
 + $cart->add($_POST["item"]);
 + } else if ($_POST["command"] == "clear") {
 + $cart->clear();
 + }
 + }
 + 
 +Then, the server outputs the final state as an XML response.
 + 
 + header("Content-type: text/xml");
 + echo "<cart>";
 + $contents = $cart->getContents();
 + foreach ($contents as $itemName => $val) {
 + echo "<item>";
 + echo "<name>$itemName</name>";
 + echo "<amount>$val</amount>";
 + echo "</item>";
 + }
 + echo "</cart>";
 + 
 +In the browser, <tt>onCartResponse</tt> is registered to render the cart based on the resulting XML.
 + 
 +=== Mailing Cart Contents ===
 + 
 +Along with several other fields, the profile block contains the user's email. There is also a clickable "Mail" field on the cart.
<pre> <pre>
- <tr><th>Current License:</th><td>+ <div>
- <a href="'.get_option('cc_content_license_uri').'">'.get_option('cc_content_license').'</a>+ <div class="userLabel">Email:</div>
- ...+ <input type="text" id="email" name="email" />
 + </div>
 +
 + ...
 +
 + <span id="cartMail">Mail Contents</span>
 +
 + ...
 +
 + $("cartMail").onclick = onCartMailClicked;
</pre> </pre>
-The form includes hidden input fields to capture information gleaned during the Ajaxian interaction. They will be populated from Javascript event-handlers.+When the user clicks on <tt>cartMail</tt>, the server checks that the email has been filled in, and simply uploads a POST message for the mail to occur. In this case, there's no feedback to the web user, so the callback function is blank.
- <pre>+ vars = {
- <input name="license_name" type="hidden" + command: "mailCart",
- value="'.get_option('cc_content_license').'" />+ email: email
- </pre>+ }
 + ajaxCaller.postForPlainText("cart.phtml", vars, function() {});
-As well, there's an initially-invisible <tt>div</tt> which will be shown once the user decides to change the license. Don't confuse this with the hidden input fields - those will never be shown to the user, while this just happens to have a hidden style when the page initially loads. Most critically, the <tt>div</tt> contains a selection field: +The server receives not only the command, but the email itself, since this might not yet be in the user's profile. Just prior to sending the mail, the server retains the email as part of the user's session. (Again, this is a simplification, because retaining the email would not be necessary&mdash;or desirable&mdash;if the user was already logged in.)
- <pre>+ function mailCart() {
- <select id="licenseClass"> <option id="-">(none)</option>+
... ...
- foreach($license_classes as $key => $l_id) {+
- echo '<option value="' . $key . '" >' . $l_id . '</option>';+ $email = $_POST["email"];
- }; // for each...+ // Add mail to the profile - it's part of the lazy registration.
 + $_SESSION['email'] = $email;
 +
... ...
- </select>+ }
- </pre>+
-Now, I said that each license has different options, so how are those options shown to the user? The "licenseClass" selector is associated with <tt>retrieveQuestions</tt>, a function which fetches the questions corresponding to the chosen license. The call is made courtesy of the [http://twilightuniverse.com/2005/05/sack-of-ajax/ Sack] library, which paints the server's HTML directly onto the <tt>license_options</tt> <tt>DIV</tt>. +After that, it's a simple matter of constructing a message from the server-side cart state and sending the email to the specified address using standard server-side libraries.
 + 
 +=== Tracking Favourite Categories ===
 + 
 +Firstly, there is a fixed "favourite category" selector in the HTML. It begins empty and is populated when the categories are loaded.
<pre> <pre>
- el.onchange = function() {+ <div id="favouriteCategoryInfo">
- retrieveQuestions();+ My&nbsp;Best&nbsp;Category: <select id="favouriteCategory"></select>
- } // onchange+ </div>
- +
- function retrieveQuestions() {+ function onAllCategoriesResponse(xml, ignoredHeaders, ignoredContext) {
- ajax = new sack(blog_url);+ ...
- ajax.element='license_options';+
- ajax.setVar('func', 'questions');+ categoryExplores[category] = 0;
- ajax.setVar('class', cmbLC.value); ''Current license passed to server''+ favouriteCategoryOption = document.createElement("option");
- ajax.runAJAX();+ favouriteCategoryOption.text = favouriteCategoryOption.value = category;
 + try {
 + $("favouriteCategory").add(favouriteCategoryOption, null); // FF
 + } catch(ex) {
 + $("favouriteCategory").add(category); // IE
 + }
 +
... ...
} }
</pre> </pre>
-Here, the server function is [[Specialised Services|specialised]] and [[HTML-Generating Services|HTML-Generating]]. It+There's also a JavaScript-based mode to indicate whether the favourite category selection is automated or not. It begins in automated mode.
-determines the appropriate questions to ask , and outputs them as HTML. (See the [[Cross-Domain Mediator]] example for+
-details.) +
-Now, how about those hidden fields? Well, the thing is, not all the information related to the options are hidden: the license URL is shown to the user, so that also needs to be updated after an option is chosen. Each time the user changes the server-generated options, the server is called to get a bunch of information about the current selection (<tt>admin.js:updateLicense()</tt>). That information then comes back to the browser, and the callback function updates both the hidden fields and the URL accordingly: + var isFavouriteCategoryAutomated = true;
-<pre>+If in automated mode, the script watches each time the user explores an item. Each cateogory is tracked according to how many times the item was explored, the selector being altered if a new maximum is reached.
- *** Updating the hidden fields ***+ 
- document.license_options.license_name.value = licenseInfo['name'];+ var categoryExplores = new Array();
- document.license_options.license_uri.value = licenseInfo['uri'];+
- document.license_options.license_rdf.value = licenseInfo['rdf'];+
- document.license_options.license_html.value = licenseInfo['html'];+
- *** Updating the visible license URL ***+ ...
- href_text = '<a href="' + licenseInfo['uri'] + '">' + licenseInfo['name'] + '</a>';+
- document.getElementById("newlicense_name").innerHTML = href_text;+ function onExploreClicked(category) {
-</pre>+ ...
 +
 + if (isFavouriteCategoryAutomated) {
 + categoryExplores[category]++;
 + favouriteCategory = $("favouriteCategory").value;
 + favouriteCategoryExplores = categoryExplores[favouriteCategory];
 + if (categoryExplores[category] > favouriteCategoryExplores) {
 + $("favouriteCategory").value = category;
 + }
 + }
 + }
-Now, what's changed so far, on a permanent basis? Well, nothing. Everything so far has been setting up the form itself. But that's fine here, because the form is submitted in the conventional manner. So as soon as the user clicks on the '''Submit''' button, all those hidden fields will be uploaded and processed as standard HTTP form data.+As soon as the user decides to overwrite this guesstimate by manually setting the preference, it stays manual forever.
-<!-- =================================================================== -->+ $("favouriteCategory").onclick = function() {
 + isFavouriteCategoryAutomated = false;
 + }
-= Alternatives =+For the sake of simplicity, this field is not actually tracked in the server, though it could easily be persisted as part of the user's profile.
-== Alternative ==+=== Verifying Password and Email ===
-<!-- =================================================================== -->+Now for the most important part. The user's finally willing to verify password and email. These could potentially be broken into two separate verification activities, but they both fit together as a formal registration step, so they are combined in the demo.
-= Related Patterns =+The trick is to manage the process with a little state transition logic. The registration is broken into a few states, with transitions between them. Each state requires handling events in a slightly different way. Each transition involves altering the UI a little to reflect what the user can do. Refer to Gamma et al's (1995) [http://wiki.cs.uiuc.edu/PatternStories/StatePattern State Pattern] for more details on this approach.
-== [[Microlink]] ==+<tt>registerState</tt> holds the current state:
-Like [[Live Form]]s, [[Microlinks]] open up new content directly on the page. Indeed, a [[Microlink]] can be used on a [[Microlink]] to provide some supporting information.+ /*
 + "start": When page is loaded
 + "mustSendMail": When instructions and verify password field shown
 + "mustVerifySecretNumber": When email sent and user must enter secret
 + number inside email
 + "verified": When user is successfully logged in
 + */
 +
 + var registerState = "start";
-== [[Live Search]] ==+The HTML for this demo contains all the necessary fields and buttons, their visibility toggled based on the current state. For example, following are the password and password verification fields. The password field is always shown until the user is at "verified" stage, while the "verify password" field is only shown after the user initiates the registration process.
-Consider including a [[Live search]] when users need to perform a search within the [[Live Form]].+<pre>
 + <div id="passwordInfo">
 + <div class="userLabel">Password:</div>
 + <input type="password" id="password" name="password" />
-== [[Suggestion]] ==+ <div id="verifyPasswordInfo">
 + <div id="regHeader">Demo Registration</div>
 + <div class="regInstructions">
 + <strong>1.</strong> Please ensure email address is correct and
 + password is <strong>not</strong> confidential, then verify your
 + password below.
 + </div>
 + <div class="userLabel">Verify Password:</div>
 + <input id="verifyPassword" type="password" name="verifyPassword" />
 + </div>
 + </div>
 +</pre>
-Consider offering [[Suggestion]]s to help users complete fields within the [[Live Form]].+All three buttons are declared, and again, their visibility will change depending on current state.
-== [[Drilldown]] ==+<pre>
 + <input type="button" id="login" value="Login" />
 + <input type="button" id="register" value="Register" />
 + <input type="button" id="cancel" value="Cancel" />
 +</pre>
-Consider including a [[Drilldown]] when users need to identify an item within a hierarchy.+The login button is only for demonstration purposes and the cancel button resumes the state back to "start", which causes the display to return to its initial state, too. What's most important here is the "Register" button, which drives the process through each state. While the button's label is changed to reflect the action being performed at each state, it is always present until the user is verified. For this reason, its event handler remains the same and decides what to do based on the current state:
-== [[Progress Indicator]] ==+ function onRegisterClicked() {
 + if (registerState=="start") {
 + registerState = "mustSendMail";
 + } else if (registerState=="mustSendMail") {
 + var submissionOK = sendMail();
 + if (submissionOK) {
 + registerState = "mustVerifySecretNumber";
 + } else {
 + return;
 + }
 + } else if (registerState=="mustVerifySecretNumber") {
 + verifySecretNumber();
 + }
 + onRegistrationStateChanged();
 + }
-Show the server is working to process a field with a [[Progress Indicator]].+And <tt>onRegistrationStateChanged()</tt> purely exists to reveal and hide fields, and change the button label, based on the current state:
-== [[One-Second Spotlight]] ==+ function onRegistrationStateChanged() {
 +
 + if (registerState=="start") {
 + $("userForm").reset();
 + $("login").style.display = "inline";
 + $("verifyPasswordInfo").style.display = "none";
 + $("secretNumberInfo").style.display = "none";
 + $("verifiedInfo").style.display="none";
 + $("cancel").style.display = "none";
 + $("register").value="Register";
 + } else if (registerState=="mustSendMail") {
 + ...
 + } else if (registerState=="mustVerifySecretNumber") {
 + ...
 + } else if (registerState=="verified") {
 + ...
 + }
-Since [[Live Form]]es are usually submitted with an [[XMLHttpRequest Call]], a [[One-Second Spotlight]] effect, such as <tt>Fade Out</tt> is a good way to convey the form's been submitted.+An alternative design might actually manipulate the DOM itself, adding and removing the elements. Or it might generate the specific HTML for the form at each stage. However, relying on the state pattern for this process makes it easy to quickly alter the flow and appearance of the registration process.
<!-- =================================================================== --> <!-- =================================================================== -->
-= Visual Metaphor =+= Alternatives =
-Filling out a Live Form is like being interviewed by someone smart enough to listen, give feedback, and improvise on the content.+= Related Patterns =
-<!-- =================================================================== -->+== [[Direct Login]] ==
 + 
 +Direct Login is a companion pattern, since some dynamic behaviour can allow for login and registration to appear on the same form.
 + 
 +== [[Live Form]] ==
 + 
 +It's useful to maintain the profile details in a Live Form, so the user can easily add to them and the server can synchronise state and provide opportunities for further enhancement to the profile.
 + 
 +== [[Heartbeat]] ==
 + 
 +Where data is held in cookies, it's a good idea to expire them if there is a risk that others may gain access to the browser. Heartbeat helps the server decide if the client is actually active. If not, it may be wise to ensure any sensitive data is wiped from cookies held in the browser.
 + 
 +== [[Guesstimate]] ==
 + 
 +Lazy Registration can sometimes involve inferring information about the user's profile by monitoring their behaviour. Thus, it embraces the same fuzzy principles as Guesstimate, where a guess is acknowledged to be imprecise, but better than no guess.
 + 
 += Visual Metaphor =
 + 
 +A good salesman works the same way. While assumptions might be made based on a prospect's behavior, the salesman is always listening and those assumptions are open to challenge. (Malcolm Gladwell detailed this pattern of successful salespeople in ''Blink''.)
= Want to Know More? = = Want to Know More? =
 +
 +* [http://www.oecd.org/document/18/0,2340,en_2649_201185_1815186_1_1_1_1,00.html OECD privacy guidelines]
 +* [http://www.truste.org/ TRUSTe certified website privacy policies]
 +* [http://www.isr.uci.edu/pep05/papers/InformedConsent.PDF Informed Consent]
 +* [http://www.clickz.com/experts/archives/mkt/precis_mkt/article.php/814811 Personalization vs. Customization]
 +
 += External Link =
 +*[http://signalsforex.org/ signals forex]
 +*[http://www.instantz.net watch anime online]
 +*[http://whowillimarry.org who will i marry]
 +*[http://www.mypastlifereading.com past life reading]
 +*[http://www.dissertationlab.com/thesis thesis]
 +*[http://www.mauime.com maui wedding packages]
 +*[http://www.bestdissertation.com/services/dissertation.html dissertation help]
 +
 += Acknowledgements =
 +
 +The idea to handle lazy registration in this Ajaxian manner was originally proposed by [http://tahpot.blogspot.com/2005/06/lazy-registration-with-ajax.html Chris Were ("Tahpot")].

Revision as of 08:55, 15 July 2011

Evidence: 1/3

Tags: Account Authentication Customisation Customization Incremental Login Password Personalisation Personalization Profiling Registration User Verification



Contents

In A Blink

User interacts with E-Commerce site, then logs in later.


Goal Story

It's Saturday afternoon, and Stuart is busy planning the evening's activities. He visits a band listings website, where he clicks on a map to zoom into his local area. Even though he's never visited the site before, a profile is already being constructed, which he can see on the top of the site. At this stage, the profile guesses at his location based on his actions so far. As he browses some of the jazz bands, the profile starts to show an increasing preference for jazz bands, and some of the ads reflect that. Since the jazz thing is a one-off idea, he goes into his profile and tweaks some of those genre preferences, but leaves the location alone as that was correctly guessed. Finally, he decides to make a booking, at which point he establishes a password for future access to the same profile and also his address, which is posted back to the profile.


Problem

How can the user customize the site, while deferring formal registration?


Forces

  • Public websites thrive on registered users. Registered users receive personalised content, which means the website is able to deliver greater value per user. And registered users can also receive more focused advertising material.
  • For non-public websites, such as extranets used by external customers, registration may be a necessity.
  • Most users don't like giving their personal information to a web server. They have concerns about their own privacy and the security of the information. Furthermore, the registration process is often time-consuming.
  • Many users spend time familiarising themselves with a site before registering. In some cases, a user might interact with a site for years before formally establishing an account. There is a lot of valuable information that can be gained from this interaction, which will benefit both the website owner and the user.
  • Users may be willing to provide some information about themselves in order to access a service, but not all the information the system can potentially store.


Solution

Accumulate bits of information about the user as they interact, with formal registration occurring later on. As soon as the user visits the website, a user account is immediately created for them, with auto-generated ID, and set in a cookie which will remain in the browser. It doesn't matter if they never return—unused IDs can be cleared after a few months.

As the user interacts with the application, the account accumulates data. In many cases, the data is explicitly contributed by the user, and it's advisable to expose this kind of information so the user can actually populate it. In this way, the initial profile may be seen as a structure with lots of holes. As the user interacts with the system, some parts of the structure are filled in automatically and others are added by the user themselves. The user is also free to correct any of the filled-in data at any time.

Two particularly notable "holes" are a unique user identifier and a password. It is this combination of attributes that allows the user to access the profile afterwards from another machine or a different browser. They will also allow the profile to survive any deletion of cookies in the user's browser. So, while the pattern is generally about gradual accumulation of profile data, there remains a significant milestone in the user-application relationship, the moment at which user ID and password are established.

Do the user ID and password have to be provided simultaneously? No, even that can be incremental, if you use a little trick: use an email address as the unique identifier. In fact, this is fairly common nowadays. Email is usually required anyway, and it's unique, so why not make it the user ID? In the context of Lazy Registration, though, there's an additional benefit: the email might be accumulated in the natural flow of events—the site might add the user to an announcements list, for example. In some cases, the email might even be verified during this process.

Sceptics may wonder why a user would want to actively work with their profile. The answer was formulated in a web usability pattern called

Determine what users consider to be a "valuable" carrot. Offer the end user a portion of that carrot before you request personal information. The content is withheld ("the stick") until the requested information is provided.

Thus, users will only enter information if there is a perceived benefit to them. There is plenty of evidence this occurs—witness the social bookmarking phenomenon, where thousands of users make public their personal links. By exposing their profile, many of those users are hoping the system will point them in the direction of related resources they haven't heard of yet. That possibility, in turn, encourages them to add even more links, so as to avoid seeing known resources appear. Admittedly, del.icio.us is a rather techno-centric community at this stage, but there is also evidence of this approach further afield, as discussed in the real-world examples.

Now, it's clear that some systems have used this pattern for years, so what does it have to do with Ajax? Lazy Registration aims for a smooth approach, where the barrier is low for each new user contribution. So you want to sign up for the website's mailing list? Great, the summary profile is already on the side menu, just make sure your email's right. See what happened? With Ajax, there's no need to break the flow. No more "Just go over there for a few minutes, then come back here, and if you're lucky, you might be looking at something similar to what you can see now." That's a big win for websites aiming to drop the barrier of registration and it's great for users too.

If some of these techniques seem underhanded, you should be aware that they are manifestations of the technology at hand. It's standard practice for websites to collect data about users. The pattern here is actually about empowering users—instead of secretly building up a corpus of data on a user, you invite them to add value to their own experience by contributing the data themselves.

The following technologies are involved in implementing Lazy Registration:

  • Database: You clearly need a persistent data store in order to capture user profiles and associate them with the session ID that's stored.
  • XMLHttpRequest: Judicious use of XMLHttpRequest Calls are the key to the smooth interaction mode which you are seeking to achieve with this pattern.
  • Cookie Manipulation and Session Tracking: A cookie must reside in the user's browser, associated with your domain and identifying a unique session ID, which can serve as a key on the server-side to locate details about the user each time they access the website.

In conventional applications, the cookie is pushed from the browser as a header in the response. That's fine for Ajaxian Lazy Registration when the user first accesses the system, though sometimes it may be convenient to use a more Ajax-oriented approach. The first such approach is to manipulate the cookie in JavaScript. The second is to set the cookie using the response from an XMLHttpRequest Call, which all browsers are apparently happy to deal with in the same way as they deal with cookies in regular page reloads. In practice, you're unlikely to be playing with cookies anyway. Most modern environments contain session-tracking frameworks that do the low-level cookie manipulation for you (see also Direct Login). They generally use either URL-rewriting or cookie manipulation, and you need the latter to make this pattern work most effectively. Since responses from XMLHttpRequest set cookies in the same way as entire page reloads, you should be able to change session data while servicing XMLHttpRequest Calls.


Decisions

What kind of data will the profile contain?

Usability and functionality concerns will drive decisions on what data is accumulated. By envisioning how users will interact with the website, you can decide what kind of data must be there to support the interaction. For example:

  • Do you want to provide localised ads? You'll need to know where the user lives.
  • Do you want to use collaborative filtering? You'll need to capture the user's preferences.

In addition, consider that some Ajax applications are used all day long by users, such as employees working on an intranet website. For that reason, the profile might also contain preferences similar to those on conventional desktop applications. Many options will be application-specific, but a few generic examples include:

  • Enabling and disabling visual effects, such as One-Second Spotlight.
  • Setting Heartbeat-related parameters, e.g. how long will timeout be, will the system prompt the user when it's coming up.
  • Customising Status Area display.

No question about it, many companies like to accumulate as much data as they can get their hands on. Especially so in an economy where storage is trivially cheap. When a company is acquired, you can see tangible evidence that such data is worth something to someone. It's naïve to assume that usability concerns are all that drive data collection, however, it's important to be aware that laws and regulations apply, as should ethical standards.

How can the profile be accumulated?

You might know what data you need, but are users willing to give it to you? This comes back to the carrot-and-stick argument: you need to provide users a service that will make it worthwhile for them to provide that data. In addition, you need to communicate the benefit, and you must be able to assure them that the data will be safe and secure.

The least imaginitive way to gain user data is to pay them for it, or more deviously, pay others for it. Giving away a CD in exchange for data was well and dandy during the dotcom boom, but you'll have to do better than that today. Give the user a service they really need. For example:

  • If you want the user to provide their address, provide localised search features.
  • If you want the user to rate your product, provide recommendations based on their ratings.

How much data should be stored in cookies?

How much you store in cookies depends on your general approach to the Ajax implementation: is the application browser-centric or server-centric? A browser-centric choice would be to pack as much as possible in the browser's local state, optimising performance while running a full-fledged JavaScript application, with a little server-side synchronisation. A server-centric approach would rely only on data held server-side, with the browser accessing additional data using XMLHttpRequest Calls on a need-to-know basis.

One special concern is the security of cookies. If users access the application from a public PC, there's the risk of unauthorised access. In this case, it's especially advisable not to store sensitive information in the browser and offer the possibility of cleaning cookies at the end of the session. (For example, the "I'm on a public terminal" option.)


Real-World Examples

Amazon.com

Amazon has recently begun incorporating Ajaxian techniques, but was relying on Lazy Registration a long time prior. Visit Amazon as a new user, browse for just a few seconds, and here's what you'll see before even beginning to register or log in:

  • Shopping cart, which you can add items to.
  • Recently Viewed Items
  • Page You Made - showing recent views and books related to those.
  • Ability to update your history, by deleting items you viewed.
  • Ability to turn off "Page You Made".
  • Ability to search for a friend's public wishlist.

Kayak

Kayak is a travel search engine which retains queries you've made. A query is history is available for non-registered users, and it becomes part of your profile once registered.

Palmsphere

Palmsphere showcases Palm applications for download and purchase. Each item has a "Favourite" button—if checked, the item is one of your "Favourites". The Favourites list is summarised in your "Member Center" area, even if you've never registered, and retained in a cookie for the next time you visit.

Madgex

View Madgex Lazy Registration Demo Madgex is a whitelabel job board platform provider, used on about 150 job boards world wide. The new version of their platform provides lazy registration facilities, allowing job seekers to set up email alerts, apply for jobs, save their CV and save their cover letter without having to set up a password. When they choose to register, all the collected information and settings are revealed to them.

Code Examples

Ajax Shop Demo

The Ajax Shop Demo illustrates the kind of user-interface described by this pattern.

Running the demo, you'll notice a few things:

  • After the page initially loads, everything runs smoothly within the browser.
  • You can add items to your cart before registering.
  • The application guesses your favourite category by watching what you're looking at. If you prefer, you can override the application's guess, and the appliction will no longer attempt to adjust it.
  • By offering you the ability to send the cart contents to your email address, the application provides an incentive to add your email to the profile, without actually registering yet.
  • The password and email verification process itself is unintrusive - the main flow of the site is uninterrupted. Even while you're waiting for verification mail, you can continue to play around with the main content.

To keep things simple, it doesn't actually use a persistent data store—all information is held in the session. That's definitely not advisable for a real system, because you don't want to store passwords and other sensitive data there. Also, it means the user in theory could bypass the email verification by inspecting the cookie. Nevertheless, the application demonstrates lazy registration from the user's perspective, and the underlying code provides some illustration of what's required to develop such an application.

Here, I'll point out how a few of the features were achieved.

Retrieval of Categories and Items

The application maintains the flow by avoiding any page reloads when categories and items are accessed. No information about categories or items are hard-coded; generic REST services are used to extract the data, and its rendered locally in JavaScript.

Cart Management

Again, the only real relevance of cart management is that page reloads are avoided. The cart contents are tracked in the session, so they should be present when the user resumes using the website. When the user adds something to the cart, the JavaScript cart is not directly altered. Instead, the new item is posted to the server as XML:

 function onAddItemClicked(item) {
   var vars = {
     command: 'add',
     item: item
   }
   ajaxCaller.postForXML("cart.phtml", vars, onCartResponse);
 }

Likewise, when the cart is cleared:

 function onCartClearClicked() {
   var vars = {
     command: 'clear'
   }
   ajaxCaller.postForXML("cart.phtml", vars, onCartResponse);
 }

For both operations, the server retrieves the session cart and alters its state:

 $cart = $_SESSION['cart'];
 
 if (isset($_POST["command"])) {
   if ($_POST["command"] == "add") {
     $cart->add($_POST["item"]);
   } else if ($_POST["command"] == "clear") {
     $cart->clear();
   }
 }

Then, the server outputs the final state as an XML response.

 header("Content-type: text/xml");
 echo "<cart>";
 $contents = $cart->getContents();
 foreach ($contents as $itemName => $val) {
   echo "<item>";
   echo "<name>$itemName</name>";
   echo "<amount>$val</amount>";
   echo "</item>";
 }
 echo "</cart>";

In the browser, onCartResponse is registered to render the cart based on the resulting XML.

Mailing Cart Contents

Along with several other fields, the profile block contains the user's email. There is also a clickable "Mail" field on the cart.

  <div>
    <div class="userLabel">Email:</div>
    <input type="text" id="email" name="email" />
  </div>
  
  ...
  
  <span id="cartMail">Mail Contents</span>
  
  ...
  
  $("cartMail").onclick = onCartMailClicked;

When the user clicks on cartMail, the server checks that the email has been filled in, and simply uploads a POST message for the mail to occur. In this case, there's no feedback to the web user, so the callback function is blank.

 vars = {
   command: "mailCart",
   email: email
 }
 ajaxCaller.postForPlainText("cart.phtml", vars, function() {});

The server receives not only the command, but the email itself, since this might not yet be in the user's profile. Just prior to sending the mail, the server retains the email as part of the user's session. (Again, this is a simplification, because retaining the email would not be necessary—or desirable—if the user was already logged in.)

 function mailCart() {
   ...
   
   $email = $_POST["email"];
   // Add mail to the profile - it's part of the lazy registration.
   $_SESSION['email'] = $email;
   
   ...
 }

After that, it's a simple matter of constructing a message from the server-side cart state and sending the email to the specified address using standard server-side libraries.

Tracking Favourite Categories

Firstly, there is a fixed "favourite category" selector in the HTML. It begins empty and is populated when the categories are loaded.

  <div id="favouriteCategoryInfo">
    My Best Category: <select id="favouriteCategory"></select>
  </div>
  
  function onAllCategoriesResponse(xml, ignoredHeaders, ignoredContext) {
    ...
    
    categoryExplores[category] = 0;
    favouriteCategoryOption = document.createElement("option");
    favouriteCategoryOption.text = favouriteCategoryOption.value = category;
    try {
      $("favouriteCategory").add(favouriteCategoryOption, null); // FF
    } catch(ex) {
      $("favouriteCategory").add(category); // IE
    }
    
    ...
  }

There's also a JavaScript-based mode to indicate whether the favourite category selection is automated or not. It begins in automated mode.

 var isFavouriteCategoryAutomated = true;

If in automated mode, the script watches each time the user explores an item. Each cateogory is tracked according to how many times the item was explored, the selector being altered if a new maximum is reached.

 var categoryExplores = new Array();
 
 ...

 function onExploreClicked(category) {
   ...
   
   if (isFavouriteCategoryAutomated) {
     categoryExplores[category]++;
     favouriteCategory = $("favouriteCategory").value;
     favouriteCategoryExplores = categoryExplores[favouriteCategory];
     if (categoryExplores[category] > favouriteCategoryExplores) {
       $("favouriteCategory").value = category;
     }
   }
 }

As soon as the user decides to overwrite this guesstimate by manually setting the preference, it stays manual forever.

 $("favouriteCategory").onclick = function() {
   isFavouriteCategoryAutomated = false;
 }

For the sake of simplicity, this field is not actually tracked in the server, though it could easily be persisted as part of the user's profile.

Verifying Password and Email

Now for the most important part. The user's finally willing to verify password and email. These could potentially be broken into two separate verification activities, but they both fit together as a formal registration step, so they are combined in the demo.

The trick is to manage the process with a little state transition logic. The registration is broken into a few states, with transitions between them. Each state requires handling events in a slightly different way. Each transition involves altering the UI a little to reflect what the user can do. Refer to Gamma et al's (1995) State Pattern for more details on this approach.

registerState holds the current state:

 /*
   "start": When page is loaded
   "mustSendMail": When instructions and verify password field shown
   "mustVerifySecretNumber": When email sent and user must enter secret 
     number inside email
   "verified": When user is successfully logged in
 */

 var registerState = "start";

The HTML for this demo contains all the necessary fields and buttons, their visibility toggled based on the current state. For example, following are the password and password verification fields. The password field is always shown until the user is at "verified" stage, while the "verify password" field is only shown after the user initiates the registration process.

  <div id="passwordInfo">
    <div class="userLabel">Password:</div>
    <input type="password" id="password" name="password" />

    <div id="verifyPasswordInfo">
      <div id="regHeader">Demo Registration</div>
      <div class="regInstructions">
        <strong>1.</strong> Please ensure email address is correct and 
        password is <strong>not</strong> confidential, then verify your 
        password below.
      </div>
      <div class="userLabel">Verify Password:</div>
      <input id="verifyPassword" type="password" name="verifyPassword" />
    </div>
  </div>

All three buttons are declared, and again, their visibility will change depending on current state.

  <input type="button" id="login" value="Login" />
  <input type="button" id="register" value="Register" />
  <input type="button" id="cancel" value="Cancel" />

The login button is only for demonstration purposes and the cancel button resumes the state back to "start", which causes the display to return to its initial state, too. What's most important here is the "Register" button, which drives the process through each state. While the button's label is changed to reflect the action being performed at each state, it is always present until the user is verified. For this reason, its event handler remains the same and decides what to do based on the current state:

 function onRegisterClicked() {
   if (registerState=="start") {
     registerState = "mustSendMail";
   } else if (registerState=="mustSendMail") {
     var submissionOK = sendMail();
     if (submissionOK) {
       registerState = "mustVerifySecretNumber";
     } else {
       return;
     }
   } else if (registerState=="mustVerifySecretNumber") {
     verifySecretNumber();
   } 
   onRegistrationStateChanged();
 }

And onRegistrationStateChanged() purely exists to reveal and hide fields, and change the button label, based on the current state:

 function onRegistrationStateChanged() {

   if (registerState=="start") {
     $("userForm").reset();
     $("login").style.display = "inline";
     $("verifyPasswordInfo").style.display = "none";
     $("secretNumberInfo").style.display = "none";
     $("verifiedInfo").style.display="none";
     $("cancel").style.display = "none";
     $("register").value="Register";
   } else if (registerState=="mustSendMail") {
     ...
   } else if (registerState=="mustVerifySecretNumber") {
     ...
   } else if (registerState=="verified") {
     ...
 }

An alternative design might actually manipulate the DOM itself, adding and removing the elements. Or it might generate the specific HTML for the form at each stage. However, relying on the state pattern for this process makes it easy to quickly alter the flow and appearance of the registration process.


Alternatives

Related Patterns

Direct Login

Direct Login is a companion pattern, since some dynamic behaviour can allow for login and registration to appear on the same form.

Live Form

It's useful to maintain the profile details in a Live Form, so the user can easily add to them and the server can synchronise state and provide opportunities for further enhancement to the profile.

Heartbeat

Where data is held in cookies, it's a good idea to expire them if there is a risk that others may gain access to the browser. Heartbeat helps the server decide if the client is actually active. If not, it may be wise to ensure any sensitive data is wiped from cookies held in the browser.

Guesstimate

Lazy Registration can sometimes involve inferring information about the user's profile by monitoring their behaviour. Thus, it embraces the same fuzzy principles as Guesstimate, where a guess is acknowledged to be imprecise, but better than no guess.

Visual Metaphor

A good salesman works the same way. While assumptions might be made based on a prospect's behavior, the salesman is always listening and those assumptions are open to challenge. (Malcolm Gladwell detailed this pattern of successful salespeople in Blink.)

Want to Know More?

External Link

Acknowledgements

The idea to handle lazy registration in this Ajaxian manner was originally proposed by Chris Were ("Tahpot").