An Introduction to...
Server Side Includes (SSI)

by George Dillon

What are SSIs?
SSI environment variables
SSI directives
What is XSSI?
SSI vs Frames
Examples of the application of SSI & XSSI

See also SSI, XSSI & CGI environment variables

What are SSIs?

As the name suggests, SSIs, or Server Side Includes, are a way to tell the server to insert something into a web page before it is sent to the viewer. What is inserted may be the content of a plain text file or it may be the output generated by another program running on the server such as the processing of a form return using a PERL script.

SSIs do not work with all servers, and even if the server is SSI-capable, it must be configured to allow SSIs to run. The most popular web server is currently Apache which, as a development of the NCSA WWW server, can be seen as the server for which SSIs (and later xSSIs) were created. For servers which do not support SSIs, is a Perl program which emulates SSIs.

If your server is already configured for them, SSIs are incredibly simple to use. For example, to include the same code for a navigation bar on every page in your site, save the required code in a plain text file - just the code, no <html>, <head> or <body> tags (unless they are part of the code to be included) - and call it anything you like e.g. 'navbar.shtml'. It can be a good idea to keep all your include files in one directory, so this example will assume 'navbar.shtml' is in a subdirectory of your site root, named 'ssi'. To include the contents of 'navbar.shtml' in a page, simply put this command at the required spot:

   <!--#include virtual="/ssi/navbar.shtml" -->

then save the page using the requisite extension for your server's configuration, which will most likely be '.shtml'. SSI-enabled servers recognise which pages which require parsing by their filename extension.

Includes may be nested (i.e. an include may call another include) up to 16 levels deep - provided every file which needs to be parsed has the correct extension.

SSIs can be a powerful tool for site management, and are especially useful for the maintenance of sites which require frequent changes. They are also particularly valuable when you are weaning yourself off using frames.

  Back to top    Back to top

SSI environment variables

As well as including external files and the results from external scripts, all the environment variables that are available to CGI programs can be used with SSIs and there are six environment variables that are exclusive to SSI. These are: the current date and time in GMT (Greenwich Mean Time) or in the local time zone; the current filename; the path (relative to the document root) to the file; the last modification date and time for current file and the query string (the part of the address after a '?'). Here's a complete list of SSI & XSSI environment variables.

  Back to top    Back to top

SSI directives

The include directive, which has already made an appearance above, has two different arguments

   <!--#include file="navbar.shtml" -->
   <!--#include virtual="/ssi/navbar.shtml" -->

in the first example the path to the included file is relative to the directory of the current page. In this example navbar.shtml will be in the same directory as the page calling it. But note that this cannot be absolute (i.e. a full URL) - so "" will not work. Nor can it be recursive (i.e. pointing to a higher level directory) - so "../navbar.shtml" won't work either. To avoid making mistakes it is safer to get in the habit of always using the virtual path (i.e. the path from the site's root), which begins with a slash.

The echo directive returns the value of an environment variable. For example this code:

   <b>[Updated - <!--#echo var="LAST_MODIFIED" -->]<b>

could be used to make this appear on a page:

[Updated - Friday, 31-Mar-2006 05:26:46 CST ]

The fsize and flastmod directives return the file size and last modification date of other files on the server. These two directives and echo are illustrated in more detail in the list of environment variables.

The config directive allows you to select the way error messages, file size information, and date and time are displayed. For example if an included file doesn't exist, the server may display:

   [an error occurred while processing this directive]

By using this config command:

   <!--#config errmsg="Error message" -->

You can change this error message to (for example):

Include file not found.
Please alert

The many different formats which can be applied to times and dates using config are also on my list of environment variables

The exec directive executes external programs, accepts two valid arguments - cmd and cgi - and is beyond the scope of this article. [It is also not to be used if XSSI is available... see below.]

  Back to top    Back to top

What is XSSI?

XSSIs (eXtended Server-Side Includes) were introduced with the popular Apache WWW server (version 1.2 and above), and add two particularly powerful features - the ability to define new variables and to attach conditions to the execution of an SSI directive. XSSIs can accomplish many of the tasks which previously required slow and less reliable client-side JavaScript, such as the inclusion of browser/platform-specific stylesheets.

XSSI Directives

The set directive is used to create a new variable and give it a value. For example:

   <!--#set var="VAR_name" value="String or a #" -->

The if, elif, else, endif (or 'flow-control') directives work like conditional statements in many other programming languages and are used to mark code which is to be included in a page if the conditions are met. These may embrace other SSIs, and are particularly powerful when used in conjunction with set variables.

The following example shows (in part) how set and flow-control directives can be used for loading a browser/platform specific stylesheet. (The convention of naming variables "VAR_name" is not necessary):

   <!--#set var="VAR_css" value="msie" -->
   <!--#if expr="($HTTP_USER_AGENT=/Mozilla/)
              && ($HTTP_USER_AGENT !=/compatible/)" -->
   <!--#set var="VAR_css" value="nav" -->
   <!--#elif expr="($HTTP_USER_AGENT=/Opera/)" -->
   <!--#set var="VAR_css" value="opera" -->
   <!--#endif -->

   <LINK REL="stylesheet" type="text/css"
    href="/css/<!--#echo var='VAR_css' -->.css">

   <!--#if expr="($HTTP_USER_AGENT=/Mac/)" -->
   <LINK REL="stylesheet" type="text/css"
   <!--#endif -->

This (limited) example works by assuming what's required is a stylesheet tailored for Internet Explorer, but loads an alternative if it detects the visitor to be using Netscape or Opera and a supplementary stylesheet for the MacIntosh platform.

Below there are examples of using the flow-control directives to create self-updating pages and a printable version of the same page.

The virtual include directive now incorporates (and replaces) exec, and can also utilise a query string:

   <!--#include virtual="/cgi-bin/bar/foo.cgi?query_string" -->

  Back to top    Back to top

SSI vs Frames

If you currently use frames but are trying to give them up, SSI will be like your nicotine substitute - except that this substitute is better than the real thing. (If you're not trying to give them up, then you should be! Reasons? Have a look at Adrian Roselli's article at Some Caveats with Using Frames ).

Pages with SSIs are more search engine friendly than pages in framesets. If you're using frames, some search engines (specifically spiders coming in at a frameset index page) won't find and list pages within your site, and even if framed pages do get listed (by your submitting the URLs of every page) they won't be loaded within the correct frameset when a visitor clicks on the listed link. There is a JavaScript trick you can use to get pages to reload themselves into the intended frameset, but it's a little bit cumbersome and has to be planned for from the start. (Have a look at Martin Webb's article at "Re-directing access within Frames", or better still, give up using frames and spend your time more profitably with SSIs.) With whole pages constructed from SSIs you have no such problems, as every page is a unique and complete resource as was intended when the URL system was conceived. Search engines are just as unaware of your use of SSIs as are your visitor's browsers.

Pages with SSIs are more screen friendly than pages in framesets. Using frames can seriously limit the possibilities of creating sites which are viewable at a variety of resolutions. Not so with single pages laid out with fluid tables, constructed using SSIs.

Pages with SSIs are easier to print and bookmark than pages in framesets. See Some Caveats with Using Frames for more details about the problems of printing/bookmarking framed pages.

In some circumstances pages with SSIs can load faster than pages in framesets. With SSIs of course there's a *slight* performance hit while the server builds the page before it is sent... but even on a slow machine this will result in no more than a few milliseconds delay (unless the include executes a particularly complex CGI script). And although using frames may mean that some bits of code don't have to be repeated in every page so file sizes may be that bit smaller, this can be more than offset by the need to include extra JavaScript controls in framed pages adding time to both their downloading and also their rendering.

You might think that frames saves some downloading, as with frames not every element of a page needs to be refreshed each time a link is followed. However, since images which have been loaded before will be in the browser cache anyway and on a moderately up-to-date computer a page-full of cached images will load almost instantaneously (even on a 486 with 1 Mb video Ram the difference in rendering time between keeping images visible in a frame or reloading them from cache in a new page will barely be noticeable - and users of such slow machines will have a greater tolerance to waiting anyway), the saving is really only achieved in the repetition of raw html code, and unless you have a prticularly complex drop-down menu navigational system this is unlikely to add much more than 5kb to each page (or less than a second download time on a 56k modem).

  Back to top    Back to top

Examples of the application of SSI & XSSI

SSIs are mainly used by developers to facilitate the management of sites which require frequent updates. For example, when SSIs are used for writing common navigational elements, new pages can be added to the relevant menu on many pages simply by adding the link to a single include file. Some designers use SSI (and XSSI) for everything except each page's unique content, including even the doctype declaration.

Different strokes for different folks. The ability of SSI and xSSI to conditionally include code according to the requesting host, address, referrer and user-agent can be applied to deliver targeted content in many ways. As well as the browser/platform specific stylesheets example above, there are many situations where you might want to select different content for the same page: different keywords for different search engines, different languages for different countries, different links for internal/external visitors (effectively 'hiding' parts of your site from all but your own employees), different advertising-banners for different incoming links, different code (particularly form tags) for live on-line pages or for off-line testing (without having to remember to change the code before uploading) etc.

Self-updating pages. In the theatre section of this site I have a page with forthcoming tour dates, which uses XSSI to exclude information about dates which are in the past. Here's a sample of the code (with thanks to Oliver Lineham who helped me get this working):

   <!--#config timefmt="%Y"
    --><!--#set var="year" value="$DATE_GMT" -->
   <!--#config timefmt="%m"
    --><!--#set var="month" value="$DATE_GMT" -->
   <!--#config timefmt="%d"
    --><!--#set var="day" value="$DATE_GMT" -->
      <!--#set var="gigy" value="2001" -->
      <!--#set var="gigm" value="02" -->
   <!--#if expr="($year<$gigy)
    || ($year=$gigy && $month<$gigm)
    || ($year=$gigy && $month=$gigm && $day<02)"-->
      <td>Tues - Thurs</td>
      <td>30th Jan - 1st Feb</td>
      <td class="h4">BRIGHTON</td>
      <td>The Komedia</td>
      <td>01273 647100</td>
      <!--#endif -->
   <!--#set var="gigm" value="04" -->
   <!--#if expr="($year<$gigy)
    || ($year=$gigy && $month<$gigm)
    || ($year=$gigy && $month=$gigm && $day<28)"-->
      <td>Wed - Fri</td>
      <td>25 - 27 Apr</td>
      <td class="h4">MANCHESTER</td>
      <td>The Green Room</td>
      <td>0161 950 5900</td>
      <!--#endif -->

Printable version. In the masthead and footer of this site there's a link to a printable version of the current page, like this:

[ Pop-up a printable version of this page ]

The code which writes this link checks for the few exceptions where a printable version is really not needed (usually pages including forms), and goes a bit like:

<!--#set var="VAR_printable" value="no"
 --><!--#if expr="($QUERY_STRING=/printable/)"
 --><!--#set var="VAR_printable" value="yes"
 --><!--#if expr="$VAR_forminpage=/yes/"
 --><!--#set var="VAR_printable" value="blank"
 --><!--#if expr="($DOCUMENT_NAME=/fluid_tables.shtml/)"
 --><!--#set var="VAR_printable" value="blank"
 --><!--#if expr="($VAR_printable=/yes/)"
 --><!--#if expr="($VAR_printable=/no/)"
 --><tr><td colspan="2" align="center"><a
 class="mastprint" target="<!--#echo var="DOCUMENT_NAME"
 -->printable" href="http://<!--#echo var="HTTP_HOST"
 --><!--#echo var="DOCUMENT_URI"
 title="Opens a new window with a version of this page
 containing only the central article in black text
 on a white background."
 width="16" height="14"
 align="absmiddle" border="0"
 alt="" name="printable">
 [ Pop-up a printable version of this page ]</a></td>
 </tr><!--#endif -->


The masthead and footer, the menus which appear in the left and right hand columns (indeed all the code for the layout tables which control the screen layout) are all cut from the print version by wrapping them in:

   <!--#if expr="($QUERY_STRING=/printable/)" --><!--#else -->


   <!--#endif -->

and something very similar is used to change the stylesheet.

Creating a Back Button No more tricky JavaScript, here's your SSI code for a back button which will work on any browser:

   <a href="<!--#echo var="HTTP_REFERER" -->">BACK</a>

Writing the document title to the page. One trick I use SSIs for is to write the page title (as defined in the header) in the body of the page. To do this, I set the page title as a variable which I can then recall whener I wish (not forgetting to insert it within the <title> tags) using:

   <!--#set var="VAR_doctitle" value="The title of this page" -->
   <title><!--#echo var="VAR_doctitle" --></title>

the footer code for my site can then look like this:

   <!--#config timefmt="%d %B %Y" -->
   <!--#echo var="VAR_doctitle" -->
  [Updated - <!--#echo var="LAST_MODIFIED" -->]

which produces:

An introduction to... Server Side Includes (SSIs) [Updated - 31 March 2006 ]

Copying SSI variables to JavaScript variables. The masthead of this site includes a motif in the top left corner which indicates the section of the current page. SSI is used to read the document URL, check which section subdirectory the page is in and load the appropriate motif image. However, since this image is also a rollover I needed a way to pass a variable from SSI to JavaScript (to avoid having to duplicate the section detection in JavaScript). This was my solution:

   <!--#set var="VAR_motif_img" value="nomotif.gif"
   --><!--#if expr="($DOCUMENT_URI=//theatre/)"
   --><!--#set var="VAR_motif_img" value="theatre.gif"
   --><!--#elif expr="($DOCUMENT_URI=//kendo/)"
   --><!--#set var="VAR_motif_img" value="kendo.gif"
   --><!--#elif expr="($DOCUMENT_URI=//web/)"
   --><!--#set var="VAR_motif_img" value="web.gif"
   --><SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
   var motif='<!--#echo var="VAR_motif_img" -->';

then the rollover script uses:

   motifoff=new Image(100,80); motifoff.src='/images/motifs/'+motif;

Note that since the SSIs are processed before the page reaches the browser it is possible to pass any variable from the SSI environment to client-side JavaScript but you cannot pass variables the other way (unless you send a new request to the server including them in the string).

  Back to top    Back to top


Much of this article (and the accompanying list of SSI environment variables ) is based on Server-Side Includes and its Extensions by Pankaj Kamthan @ For me is the most useful web related learning site on the Internet, not least because it allows you to download 100s of in-depth articles and 1,000s of FAQs in (a variety of) zipped format(s) for off-line study. Another clear and simple explanation of SSIs can be found at SSI Tutorial - Server Side Includes @ UseForesight

The Webmonkey XSSI package extends Dreamweaver 2.0, to provide a useful graphical interface for inserting and modifying XSSI commands. However, it disables Dreamweaver's built-in SSI translation (replacing it with its own XSSI translation) and this can cause some pages to display incorrectly. Fortunately the documentation tells you how to reverse this and (after installation) it can be found at /Dreamweaver 2/Configuration/WM_common/xssi_help.html. Here's what it says:

You will need to rename two files in your Dreamweaver 2/Configuration/
directory. First, in the Translators subdirectory, there should be a file
named "Server-Side Includes.htm.old". Second, in the JSExtensions
subdirectory, there should be a file named "SSITranslator.dll.old" Simply
remove the ".old" part of the filenames and restart Dreamweaver.

To view pages using SSIs in your browser off-line you will need to run a server. I found the documentation to Microsoft's Personal Web Server incomprehensible, and the first local server I had any success with was Xitami a mere 764 kb download from Xitami runs on all UNIX platforms, OS/2, OpenVMS, Windows 3.x, Windows 95, and Windows NT and since it comes fully configured, you don't need to change a single option to run it... Soon afterwards, however, I migrated to Apache which is undoubtedly the one to recommend, and to start/stop it from the system tray I use Apache manager for Windows.

{Printed from on Wed, 20 Sep, 2017 @ 22:09:44}