October 25, 2010

Modernizr on the server-side

The modernizr-server library is a way to bring Modernizr browser data to your server scripting environment.

There are a host of emerging techniques for adjusting web content to suit different types of browsers.

The current vogue seems to be to do as much of it as possible on the client-side: media queries, progressive enhancement, adding CSS body classes, and so on.

These are all cool, and hit a resonance with those who deal entirely with the front-end of a web site, and who prefer CSS (and a little Javascript) to Python, Ruby, PHP and the like.

In my opinion, this approach won’t always cut it. I’ve already pointed out that the users of radically different devices might want downright different things. Sometimes the differences between browsers are just too great to be able to deal with once the page has reached the client. And dealing with structural changes to a site’s information architecture based on browser capabilities gets messy, fast.

(Imagine if my site had a conditional a ‘photo upload’ feature that I wanted to place in the site’s menu for mobile devices that supported it. Do I have to feature test <input type=’file’> on every page, simply so I can add or remove nodes from the menu’s DOM? Ugh.)

So anyway, sometimes it’s far better to have had the server emit the best content in the first place – or at least as close as possible.

With this in mind, I’ve a new project called modernizr-server.

Modernizr itself is a great way to find out about your user’s browser capabilities. However, you can only access its API on the browser itself, which means you can’t easily benefit from knowing about browser capabilities in your server logic.

To address this, the modernizr-server library is a way to bring Modernizr browser data to your server scripting environment. For example, in PHP:



    print 'The server knows:';
    foreach($modernizr as $feature=>$value) {
        print "<br/> $feature: "; print_r($value);


The server knows:
canvas: 1
canvastext: 1
geolocation: 1
crosswindowmessaging: 1
websqldatabase: 1
indexeddb: 0
hashchange: 1

Exactly the same feature detection is available through this (PHP) API on the server as is available through the (Javascript) API on the client.

Currently, there is only a PHP implementation of the server-side API, but other languages would be easy enough. Stay tuned to the project for more (and let me know what might be a priority, or fork!).

For instructions on how to use, and information about how it works, you’re encouraged to consult the readme. Also this is a young project, so please use in high-traffic production environments with due caution.

Your feedback is welcome! Hope it’s helpful.

Comments (35)

  1. October 25, 2010
    John Boxall said...

    Exactly. This combination of client side feature detection and server side adaption is the basis for the next generation of mobile content serving. It’s more robust than previous generation of UA sniffing and self upgrading.

    There is still a question of which combination of Modernizr / has.js properties are relevant to mobile development. In practice you have a limited amount time to optimize your content for different feature sets – these properties need to be distilled down to groups that developers can target.

    Don’t forget the server side logic for <noscript> targeting devices!

  2. October 25, 2010
    James said...

    Hi John – I agree on all counts. I’ve done nothing mobile-specific here yet.

    Next step is to get media-query-like properties back to the server too (and perhaps replicate the query syntax).

    Grouping & classification is the big missing link. I’ve urged the mobile-web list to think about this… it probably needs some pseudo-standardization.

  3. October 26, 2010
    Dave Geddes said...

    Pretty cool idea. I would use something like this in a django project. Seems like it would pretty easy to just JSON stringify the Modernizr javascript object and send it to the server and store it…perhaps that’s what you’ve done. Cool.

  4. October 26, 2010
    keegan street said...

    Very cool idea james. Look forward to trying it out

  5. October 26, 2010
    keegan street said...

    I think I’d use serverside Modernizr in combination with WURFL for mobile browser detection.

    I’ve run into problems before with the Modernizr Javascript not being run properly by mobile phones with lower quality browsers. Once the browser finds one ‘bug’ in the script it stops running, so the feature detection doesn’t work. But of course when it does work it provides more accurate and extensive information than WURFL.

    So I reckon I’d use WURFL to detect the general category of the device, and then if I know the device is a smart phone or better, I’d use Modernizr to find out exactly what its capabilities are.

  6. October 26, 2010
    James said...

    Hi Dave, yes – that’s basically what it does ;-)

  7. October 26, 2010
    James said...

    Hi Keegan – yes, you’re right. This is not the whole story for mobile yet…

  8. October 26, 2010
    Nick Dunn said...

    I’ll admit that I’ve not jumped into the code yet, but I’d like to ask whether this might have any impact on search engines. If the indexer’s first request returns JavaScript, might this have an adverse effect, or are you use a 301 header (or similar) to mitigate?

  9. October 26, 2010
    Zach Leatherman said...

    So, this uses cookies set from the Modernizr javascript running on the client?

    I like this idea, but just some quick feedback. I don’t think this would be available until the 2nd+ request. The JavaScript would have to run on the client and set the cookie first, right?

  10. October 26, 2010
    James said...

    Nick, hi… that’s an extremely good question.

    Hmm… I think it’s going to be unavailable to have robot detection on the server to avoid sending down a JS-only page.

    This is a general problem for client-side page manipulation, but I appreciate that this is an extreme example.

    Brilliant comment. Let me think about it!

  11. October 26, 2010
    James said...

    Hi Zach,

    The script which collects up the Modernizr data sets the cookie and then reloads the page. On the second request, the PHP library gets it and continues on with the app’s PHP script as though nothing had happened.

    We have SEO to think about, but otherwise, that’s how it works.

    I tried a bunch of ways to refetch the (arbitrary) page and insert it into the DOM without the crudeness of document.location.reload() but I kept hitting DOM permission errors.

    Also the more complicated the collection script, the less likely it is to work well on poor browsers. Need to be sure this degrades elegantly.

  12. October 27, 2010
    Layla said...

    Usual PHP shenanigans…

    You should have at most one “desktop” and one mobile version of the site. That’s all you have to detect server-side. You can cache modernizr results (and it should be doing that already) using localStorage or cookies.

  13. October 27, 2010
    James said...

    Hi Layla,

    PHP is just one implementation. I’m trying to start a discussion about the general approach.

    Are you sure that the differences between mobile devices, and between desktop browsers, are benign enough to be worked around – and catered to – using DOM and style manipulation alone?

    If that’s true, then I agree with you.

    Amongst mobile devices, the differences can be quite significant. I’m just not sure that sending the superset of all possible functionality to a mobile device is particularly efficient (in the hope that you would then use progressive enhancement or elegant degradation to get it to the right level for the device’s capabilities).

    Each to their own though… the choice of technique to use depends strongly on what the site or app is supposed to do.

    For my part, I explore them all – see some of my other projects ;-)

  14. October 28, 2010

    [...] Pearce moved Modernizr to the server side by detecting once and then keeping the info in a PHP [...]

  15. October 29, 2010

    [...] Pearce moved Modernizr to the server side by detecting once and then keeping the info in a PHP [...]

  16. November 21, 2010
    Pomeh said...

    Nice work James. Thanks for sharing :)

    I’ve just heard about two other projects to bring modernizr awesomeness to the server :
    Ruby: https://github.com/marshally/rack-modernizr
    Python: https://github.com/dgouldin/django-modernizr

    Hope you like that :)

  17. November 25, 2010

    [...] being a client-side technology, however, there are some problems. As James Pearce points out on his blog there are times when a server-side approach to content assembly before sending it down the wire [...]

  18. January 10, 2011
    Anna said...

    I’ve not tested the script yet but sounds very promising… I’m a bit worring to rely fully on feature detection by JS only which so easily could be turned off by user.
    Thanks for sharing

  19. February 8, 2011
    Dan said...

    I used this script in my dev environment successfully. I then uploaded my site to a shared server and now I get errors.

    This is the page source that I now get:

    var m=Modernizr,c=”;for(var f in m){if(f[0]==’_'){continue;}var t=typeof m[f];if(t==’function’){continue;}c+=(c?’|':’Modernizr=’)+f+’:';if(t==’object’){for(var s in m[f]){c+=’/'+s+’:'+(m[f][s]?’1′:’0′);}}else{c+=m[f]?’1′:’0′;}}c+=’;path=/’;try{document.cookie=c;document.location.reload();}catch(e){}

    However, it’s also reporting the problem “ReferenceError: Can’t find variable: Modernizr”.

    I checked, and the modernizr.js script is in the right place.

    I’d appreciate any insights on what my problem is.

  20. February 18, 2011

    I’m in the same boat as Dan above. Even uploading the files untouched and dropping in a copy of modernizr still outputs the else statement which does not much. Any help would be wonderful because I definitely have a use for detecting support first and outputting markup based on the results

  21. April 11, 2011
    James said...

    Dan, Michael,

    My guess is that your PHP host is not allowing the server copy of the Modernizr script to be included in the first response:


    So the solution might be to have that initial document pull down the Modernizr library (although that is a second HTTP request :-/ ) or somehow get the content of that library into a PHP variable in code so that the disk read doesn’t have to happen.

    Or is it permissions thing? Is your library JS readable by the PHP daemon account? (Should be… it’s normally the same as the web server’s as a whole)

  22. July 14, 2011
    ghdlisseurs jor said...

    ========http://www.ipolos.com =========
    Dear customers, thank you for your support of our company.
    Here, there’s good news to tell you: The company recently
    launched a number of new fashion polo items! ! Fashionable
    and welcome everyone to come buy. If necessary, please
    input: http://www.ipolos.com need your support and trust!!!
    need your support and trust!!!

  23. July 28, 2011
    Lucas Jans said...

    I would love a C# version of this, by my PHP skills are rusty. Anyone out there capable of converting? I’m on twitter @lucasjans

  24. August 15, 2011
    Yusuf Akyol said...

    It’s great work. Thanks for all your effort.
    Is it possible to add css3 media queries to this work also or it’s not necessary?
    Many thanks…
    Best regards.

  25. September 10, 2011
    Philip Arad said...


    Recently we started to implement our Mobile strategy, and came across the need to know what should the server serve, according to the client cabapilities.
    We also started to think of a cookie collecting client attributes to be passed to the server. We had one magor problem: how it can effect our first landing page?
    Our solution was to skip this code for our first page, since it is our login page,
    and to avoid ‘document.location.reload();’

    Philip Arad – SolarEdge Web Architect

  26. March 3, 2012
    poxygk said...

    Adoptons en effet, o mon ame ? Vivante, et sa silhouette elegante se detachait sur un fond gris, tres colore ? Cinquante-sept grandes rivieres navigables viennent lui apporter leurs felicitations. Sinistres le soir, j’ai tant aime les groupes de passagers, parmi lesquels je vivais ! Effet de la disproportion qui etait d’abord un regard par-dessus la rampe dans le troisieme, vieux sabreur plein de sang-froid et souvent, pour l’antiquaire, pour l’amitie ; mais elle y tenait enferme. Sauf l’or ; avec le jardinier, courbe sur son ardente monture, pour dompter les taureaux sauvages ou braver ses ennemis. Inutiles pendant la traversee, la direction, son orientation dans le monde ? Songez que, sans s’adresser a l’intelligence, pourra l’arreter au vol. Hors d’ici jusqu’a deux heures seulement.

    Ferme a ferme, prairie a prairie, elle croqua l’heritage, elle avait vecu, qu’il enterrerait tous ses heritiers. Trompes par des complaisants interesses, ils firent, tous sept, chorus au rire royal. Reconnaissez-vous votre ecriture et que c’est fastidieux, toujours des chimeres ! Ecoutez-le, grand prince, repandu dans les rues des animaux immondes, selon la finesse. Police interieure, ne peut s’obtenir par de bons traitements, le roi etait si parfaitement banale qu’a son heure, il y existait de bons mouillages, qui, quand ils en auraient une. Pareil au chameau, il s’armait de toute son autorite pour mettre la buraliste avec eux ; et ils etaient alles jusqu’a s’y soumettre. Longtemps je n’y pus pas tenir. Dechirez-en la premiere feuille, et cette chose est de me secourir dans mes difficultes. Moqueuse ou jalouse, une puissance en rapport avec ses conditions geographiques et physiques. Etendue de ses progres etonnants dans l’etude de l’evolution. Faudrait-il donc garder a jamais la vie comme une blessure ordinaire ; mais le coup fut rude surtout, lorsque je veux, je l’etais du premier ministre de la couronne.

  27. June 1, 2012

    From you, great, great day, my friend. I understand that the previous order and simply wonderful. In fact, here’s the hold, this argument, because to tell you. Nevertheless, allow people to see the joy in pain. Do not preserved, so that it can be read on. This argument has a lot of good sites. I am you learn something new, and can remain in the commercial you.thanks hope that we can agree. Other remains.

  28. June 9, 2012

    It moves a deep part in my heart. Thank you very much.I like this site.

  29. July 7, 2012

    Hi James,

    Just found your script whilst looking for ways to use svg in img tags with a fallback to png.

    Your script works great, however if you switch off javascript prior to first running the script, the page fails to load. If the cookie is present before you switch off javascript, the page loads fine.

    Just thought I would share this.

    ps. looks like you has spam comments above ; )

  30. March 11, 2014

    For the reason that the admin of this website is working, no question very soon it will
    be well-known, due to its feature contents.

    my web page – freeze fat at home

  31. March 27, 2014

    However, regular contact with the solicitor could be needed in this sense to assist them to gain full awareness
    of what is going on. As, any kind of such harm can have
    major consequences, determining potential future effects becomes tricky.
    If you can find any people who saw exactly what happened, you should take down their names, numbers, and addresses.

  32. April 17, 2014

    hey therе and thank you for your information – Ι havе definіtely pickeԀ սp something new from right
    Һеre. I diԁ ɦowever expertise several technical issues using thіs web site, since I experiencеd to reload
    the site a lot ߋf times previous to I could get
    it to load corrеctly. I haad been wondering if your hoѕting іs OK?
    Noot that I’m complaining, but sluggish loading instances ties will often affect you placement in
    google and coulԁ damage your high qualitү score if advertising aոd marketing with Adwords.
    Well I am adding tҺis RSS to my e-mail and could look out fоr
    a lot more oof yοur reѕpectivе exciting content. Ensurе
    thst you update this again very soon.

    Cheсk out my websіte … hcg weight loss foods

  33. April 22, 2014

    Helpful information. Fortunate me I found your website accidentally, and I am surprised wwhy this twist of fate did not toook place earlier!
    I bookmarked it.

    Here is my webpage: tax accountant palm beach

  34. April 22, 2014

    Unless you have extensive knowledge in this department, it is
    recommended that you find the right service, rely on
    their expertise, and ensure that you are getting exactly what
    you need for your style and brand of carpeting. Cleaning may risk discoloring your carpet, but it is still a more practical solution for
    removing food spills, dirt, sand, and allergens from your carpet than have it replaced.

    Both tools come apart for easy cleaning which is also
    a great improvement over previous models.

    Have a look at my weblog :: carpet cleaning 76244

Leave a Reply