Designed for archives finding aids, Circulate is a free, open-source, XML-driven solution for automated user requests and usage reports.


Circulate is a super-simple, super-customizable request and reporting solution for archives finding aids. Circulate uses: your existing EAD files, XSLT, HTML, CSS, javascript, simpleCart.js, and one itty-bitty PHP script. That's it! No database required. Circulate is built with front-end Web development and XML technologies. Circulate is built for archivists.

Circulate is modular and extensible. You can choose which elements to use. You can add or customize stylesheets and reports. Or, you can invent something completely new. Circulate is proof-of-concept that it's easy to automate a request and reporting solution for archives, with just a little XSLT magic and basic front-end Web development.


Circulate allows users to "shop" your finding aids, and add items to a request list. The request list, alongside collected user information, is sent to the archivist, who can: schedule a research appointment, print call slips, track patron histories, run reports on collection usage, and more.

Simple finding aid   |   Another simple finding aid   |   More detailed finding aid   |   Print call slips (Just click print!)

Documentation & Downloads

The "in-a-box" download will be on GitHub soon. In the meantime, it basically works like this...

Download and use simpleCart.js.
This is what powers the "request" functionality.

<script type="text/javascript" src="simpleCart/simpleCart.js"></script>

Treat boxes/files/items/whatever like cart items when you write XSLTs for your EAD files.
Something like this:

<xsl:for-each select="ead/archdesc/dsc/c01/did">
    <p><div class="simpleCart_shelfItem">
        <div class="item_name">
        <xsl:value-of select="unittitle"/>, <xsl:value-of select="unitdate"/>
    <button href="javascript:;" class="item_add">Request</button>

Of course, you need to associate container information with your items. Here's something a little more fancy, adding XML mark-up:

<xsl:for-each select="ead/archdesc/dsc/c01/did">
<p><div class="simpleCart_shelfItem">
<div class="item_name">
<item><xsl:value-of select="unittitle"/>, <xsl:value-of select="unitdate"/></item>. 
    <collection><xsl:value-of select="//eadid"/></collection>. 
    <xsl:for-each select="container"> <xsl:value-of select="@type"/>: <xsl:value-of select="."/>. </xsl:for-each>
<button href="javascript:;" class="item_add" onclick="displaymessage()">Request</button>

Bonus: this XML mark-up will let us style the different elements for display, and also run reports on collection usage.
Two demo XSLTs: One, Two

When a patron clicks "request," the cart items are stored as cookies. (You can set the duration of storage in simpleCart.js.) This means that the request list is available across all your finding aids.

Display the cart, and allow patrons to remove and/or edit items.
Something like this:

<script type="text/javascript">
    simpleCart.cartHeaders = ["Name_noHeader", "Remove_noHeader" ];

<div class="simpleCart_items"></div>

Note bene: simpleCart.js is designed to handle currency transactions -- so it's a great tool to manage reproduction requests, too!

Collect patron data.
The demo lets users input their contact info through a form:

<p>E-mail address:<br/><input type="email" id="email"/></p>
<p>Name:<br/><input type="text" id="name"/></p>
<p>When would you like to visit?<br/><input type="date" id="visit"/></p>
<p><button onclick="javascript:eadcart()">Submit</button></p>

You could do some fancy identity management (user registration, single sign-on)... or not. E-mail addresses effectively serve as unique identifiers for folks. To protect patron privacy, you might find value in letting them use aliases and e-mail addresses for communication. Of course, this approach raises security questions. How you handle patron data should match the needs of your institution.

Send cart items and patron data somewhere.
The demo formats this information with XML mark-up, e-mails the request to the archives, and appends a requests.xml document.

Format and post data:

function eadcart() {
    simpleCart.each(function( item, x ){;
    var sendx = document.getElementById("sendcartx");
    sendx.value = resultx;
    intro="On ";
    result=intro.concat(visit,", ",name,", ",email,", would like to consult: ",eaditems);
    var message = document.getElementById("sendcartmessage");
    message.value = result;

<form action="sendcart.php" method="post"> <input type="hidden" name="sendcartx" id="sendcartx"></input> </form>
<form action="sendcart.php" method="post"> <input type="hidden" name="sendcartmessage" id="sendcartmessage"></input> </form>


    $to = '';
    $subject = 'Research Request';
    $sendcartmessage = $_POST['sendcartmessage'];
    $headers = 'From: Archives ' . "\r\n" .
           'Reply-To: Archives ' . "\r\n" .
           'X-Mailer: PHP/' . phpversion();

    mail($to, $subject, $sendcartmessage, $headers);

    $sendcartx   = $_POST['sendcartx'];

    echo file_put_contents("requests.xml", $sendcartx, FILE_APPEND);
    echo " Request submitted!";

Use XML-encoded request information to create reports.
Now, all it takes is a bit more XSLT magic!
For instance, the demo XSLT to print call slips:

<xsl:for-each select="requests/request/item">
<h2><xsl:value-of select="."/></h2>
<p>Requestor: <xsl:value-of select="../name"/><br/></p>
<p>E-mail address: <xsl:value-of select="../email"/><br/></p>
<p>Wanted on: <xsl:value-of select="../visit"/><br/></p>
<p style="page-break-after:always;"></p>

Want more info?

This project was described in Archival Practice vol. 1, no. 1 (2014).

For more projects and proven concepts: Hack your Library