Single Page Refresh for Client Side Data Server Side

Chris Coyier //

UPDATE: I have a newer article "Server Side Mustard Cut" that covers this same ground and has many of the quirks worked out. That's probably a better read.

We recently covered how you could get client-side information and make it available server side. Do real tests on the client, like measure browser window width and do feature tests. Then save that data to a Cookie. Then next time the page is loaded, you'll have that data in a cookie.

I quite like that technique, and use it, but what if you really want to be using that info on the first page a user sees? You might need to do a page refresh, but you have to be safe about it.

You might be tempted to just test if the cookie is set, and if not, set it and reload. PHP and jQuery here used just for demo purposes, but you can (and I have) done this in any different backend language and with or without a front end library.

<?php if (isset($_COOKIE['_clientInfo'])) { ?>

  <script>
    // Do tests, set cookie

    location.reload(true); // true means don't use cache
  </script>

<?php } else { ?>

  <!-- Proceed normally, using cookie data to make more choices -->

<?php } ?>

This is quite dangerous though. Because:

  1. A user might disallow cookies on purpose.
  2. A user might be using a browser that doesn't allow cookies.

From what I can tell, iOS app that include a WebView need to specifically turn on the ability to accept cookies, meaning the default is to not allow them.

If either of those above two things are true, you'll get into an infinite-reload situation, which is very bad.

The trick here is to approach it this way:

  1. Test if the cookie is present server-side.
  2. If the cookie isn't set, set it on the client side with the data you want.
  3. Then do another test, client side, if the browser supports cookies or not.
  4. If it does support cookies and you haven't used it yet (cookieUsed), then refresh.

Here's a complete document that shows how it could go down:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset='UTF-8'>
  <title>Client Info In Cookie</title>
  <script src="//code.jquery.com/jquery-1.10.2.min.js"></script>
</head>

<body>

    <?php if (isset($_COOKIE['_clientInfo'])) { ?>

      <p>Use the data as you see fit!</p>

      <?php
          $json = $_COOKIE['_clientInfo'];
          $obj = json_decode(stripslashes($json));
          echo "<p>Browser Width: " . $obj->{'browserWidth'} . "</p>";
          echo "<p>Browser Height: " . $obj->{'browserHeight'} . "</p>";
          echo "<p>Flexbox Support: " . $obj->{'flexboxSupport'} . "</p>";
          echo "<p>SVG Support: " . $obj->{'SVGSupport'} . "</p>";
      ?>

      <p>You can use it server-side OR client-side.</p>

      <script>
        // You could use the plugin here too, but whatever this is lighter
        var clientInfo = JSON.parse('<?php echo $_COOKIE['_clientInfo']; ?>');

        output = "<p>Browser Width: " + clientInfo.browserWidth + "</p>";

        $("body").append(output);
      </script>

    <?php } else { ?>

      <!-- LOAD TESTING LIBRARY, only load when testing -->
      <script src="js/modernizr.js"></script>

      <!-- COOKIE LIBRARY -->
      <script src="js/jquery.cookie.js"></script>

      <!-- CREATE COOKIE -->
      <script>

        var clientInfo = {
          browserWidth: $(window).width(),
          browserHeight: $(window).height(),
          flexboxSupport: Modernizr.flexbox,
          SVGSupport: Modernizr.svg
        };

        var cookieVal = JSON.stringify(clientInfo);

        // was using document.cookie, this plugin worked better
        $.cookie("_clientInfo", cookieVal, {
          expires: 7
        });
      </script>

      <!-- RELOAD PAGE if supported and not used -->
      <script>
        var cookiesEnabled = navigator.cookieEnabled ? true : false;
        if (cookiesEnabled) {
          location.reload(true);
        }
      </script>

      <p>Make sure you serve useful content here as well.</p>

    <?php } ?>

</body>

</html>

Live demo here.

You may need to mess around with that structure a little to suit your needs. The important part being that you serve useful content no matter what the result is. The worst that can happen then is that you keep trying to set a cookie that will never get set for those users in no-cookie environments. You make the call on how acceptable that is.

You could do more robust testing with something like Detector.

We use this on CodePen (as of this update, December 2014), and have made improvements to it.