diff --git a/Network/Shpider.hs b/Network/Shpider.hs
--- a/Network/Shpider.hs
+++ b/Network/Shpider.hs
@@ -94,7 +94,8 @@
 curlDownload url = do
    shpider <- get
    res <- liftIO $ curlGetString url $ curlOpts shpider
-   mkRes url res
+   r <- mkRes url res
+   return r
 
 mkRes url ( curlCode , html ) = do
    p <- if curlCode == CurlOK
diff --git a/Network/Shpider/Curl/Curl.hs b/Network/Shpider/Curl/Curl.hs
--- a/Network/Shpider/Curl/Curl.hs
+++ b/Network/Shpider/Curl/Curl.hs
@@ -175,7 +175,7 @@
 -- | 'curlGet' perform a basic GET, dumping the output on stdout.
 -- The list of options are set prior performing the GET request.
 curlGet :: URLString -> [CurlOption] -> IO ()
-curlGet url opts = initialize >>= \ h -> do
+curlGet url opts = initialize_no_cleanup >>= \ h -> do
   setopt h (CurlFailOnError True)
   setopt h (CurlURL url)
    -- Note: later options may (and should, probably) override these defaults.
@@ -201,7 +201,7 @@
 curlGetString :: URLString
               -> [CurlOption]
               -> IO (CurlCode, String)
-curlGetString url opts = initialize >>= \ h -> do
+curlGetString url opts = initialize_no_cleanup >>= \ h -> do
   ref <- newIORef []
    -- Note: later options may (and should, probably) override these defaults.
   setopt h (CurlFailOnError True)
@@ -218,7 +218,7 @@
                => URLString
                -> [CurlOption]
                -> IO (CurlCode, ty)
-curlGetString_ url opts = initialize >>= \ h -> do
+curlGetString_ url opts = initialize_no_cleanup >>= \ h -> do
   (finalBody, gatherBody) <- newIncoming
   setopt h (CurlFailOnError True)
   setDefaultSSLOpts h url
@@ -254,7 +254,7 @@
                  -> [CurlOption]
                  -> IO (CurlResponse_ hdr ty)
 curlGetResponse_ url opts = do
-  h <- initialize
+  h <- initialize_no_cleanup
    -- Note: later options may (and should, probably) override these defaults.
   setopt  h (CurlFailOnError True)
   setDefaultSSLOpts h url
@@ -262,7 +262,7 @@
   mapM_ (setopt h) opts
   -- note that users cannot over-write the body and header handler
   -- which makes sense because otherwise we will return a bogus reposnse.
-  perform_with_response_ h 
+  manual_perform_with_response_ h 
 
 {-# DEPRECATED curlGetResponse "Switch to using curlGetResponse_" #-}
 curlGetResponse :: URLString
@@ -287,6 +287,42 @@
 -- 'CurlWriteFunction' and 'CurlHeaderFunction' options.
 -- The returned payload is overloaded over the representation of
 -- both headers and body via the 'CurlResponse_' type.
+-- Deterministic cleanup
+manual_perform_with_response_ :: (CurlHeader headerTy, CurlBuffer bodyTy)
+                       => Curl
+		       -> IO (CurlResponse_ headerTy bodyTy)
+manual_perform_with_response_ h = do
+   (finalHeader, gatherHeader) <- newIncomingHeader
+   (finalBody,   gatherBody)   <- newIncoming
+
+     -- Instead of allocating a separate handler for each
+     -- request we could just set this options one and forall
+     -- and just clear the IORefs.
+
+   setopt  h (CurlWriteFunction (gatherOutput_ gatherBody))
+   setopt  h (CurlHeaderFunction (gatherOutput_ gatherHeader))
+   rc      <- perform h
+   manual_cleanup h
+   rspCode <- getResponseCode h
+   (st,hs) <- finalHeader
+   bs      <- finalBody
+   return CurlResponse
+       { respCurlCode   = rc
+       , respStatus     = rspCode
+       , respStatusLine = st
+       , respHeaders    = hs
+       , respBody       = bs 
+       -- note: we're holding onto the handle here..
+       -- note: with this interface this is not neccessary.
+       , respGetInfo    = getInfo h
+       }
+
+-- | Perform the actions already specified on the handle.
+-- Collects useful information about the returned message.
+-- Note that this function sets the
+-- 'CurlWriteFunction' and 'CurlHeaderFunction' options.
+-- The returned payload is overloaded over the representation of
+-- both headers and body via the 'CurlResponse_' type.
 perform_with_response_ :: (CurlHeader headerTy, CurlBuffer bodyTy)
                        => Curl
 		       -> IO (CurlResponse_ headerTy bodyTy)
@@ -301,7 +337,6 @@
    setopt  h (CurlWriteFunction (gatherOutput_ gatherBody))
    setopt  h (CurlHeaderFunction (gatherOutput_ gatherHeader))
    rc      <- perform h
-   manual_cleanup h
    rspCode <- getResponseCode h
    (st,hs) <- finalHeader
    bs      <- finalBody
@@ -316,6 +351,7 @@
        , respGetInfo    = getInfo h
        }
 
+
 -- | Performs a curl request using an exisitng curl handle.
 -- The provided URL will overwride any 'CurlURL' options that
 -- are provided in the list of options.  See also: 'perform_with_response'.
@@ -339,7 +375,7 @@
 -- | Get the headers associated with a particular URL.
 -- Returns the status line and the key-value pairs for the headers.
 curlHead :: URLString -> [CurlOption] -> IO (String,[(String,String)])
-curlHead url opts = initialize >>= \ h -> 
+curlHead url opts = initialize_no_cleanup >>= \ h -> 
   do ref <- newIORef []
 --     setopt h (CurlVerbose True)
      setopt h (CurlURL url)
@@ -357,7 +393,7 @@
           => URLString
 	  -> [CurlOption]
 	  -> IO (String, headers)
-curlHead_ url opts = initialize >>= \ h -> do
+curlHead_ url opts = initialize_no_cleanup >>= \ h -> do
   (finalHeader, gatherHeader) <- newIncomingHeader
 --  setopt h (CurlVerbose True)
   setopt h (CurlURL url)
@@ -396,7 +432,7 @@
 
 -- | 'curlMultiPost' perform a multi-part POST submission.
 curlMultiPost :: URLString -> [CurlOption] -> [HttpPost] -> IO ()
-curlMultiPost s os ps = initialize >>= \ h -> do
+curlMultiPost s os ps = initialize_no_cleanup >>= \ h -> do
   setopt h (CurlVerbose True)
   setopt h (CurlURL s)
   setopt h (CurlHttpPost ps)
@@ -409,7 +445,7 @@
 -- | 'curlPost' performs. a common POST operation, namely that
 -- of submitting a sequence of name=value pairs.
 curlPost :: URLString -> [String] -> IO ()
-curlPost s ps = initialize >>= \ h -> do
+curlPost s ps = initialize_no_cleanup >>= \ h -> do
   setopt h (CurlVerbose True)
   setopt h (CurlPostFields ps)
   setopt h (CurlCookieJar "cookies")
diff --git a/Network/Shpider/Curl/Debug.hs b/Network/Shpider/Curl/Debug.hs
--- a/Network/Shpider/Curl/Debug.hs
+++ b/Network/Shpider/Curl/Debug.hs
@@ -15,7 +15,7 @@
 import System.IO
 
 debugging :: Bool
-debugging = False
+debugging = False 
 
 debug :: String -> IO ()
 debug msg
diff --git a/Network/Shpider/Curl/Easy.hs b/Network/Shpider/Curl/Easy.hs
--- a/Network/Shpider/Curl/Easy.hs
+++ b/Network/Shpider/Curl/Easy.hs
@@ -18,6 +18,7 @@
 --------------------------------------------------------------------
 module Network.Shpider.Curl.Easy
         ( initialize    -- :: IO Curl
+        , initialize_no_cleanup -- :: IO Curl
         , perform       -- :: Curl -> IO CurlCode
         , setopt        -- :: Curl -> CurlOption -> IO CurlCode
         , duphandle     -- :: Curl -> IO Curl
@@ -50,6 +51,13 @@
 initialize = do
   h <- easy_initialize
   mkCurl h 
+
+-- | Initialize a curl instance
+-- | No automatic garbage colelction
+initialize_no_cleanup :: IO Curl
+initialize_no_cleanup = do
+   h <- easy_initialize
+   mkCurl_no_cleanup h
 
 -- XXX: Is running cleanup here OK?
 reset :: Curl -> IO ()
diff --git a/Network/Shpider/Curl/Types.hs b/Network/Shpider/Curl/Types.hs
--- a/Network/Shpider/Curl/Types.hs
+++ b/Network/Shpider/Curl/Types.hs
@@ -19,7 +19,7 @@
   ( CurlH, URLString, Port, Long, LLong, Slist_ 
   , Curl, curlPrim, mkCurl, mkCurlWithCleanup
   , OptionMap, shareCleanup, runCleanup, updateCleanup
-  , manual_cleanup
+  , manual_cleanup , mkCurl_no_cleanup
   ) where
 
 import Network.Shpider.Curl.Debug
@@ -59,8 +59,20 @@
 
 
 -- | Allocates a Haskell handle from a C handle.
+-- | No garbage collection so cookies are written deterministically
+mkCurl_no_cleanup :: CurlH -> IO Curl
+mkCurl_no_cleanup h = do
+  debug "ALLOC: CURL"
+  fh  <- newForeignPtr_ h 
+  v1  <- newMVar fh
+  v2  <- newIORef om_empty 
+  let new_h = Curl { curlH = v1, curlCleanup = v2 }
+  return new_h
+
+-- | Allocates a Haskell handle from a C handle.
 mkCurl :: CurlH -> IO Curl
-mkCurl h = mkCurlWithCleanup h om_empty
+mkCurl h = 
+    mkCurlWithCleanup h om_empty
 
 -- | Allocates a Haskell handle from a C handle.
 mkCurlWithCleanup :: CurlH -> OptionMap -> IO Curl
@@ -70,9 +82,11 @@
   v1  <- newMVar fh
   v2  <- newIORef clean
   let new_h = Curl { curlH = v1, curlCleanup = v2 }
-  
+ 
   fin <- mkIOfin $ do debug "FREE: CURL"
                       runCleanup v2
+                      withForeignPtr fh easy_cleanup
+                      
   addForeignPtrFinalizer fin fh
 
   return new_h
@@ -80,9 +94,9 @@
  -- Manually cleanup a curl instance, writing cookies etc.
 manual_cleanup curl = do 
    fh <- readMVar $ curlH curl
+   debug "FREE: CURL"
+   runCleanup $ curlCleanup curl
    withForeignPtr fh easy_cleanup
-   finalizeForeignPtr fh
- 
 
 -- Admin code for cleaning up marshalled data.
 -- Note that these functions assume that they are running atomically,
diff --git a/shpider.cabal b/shpider.cabal
--- a/shpider.cabal
+++ b/shpider.cabal
@@ -1,5 +1,5 @@
 Name:               shpider 
-Version:            0.0.5
+Version:            0.0.6
 Synopsis:           Web automation library in Haskell.
 Description:
     Shpider is a web automation library for Haskell.   It allows you to quickly write crawlers, and for simple cases ( like following links ) even without reading the page source.
@@ -17,7 +17,7 @@
     >            "occupation" =: "unemployed Haskell programmer"
     >            "location" =: "mother's house"
     .
-    Shpider contains a patched version of the curl package, to fix cookie handling.  The curl licence is therefore distributed with this package.
+    Shpider contains a patched version of the curl package ( the original package's garbage-collection caused non-deterministic behaviour ).  The curl licence is therefore distributed with this package.
 Category:           Web
 License:            BSD3
 License-file:       LICENSE
@@ -29,7 +29,7 @@
 Extra-source-files: LICENSE.CURL, configure, configure.ac, curl.buildinfo.in
 
 Library
-   Build-depends:   base , regex-posix , tagsoup-parsec , url==2 , containers , tagsoup , mtl , bytestring
+   Build-depends:   base < 5, regex-posix , tagsoup-parsec , url>=2 , containers , tagsoup , mtl , bytestring
    Exposed-modules: Network.Shpider.URL
                     Network.Shpider.Code
                     Network.Shpider.State
