Detecting whether or not a visitor to your web site can accept
cookies is not difficult. There are, however, a number of issues
involved in the process which can cause it to get confusing.
This article will explain the problems faced and address them one
by one. This will result in a cookie detection script written in
ASP that you can use on your own site.
The Problem
I often get asked how you can check to see if a visitor to your
web site user has cookies enabled or not. It used to be because
not all browsers supported them. These days, even though they
are almost universally supported, there is still a stigma associated
with cookies and many users go out of their way to disable them. So
even if you find out that their browser can support them, it does not
mean that it will accept the cookies you send. The only way to be
sure cookies are available for you to use is to actually try and use
them and see if they work. So that's the approach this script will
take.
So... what's the big deal?
This seems pretty simple so far. I'll set a cookie and see if it
exists. A simple piece of code should accomplish this.
cookie_bad.asp
<%@ Language="VBScript" %>
<%
Option Explicit
' Declare 2 variable to hold our values.
Dim strCookieValueSet
Dim strCookieValueRead
' Set two default values that are different.
strCookieValueSet = "true"
strCookieValueRead = "false"
' Set a test cookie with a value and an expiration date.
Response.Cookies("cookie_test") = strCookieValueSet
Response.Cookies("cookie_test").Expires = Date + 1
' Read the cookie to see if it exists.
strCookieValueRead = Request.Cookies("cookie_test")
' Compare the value set and the value read back.
' If they're the same it would seem that cookies
' are actually working.
If strCookieValueSet = strCookieValueRead Then
Response.Write "Cookies Are Supported!"
Else
Response.Write "Cookies Are Not Supported!"
End If
' Don't be fooled... try this script with a browser
' that has cookies turned off... it still says cookies
' are enabled! (It's really not the script's fault!)
%>
I've gotten many pieces of code that have attempted this approach and
they're usually accompanied by a note asking where the typo is in the
script. There's not one! Now let me explain why that doesn't work.
The web works over the HTTP protocol which is where cookies come from.
A complete HTTP request consists of the browser asking for a piece of
content and the server responding with the content the browser asked
for. Well, along with this request and content, there is additional
information sent so that both the client and the server know how to
handle the content. This additional information is contained in
headers that are sent along with the transmission in both directions.
These headers can contain cookie information. Via these headers, the
server can set cookies and according to the HTTP standards, browsers
that have received a cookie from a server are supposed to send that
cookie back to the server with all future requests to that same server
(until the cookie reaches its expiration date and time). It is this
interaction with the headers that ASP does for you when you use the
Response.Cookies or Request.Cookies collections.
The problem lies in the order in which the events must occur. As I
mentioned earlier, requests comes in and then the server sends a
response. Well, the ASP processing happens at the server in between
these two steps. As such, ASP has access to the cookies sent with the
request and can set cookies to be set in the response, but it really
has no idea if those cookies it just told the browser to set will ever
actually be set. Those are the cookies that the above script reads
back from the cookie collection right after it sets them. They haven't
yet made the trip to the browser and been sent back, so there's really
no way to be sure they ever will be.
Checking for a Reply
So since we can't see if a cookie has been sent back on the first
request, it actually takes two requests to complete our cookie test.
The first one to set the cookie during the response. The second one
to see if the browser sent it back with the reply. This is all well
and good, but it can be cumbersome to manage so I've tried to wrap it
up into a nice little page you can add you your site and utilize just
by adding a few lines to any page.
Let me outline the basic process. A request comes in to a page on your
web site (cookie.asp). This page contains some code that checks for
a signal that cookie detection has been done. If it finds it, it
continues about its business using this information as it sees fit.
If, on the other hand, it doesn't, it directs the browser to the
cookie detection script (cookie_detect.asp) which determines this
information and sends the browser back to the original page
(cookie.asp) along with the new found knowledge of whether or not
cookies are supported.
Now passing all this information around is what became the hard part
in this script. I can't use sessions or cookies since they both rely
on cookies! So that basically left me with the QueryString and so
that's what I used.
Without any more ado... here are the two scripts involved.
cookie.asp
<%@ Language="VBScript" %>
<%
Option Explicit
' Buffering needs to be on to be able to redirect to
' the detection script if we need to.
Response.Buffer = TrueDim bCookies ' T/F indicating cookies enabled.
Dim strURL ' URL to this page.
Dim strQS ' QueryString of initial request.
' Read in the value of cookie enablement.
bCookies = Request.QueryString("cookies")
' Check for a value indicating cookie enablement.
Select Case LCase(bCookies)
Case "true", "false"
' We got a valid response.
bCookies = CBool(bCookies)
Case Else
' We didn't get a valid response.
' Get the info we need to pass to our detection
' script so we can get back here.
strURL = Request.ServerVariables("URL")
strQS = Request.QueryString
' Clean up trailing ? problem we ran into
' if there's no QS on initial request.
If strQS <> "" Then strQS = "?" & strQS
' Send browser to be tested and tell the test
' script where to send them when they're done
' being tested.
Response.Redirect "cookie_detect.asp?from=" _
& Server.URLEncode(strURL & strQS)
End Select
' By the time we get here, we should always have a
' boolean value in bCookies indicating whether or
' not cookies are enabled.
%>
<html>
<head>
<title>This Page Needs to Know if Cookies Work</title>
</head>
<body bgcolor="#FFFFFF">
Cookies Are Enabled: <%= bCookies %>
</body>
</html>
cookie_detect.asp
<%@ Language="VBScript" %>
<%
Option Explicit
' We need buffering to be able to redirect.
Response.Buffer = True
' Retreive our own script name for the cookie test.
Dim strThisScriptName
strThisScriptName = Request.ServerVariables("URL")
' Declare a variable to pass the referring page path
' from the set to the read and then to redirect to.
Dim strFrom
' Check if we've already set a cookie to check.
If Request.QueryString("action") <> "checkcookie" Then
' We haven't set the test cookie yet.
' Get the info from the sending script about
' where to send the user when we're done. If
' we don't find anything we try and get it
' ourselves or if that fails just send them to
' the root of the site so they end up somewhere.
strFrom = Request.QueryString("from")
If strFrom = "" Then
strFrom = Request.ServerVariables("HTTP_REFERER")
End IfIf strFrom = "" Then
strFrom = "/"
End If
' Set a test cookie with a value and an expiration date.
Response.Cookies("cookie_test") = "true"
Response.Cookies("cookie_test").Expires = Date + 1
' This is useful if you need to remove the test
' cookie while you are testing.
'Response.Cookies("cookie_test").Expires = Date - 2
' Send the browser to the read back phase of the test.
' Notice the action attribute we check for above.
' We also continue to pass the from attribute.
Response.Redirect strThisScriptName & "?from=" _
& Server.URLEncode(strFrom) & "&action=checkcookie"
Else
' Boolean indicating cookie enablement.
Dim bCookiesEnabled
' Read back our values during second request.
bCookiesEnabled = Request.Cookies("cookie_test")
bCookiesEnabled = (bCookiesEnabled = "true")
' Read in the referring script path.
strFrom = Request.QueryString("from")
' Append appropriate QS character
If InStr(1, strFrom, "?", 1) = 0 Then
strFrom = strFrom & "?"
Else
strFrom = strFrom & "&"
End If
' Send the browser back to the start with a QueryString
' variable named cookie set to either true of false.
Response.Redirect strFrom & "cookies=" & bCookiesEnabled
End If
%>
Problems
While these scripts are relatively easy to use, please realize that
any time you start doing a lot of redirects it will add to the load
on your server and slow your apparent response time. Please use these
files with a sense of caution and if you need to know if cookies are
enabled on a lot of pages, it really does make more sense to test
them once and then store this value somewhere so you don't have to
keep testing the browser.
You could also run into trouble with some caching solutions. If
the caching is not very smart, you could easily end up telling
users who have cookies enabled that they don't and vice versa.
In an attempt to keep them to the point, these scripts don't
address caching, but you might need to start setting headers
to stop caching of these pages if it becomes a problem for you.
Conclusion
I hope this has helped shed some light on the cookie detection
problems you might have encountered or at very least made for an
interesting read.
If you'd like to play with the files, I've included cookie_bad.asp,
cookie.asp, and cookie_detect.asp in this zip file.
Update: Single File Cookie Detection
I recently got an email from a reader who had this to say:
Hi John,
Not sure how old the article is but I had an idea to achieve the same goal
on the same page. Still requires a redirect, but because the code stops
executing after the Response.Redirect line, it should reduce server load.
The page name for the example below would be cookietest.asp
<%
If Request.Querystring("Check") = "" Then
Session("cookietest") = "True"
Response.Redirect("cookietest.asp?Check=True")
Else
If Session("cookietest") Then
<!-- Execute code if enabled -->
Else
<!-- Execute code if disabled -->
End If
End If
%>
Just a thought. Thanks for the page!
Scott
Scott is absolutely right... you could easily do this in one page.
I separated it into two to try and keep things easier to follow as
to which file was doing what. You might also notice that Scott's
script is 1/20th the length of mine. If you're curious as to why...
the majority of the difference in length comes from the comments,
filename independence, and querystring passthrough that the original
script includes which Scott's doesn't. These could easily be
incorporated into a one-page solution as well.
In terms of performance... Scott's script does alleviate a couple
of redirects. The original script does none of the processing in
the "host" page and therefore needs to "hand off" to the
processing script and then "hand" the result back to the
"host" page. This is where the additional redirects
are incurred. While no script will work for everyone right
"out of the box" (or in this case right "off the site"),
the approach which will work best for you depends on your situation.
If there's enough interest, I'll be happy to write a more "useable"
version. It shouldn't be all that difficult to combine aspects of
both scripts into a simple include file that could easily be added
to any asp page. Ideally it would do the processing on one page
like Scott's script, yet include the additional features of the original.