Operating a website used by predominantly non-technical users can be an eye-opening experience when the time comes to support those users. It’s easy to forget how much of the nomenclature and technical understanding that we take for granted is just unintelligible jargon to others. In fact about 10% of people surveyed this year even guessed that HTML was an STD.

A particularly poignant example I dealt with recently was a user telling me they were using “Google” to browse the Internet on their desktop PC. You’d think that probably means they were using Google Chrome as their browser, right? Nope. They were using Internet Explorer with Google’s website set as their home page.

Unfortunately, assisting the most helpless users with technical issues still requires that they communicate details about their platform and browser to you at least semi-accurately. The broader problem is bigger than anyone can solve in a thousand words, but in this post I want to show you one small improvement I’ve made on my public-facing contact forms to help cut down on confusion with this specific aspect of helping non-technical users.

Browser knows best

The key to improving this situation is to eliminate dependence on the user’s knowledge about their browser entirely. As it turns out, the browser is already happily communicating this information.

In fact, every single request a user’s browser sends includes a string known as the user agent. You’ll see this user agent show up in raw server logs and server-side HTTP-related variables on almost every server-side platform and web framework.

For example, here’s my user agent right now, running Chrome 34 on Windows 8.1:

Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.60 Safari/537.36

Next, here’s Internet Explorer 11 running on my Windows 8.1 Surface 2:

Mozilla/5.0 (Windows NT 6.3; ARM; Trident/7.0; Touch; rv:11.0) like Gecko

Finally, here’s my iPhone running Mobile Safari under iOS 7.1:

Mozilla/5.0 (iPhone; CPU iPhone OS 7_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D167 Safari/9537.53

Those strings aren’t exactly the most straightforward representations of Chrome, Internet Explorer, or Mobile Safari, but they’re definitely more reliable than the user who tells me “Google” when they mean “Internet Explorer”.

Let the server be your guide

There are handy sites you can send users to that will show them their user agent, like support details and what is my browser. However, life is much easier if you can eliminate the time-consuming roundtrip and potential inaccuracy of manual self-reporting.

The great thing about the browser’s user agent is that your server-side code probably already has access to it on every request. In every web framework you’re likely to encounter today, you should have some sort of access to the value of an HTTP header named HTTP_USER_AGENT. As you might guess, that will contain the user agent string that came along with the request.

With that data in hand, adding it to your contact form’s emails is a straightforward line or two of code. It literally only took five minutes last year to append the user agent to one of my ASP.NET sites’ contact forms, push that to my master git branch, and have that change automatically deployed to my production site on Azure. A five minute change that has saved me hours since.

See the following sections for specific syntax for accessing the request’s user agent in a few popular frameworks.


ASP.NET exposes a collection of server variables in the current HttpContext‘s
ServerVariables property. From the scope of an MVC controller action or WebForms code behind, you can concisely access that via the Request convenience property:

There’s also a handy UserAgent shortcut property on the Request object:

Note: Request isn’t available outside of the Page or Controller scope. If you need access to it somewhere like a static method or model class, you’ll need to explicitly reference the current HttpContext:

For a simple runnable example of collecting form data, adding the user agent, and sending an email using .NET’s built-in SmtpClient, take a look at this example on GitHub: Encosia-Samples-Contact-Form-with-User-Agent

Edit: As JK points out in the comments below, it’s probably not the best idea to reference HttpContext.Current directly and tightly couple ancillary code to System.Web. Better instead to pass Request.UserAgent into any other code that needs access to it, from the Controller or Page.


In Node, the first parameter to http.createServer‘s callback gives you access to a headers object that exposes a user-agent property.

This is how you could modify the example shown on the Node.js home page to echo back the browser’s user agent instead of “Hello World”, for example:

If you’re using Express, the first parameter passed into Express’ route handler callbacks exposes the same user-agent property. This is how you could get access to it in the index.js that Express 3.x’s generator creates:


Since this site runs on WordPress, I begrudgingly get my hands dirty with a bit of PHP from time to time. In PHP, there’s a $_SERVER superglobal that provides easy access to server variables like the user agent:


Thanks to Phil for providing this example of how to access the user agent in Go:


Am I missing your favorite framework or language above? Leave a comment below with an example and I’ll be happy to add it here.


Initially knowing as much as possible about how a user is accessing your site can be a huge asset when troubleshooting support issues. Never needing to ask users about their browser, device, or operating system has saved me hours supporting just one of my public-facing sites alone over the past year. I can’t believe it took me so long to spend a few minutes on the code that captures that data during the contact form submission.

While the user agent is helpful for diagnosing problems for legitimate users, it’s good to keep in mind that user agents are trivially easy to change. Like the referer [sic] header, it’s not a good idea to trust most HTTP headers for anything more than supplemental information.

Once you begin capturing user agents, a great next step is to include information about whether JavaScript is enabled and the presence of ad blocking and/or privacy plugins that can break even harmless sites. Let me know in the comments below if you’d like to see an example of how to do that in a followup post.