diff --git a/hspec-wai.cabal b/hspec-wai.cabal
--- a/hspec-wai.cabal
+++ b/hspec-wai.cabal
@@ -1,13 +1,13 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.31.0.
+-- This file has been generated from package.yaml by hpack version 0.31.2.
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 8cd8444fb81ce20f9ac1bc6ef05bcaf0c7bfec1e15deefc045dbe71f1830a92b
+-- hash: 811a23841d28e2d55f76be822fe6c98b2a677f409a68b8e8c997c594712c834c
 
 name:             hspec-wai
-version:          0.9.2
+version:          0.10.0
 homepage:         https://github.com/hspec/hspec-wai#readme
 bug-reports:      https://github.com/hspec/hspec-wai/issues
 license:          MIT
diff --git a/src/Test/Hspec/Wai.hs b/src/Test/Hspec/Wai.hs
--- a/src/Test/Hspec/Wai.hs
+++ b/src/Test/Hspec/Wai.hs
@@ -32,6 +32,8 @@
 -- * Helpers and re-exports
 , liftIO
 , with
+, withState
+, getState
 , pending
 , pendingWith
 ) where
@@ -54,16 +56,20 @@
 import           Test.Hspec.Wai.Internal
 import           Test.Hspec.Wai.Matcher
 
--- | An alias for `before`.
-with :: IO a -> SpecWith a -> Spec
-with = before
+import           Network.Wai (Application)
 
+with :: IO Application -> SpecWith ((), Application) -> Spec
+with action = before ((,) () <$> action)
+
+withState :: IO (st, Application) -> SpecWith (st, Application) -> Spec
+withState = before
+
 -- | A lifted version of `Core.pending`.
-pending :: WaiSession ()
+pending :: WaiSession st ()
 pending = liftIO Core.pending
 
 -- | A lifted version of `Core.pendingWith`.
-pendingWith :: String -> WaiSession ()
+pendingWith :: String -> WaiSession st ()
 pendingWith = liftIO . Core.pendingWith
 
 -- | Set the expectation that a response matches a specified `ResponseMatcher`.
@@ -100,38 +106,38 @@
 --
 -- > get "/" `shouldRespondWith` "foo" {matchHeaders = ["Content-Type" <:> "text/plain"]}
 -- > -- matches if body is "foo", status is 200 and there is a header field "Content-Type: text/plain"
-shouldRespondWith :: HasCallStack => WaiSession SResponse -> ResponseMatcher -> WaiExpectation
+shouldRespondWith :: HasCallStack => WaiSession st SResponse -> ResponseMatcher -> WaiExpectation st
 shouldRespondWith action matcher = do
   r <- action
   forM_ (match r matcher) (liftIO . expectationFailure)
 
 -- | Perform a @GET@ request to the application under test.
-get :: ByteString -> WaiSession SResponse
+get :: ByteString -> WaiSession st SResponse
 get path = request methodGet path [] ""
 
 -- | Perform a @POST@ request to the application under test.
-post :: ByteString -> LB.ByteString -> WaiSession SResponse
+post :: ByteString -> LB.ByteString -> WaiSession st SResponse
 post path = request methodPost path []
 
 -- | Perform a @PUT@ request to the application under test.
-put :: ByteString -> LB.ByteString -> WaiSession SResponse
+put :: ByteString -> LB.ByteString -> WaiSession st SResponse
 put path = request methodPut path []
 
 -- | Perform a @PATCH@ request to the application under test.
-patch :: ByteString -> LB.ByteString -> WaiSession SResponse
+patch :: ByteString -> LB.ByteString -> WaiSession st SResponse
 patch path = request methodPatch path []
 
 -- | Perform an @OPTIONS@ request to the application under test.
-options :: ByteString -> WaiSession SResponse
+options :: ByteString -> WaiSession st SResponse
 options path = request methodOptions path [] ""
 
 -- | Perform a @DELETE@ request to the application under test.
-delete :: ByteString -> WaiSession SResponse
+delete :: ByteString -> WaiSession st SResponse
 delete path = request methodDelete path [] ""
 
 -- | Perform a request to the application under test, with specified HTTP
 -- method, request path, headers and body.
-request :: Method -> ByteString -> [Header] -> LB.ByteString -> WaiSession SResponse
+request :: Method -> ByteString -> [Header] -> LB.ByteString -> WaiSession st SResponse
 request method path headers body = getApp >>= liftIO . runSession (Wai.srequest $ SRequest req body)
   where
     req = setPath defaultRequest {requestMethod = method, requestHeaders = headers} path
@@ -142,5 +148,5 @@
 -- @application/x-www-form-urlencoded@ and used as request body.
 --
 -- In addition the @Content-Type@ is set to @application/x-www-form-urlencoded@.
-postHtmlForm :: ByteString -> [(String, String)] -> WaiSession SResponse
+postHtmlForm :: ByteString -> [(String, String)] -> WaiSession st SResponse
 postHtmlForm path = request methodPost path [(hContentType, "application/x-www-form-urlencoded")] . formUrlEncodeQuery
diff --git a/src/Test/Hspec/Wai/Internal.hs b/src/Test/Hspec/Wai/Internal.hs
--- a/src/Test/Hspec/Wai/Internal.hs
+++ b/src/Test/Hspec/Wai/Internal.hs
@@ -7,8 +7,10 @@
   WaiExpectation
 , WaiSession(..)
 , runWaiSession
+, runWithState
 , withApplication
 , getApp
+, getState
 , formatHeader
 ) where
 
@@ -16,6 +18,7 @@
 import           Prelude.Compat
 
 import           Control.Monad.IO.Class
+import           Control.Monad.Trans.Class
 import           Control.Monad.Trans.Reader
 import           Network.Wai (Application)
 import           Network.Wai.Test hiding (request)
@@ -29,26 +32,32 @@
 -- | An expectation in the `WaiSession` monad.  Failing expectations are
 -- communicated through exceptions (similar to `Test.Hspec.Expectations.Expectation` and
 -- `Test.HUnit.Base.Assertion`).
-type WaiExpectation = WaiSession ()
+type WaiExpectation st = WaiSession st ()
 
 -- | A <http://www.yesodweb.com/book/web-application-interface WAI> test
 -- session that carries the `Application` under test and some client state.
-newtype WaiSession a = WaiSession {unWaiSession :: Session a}
+newtype WaiSession st a = WaiSession {unWaiSession :: ReaderT st Session a}
   deriving (Functor, Applicative, Monad, MonadIO
 #if MIN_VERSION_base(4,9,0)
   , MonadFail
 #endif
   )
 
-runWaiSession :: WaiSession a -> Application -> IO a
-runWaiSession = runSession . unWaiSession
+runWaiSession :: WaiSession () a -> Application -> IO a
+runWaiSession action app = runWithState action ((), app)
 
-withApplication :: Application -> WaiSession a -> IO a
+runWithState :: WaiSession st a -> (st, Application) -> IO a
+runWithState action (st, app) = runSession (flip runReaderT st $ unWaiSession action) app
+
+withApplication :: Application -> WaiSession () a -> IO a
 withApplication = flip runWaiSession
 
-instance Example WaiExpectation where
-  type Arg WaiExpectation = Application
-  evaluateExample e p action = evaluateExample (action $ runWaiSession e) p ($ ())
+instance Example (WaiExpectation st) where
+  type Arg (WaiExpectation st) = (st, Application)
+  evaluateExample e p action = evaluateExample (action $ runWithState e) p ($ ())
 
-getApp :: WaiSession Application
-getApp = WaiSession ask
+getApp :: WaiSession st Application
+getApp = WaiSession (lift ask)
+
+getState :: WaiSession st st
+getState = WaiSession ask
diff --git a/src/Test/Hspec/Wai/QuickCheck.hs b/src/Test/Hspec/Wai/QuickCheck.hs
--- a/src/Test/Hspec/Wai/QuickCheck.hs
+++ b/src/Test/Hspec/Wai/QuickCheck.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies #-}
 module Test.Hspec.Wai.QuickCheck (
   property
 , (==>)
@@ -19,26 +20,30 @@
 
 import           Test.Hspec.Wai.Internal
 
-property :: Testable a => a -> Application -> Property
+property :: Testable a => a -> (State a, Application) -> Property
 property = unWaiProperty . toProperty
 
-data WaiProperty = WaiProperty {unWaiProperty :: Application -> Property}
+data WaiProperty st = WaiProperty {unWaiProperty :: (st, Application) -> Property}
 
 class Testable a where
-  toProperty :: a -> WaiProperty
+  type State a
+  toProperty :: a -> WaiProperty (State a)
 
-instance Testable WaiProperty where
+instance Testable (WaiProperty st) where
+  type State (WaiProperty st) = st
   toProperty = id
 
-instance Testable WaiExpectation where
-  toProperty action = WaiProperty (QuickCheck.property . runWaiSession action)
+instance Testable (WaiExpectation st) where
+  type State (WaiExpectation st) = st
+  toProperty action = WaiProperty (QuickCheck.property . runWithState action)
 
 instance (Arbitrary a, Show a, Testable prop) => Testable (a -> prop) where
+  type State (a -> prop) = State prop
   toProperty prop = WaiProperty $ QuickCheck.property . (flip $ unWaiProperty . toProperty . prop)
 
 infixr 0 ==>
-(==>) :: Testable prop => Bool -> prop -> WaiProperty
+(==>) :: Testable prop => Bool -> prop -> WaiProperty (State prop)
 (==>) = lift (QuickCheck.==>)
 
-lift :: Testable prop => (a -> Property -> Property) -> a -> prop -> WaiProperty
+lift :: Testable prop => (a -> Property -> Property) -> a -> prop -> WaiProperty (State prop)
 lift f a prop = WaiProperty $ \app -> f a (unWaiProperty (toProperty prop) app)
