diff --git a/integration/Main.hs b/integration/Main.hs
--- a/integration/Main.hs
+++ b/integration/Main.hs
@@ -2,6 +2,7 @@
 
 import Test.Tasty (TestTree, defaultMain, testGroup)
 
+import Polysemy.Http.CookieTest (test_cookies)
 import Polysemy.Http.RequestTest (test_request)
 import Polysemy.Http.StreamTest (test_httpStream)
 import Polysemy.Http.Test (unitTest)
@@ -10,7 +11,8 @@
 tests =
   testGroup "integration" [
     unitTest "simple request" test_request,
-    unitTest "streaming http response handler" test_httpStream
+    unitTest "streaming http response handler" test_httpStream,
+    unitTest "cookies" test_cookies
   ]
 
 main :: IO ()
diff --git a/integration/Polysemy/Http/CookieTest.hs b/integration/Polysemy/Http/CookieTest.hs
new file mode 100644
--- /dev/null
+++ b/integration/Polysemy/Http/CookieTest.hs
@@ -0,0 +1,44 @@
+module Polysemy.Http.CookieTest where
+
+import Control.Lens ((.~))
+import Hedgehog (evalEither, (===))
+import Polysemy (embedToFinal, runFinal)
+
+import qualified Polysemy.Http.Data.Http as Http
+import Polysemy.Http.Data.HttpError (HttpError)
+import qualified Polysemy.Http.Data.Request as Request
+import Polysemy.Http.Data.Request (Port(Port), Tls(Tls))
+import qualified Polysemy.Http.Data.Response as Response
+import Polysemy.Http.Data.Response (Response)
+import Polysemy.Http.Log (interpretLogNull)
+import Polysemy.Http.Native (interpretHttpNative)
+import qualified Polysemy.Http.Request as Request
+import Polysemy.Http.Request (addCookie)
+import Polysemy.Http.Server (withServer)
+import Polysemy.Http.Test (UnitTest)
+import Polysemy.Resource (resourceToIOFinal)
+
+c1, c1v, c2, c2v :: Text
+c1 = "c1"
+c1v = "c1v"
+c2 = "c2"
+c2v = "c2v"
+
+runRequest ::
+  Int ->
+  IO (Either HttpError (Response LByteString))
+runRequest port = do
+  runFinal $ resourceToIOFinal $ embedToFinal $ interpretLogNull $ interpretHttpNative (Http.request request)
+  where
+  request =
+    Request.get "localhost" "cookie"
+    & Request.tls .~ Tls False
+    & Request.port .~ Just (Port port)
+    & addCookie "localhost" c2 c2v
+    & addCookie "localhost" c1 c1v
+
+test_cookies :: UnitTest
+test_cookies = do
+  result <- lift (withServer runRequest)
+  response <- evalEither result
+  [qt|#{c1}=#{c1v};#{c2}=#{c2v}|] === Response.body response
diff --git a/integration/Polysemy/Http/Server.hs b/integration/Polysemy/Http/Server.hs
--- a/integration/Polysemy/Http/Server.hs
+++ b/integration/Polysemy/Http/Server.hs
@@ -19,7 +19,7 @@
   withSocketsDo,
   )
 import qualified Network.Wai.Handler.Warp as Warp
-import Servant (Get, Handler, JSON, PlainText, Post, ReqBody, ServerT, serve, (:<|>)((:<|>)), (:>))
+import Servant (Header, Get, Handler, JSON, PlainText, Post, ReqBody, ServerT, serve, (:<|>)((:<|>)), (:>))
 import Servant.Client (BaseUrl(BaseUrl), Client, ClientEnv, ClientM, Scheme(Http), client, mkClientEnv, runClientM)
 
 freePort ::
@@ -49,6 +49,8 @@
   "add" :> ReqBody '[JSON] Payload :> Post '[JSON] Int
   :<|>
   "stream" :> Get '[PlainText] Text
+  :<|>
+  "cookie" :> Header "cookie" Text :> Get '[PlainText] Text
 
 apiClient :: Client ClientM Api
 apiClient =
@@ -71,6 +73,8 @@
   (\ (Payload a b) -> pure (a + b))
   :<|>
   pure (Text.replicate (10 * 8192) "x")
+  :<|>
+  (\ cookies -> pure (fromMaybe "no cookies" cookies))
 
 forkServer :: IO (ThreadId, Int)
 forkServer = do
diff --git a/lib/Polysemy/Http.hs b/lib/Polysemy/Http.hs
--- a/lib/Polysemy/Http.hs
+++ b/lib/Polysemy/Http.hs
@@ -8,7 +8,21 @@
   module Polysemy.Http.Data.Request,
   module Polysemy.Http.Data.Response,
   module Polysemy.Http.Data.Header,
-  module Polysemy.Http.Request,
+  withPort,
+  withTls,
+  simple,
+  get,
+  post,
+  put,
+  delete,
+  fromUrl,
+  getUrl,
+  postUrl,
+  putUrl,
+  deleteUrl,
+  cookie,
+  addCookies,
+  addCookie,
   HttpError(..),
   -- * Streaming
   module Polysemy.Http.Http,
@@ -78,8 +92,25 @@
 import Polysemy.Http.Http (streamResponse)
 import Polysemy.Http.Log (interpretLogNull, interpretLogStdout)
 import Polysemy.Http.Native (interpretHttpNative)
-import Polysemy.Http.Request (delete, deleteUrl, get, getUrl, post, postUrl, put, putUrl)
+import Polysemy.Http.Request (
+  addCookie,
+  addCookies,
+  cookie,
+  delete,
+  deleteUrl,
+  fromUrl,
+  get,
+  getUrl,
+  post,
+  postUrl,
+  put,
+  putUrl,
+  simple,
+  withPort,
+  withTls,
+  )
 import Polysemy.Http.Strict (interpretHttpStrict)
+import Prelude hiding (get, put)
 
 -- $intro
 -- A basic 'Polysemy' effect abstracting HTTP requests:
diff --git a/lib/Polysemy/Http/Data/Request.hs b/lib/Polysemy/Http/Data/Request.hs
--- a/lib/Polysemy/Http/Data/Request.hs
+++ b/lib/Polysemy/Http/Data/Request.hs
@@ -2,6 +2,7 @@
 
 import Control.Lens (makeClassy)
 import qualified Data.Text as Text
+import Network.HTTP.Client.Internal (CookieJar)
 
 import Polysemy.Http.Data.Header (HeaderName, HeaderValue)
 
@@ -123,6 +124,7 @@
     _tls :: Tls,
     _path :: Path,
     _headers :: [(HeaderName, HeaderValue)],
+    _cookies :: CookieJar,
     _query :: [(QueryKey, Maybe QueryValue)],
     _body :: Body
   }
diff --git a/lib/Polysemy/Http/Native.hs b/lib/Polysemy/Http/Native.hs
--- a/lib/Polysemy/Http/Native.hs
+++ b/lib/Polysemy/Http/Native.hs
@@ -2,23 +2,9 @@
 
 import qualified Data.CaseInsensitive as CaseInsensitive
 import Data.CaseInsensitive (foldedCase)
+import qualified Network.HTTP.Client as HTTP
 import Network.HTTP.Client (BodyReader, httpLbs, responseClose, responseOpen)
-import qualified Network.HTTP.Client as HTTP (Manager)
-import Network.HTTP.Simple (
-  defaultRequest,
-  getResponseBody,
-  getResponseHeaders,
-  getResponseStatus,
-  setRequestBodyLBS,
-  setRequestHeaders,
-  setRequestHost,
-  setRequestMethod,
-  setRequestPath,
-  setRequestPort,
-  setRequestQueryString,
-  setRequestSecure,
-  )
-import qualified Network.HTTP.Simple as N (Request, Response)
+import Network.HTTP.Client.Internal (CookieJar(CJ))
 import Polysemy (Tactical, interpretH, runT)
 import qualified Polysemy.Http.Data.Log as Log
 import Polysemy.Http.Data.Log (Log)
@@ -46,34 +32,32 @@
 import Polysemy.Http.Manager (interpretManager)
 
 -- |Converts a 'Request' to a native 'N.Request'.
-nativeRequest :: Request -> N.Request
-nativeRequest (Request method (Host host) portOverride (Tls tls) (Path path) headers query (Body body)) =
-  cons defaultRequest
+nativeRequest :: Request -> HTTP.Request
+nativeRequest (Request method (Host host) portOverride (Tls tls) (Path path) headers (CJ cookies) query (Body body)) =
+  HTTP.setQueryString queryParams HTTP.defaultRequest {
+    HTTP.host = encodeUtf8 host,
+    HTTP.port = port,
+    HTTP.secure = tls,
+    HTTP.method = encodeUtf8 (methodUpper method),
+    HTTP.requestHeaders = encodedHeaders,
+    HTTP.path = encodeUtf8 path,
+    HTTP.requestBody = HTTP.RequestBodyLBS body,
+    HTTP.cookieJar = CJ . toList <$> nonEmpty cookies
+  }
   where
-    cons =
-      scheme .
-      setRequestMethod (encodeUtf8 $ methodUpper method) .
-      setRequestHeaders encodedHeaders .
-      setRequestHost (encodeUtf8 host) .
-      setRequestPort port .
-      setRequestPath (encodeUtf8 path) .
-      setRequestQueryString queryParam .
-      setRequestBodyLBS body
-    queryParam =
+    queryParams =
       bimap (encodeUtf8 . unQueryKey) (fmap (encodeUtf8 . unQueryValue)) <$> query
-    scheme =
-      if tls then setRequestSecure True else id
     port =
       maybe (if tls then 443 else 80) unPort portOverride
     encodedHeaders =
       bimap (CaseInsensitive.mk . encodeUtf8 . unHeaderName) (encodeUtf8 . unHeaderValue) <$> headers
 
-convertResponse :: N.Response b -> Response b
+convertResponse :: HTTP.Response b -> Response b
 convertResponse response =
-  Response (getResponseStatus response) (getResponseBody response) headers
+  Response (HTTP.responseStatus response) (HTTP.responseBody response) headers
   where
     headers =
-      header <$> getResponseHeaders response
+      header <$> HTTP.responseHeaders response
     header (foldedCase -> decodeUtf8 -> name, decodeUtf8 -> value) =
       Header (fromString name) (fromString value)
 
diff --git a/lib/Polysemy/Http/Request.hs b/lib/Polysemy/Http/Request.hs
--- a/lib/Polysemy/Http/Request.hs
+++ b/lib/Polysemy/Http/Request.hs
@@ -1,8 +1,15 @@
 module Polysemy.Http.Request where
 
+import Control.Lens ((%~))
 import qualified Data.Text as Text
-import Prelude hiding (get)
+import Data.Time (UTCTime(UTCTime))
+import Network.HTTP.Client (Cookie(Cookie))
+import Network.HTTP.Client.Internal (CookieJar(CJ, expose))
+import Prelude hiding (get, put)
 
+import Data.Time.Calendar (fromGregorian)
+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
+import qualified Polysemy.Http.Data.Request as Request
 import Polysemy.Http.Data.Request (Body, Host(Host), Method(..), Path(Path), Port(Port), Request(Request), Tls(Tls))
 
 invalidScheme ::
@@ -48,6 +55,7 @@
   (host, port) <- parseHostPort url (split ":" hostPort)
   pure (tls, host, port, Path (fromMaybe "" path))
 
+-- |Create a request with empty headers, query and cookies.
 withPort ::
   Maybe Port ->
   Tls ->
@@ -57,8 +65,9 @@
   Body ->
   Request
 withPort port tls method host path =
-  Request method host port tls path [] []
+  Request method host port tls path [] (CJ []) []
 
+-- |Create a request with default port and empty headers, query and cookies.
 withTls ::
   Tls ->
   Method ->
@@ -69,6 +78,7 @@
 withTls =
   withPort Nothing
 
+-- |Create a TLS request with default port and empty headers, query and cookies.
 simple ::
   Method ->
   Host ->
@@ -78,6 +88,7 @@
 simple =
   withTls (Tls True)
 
+-- |Create a TLS GET request with default port and empty headers, query and cookies.
 get ::
   Host ->
   Path ->
@@ -85,6 +96,7 @@
 get host path =
   simple Get host path ""
 
+-- |Create a TLS POST request with default port and empty headers, query and cookies.
 post ::
   Host ->
   Path ->
@@ -93,6 +105,7 @@
 post host path =
   simple Post host path
 
+-- |Create a TLS PUT request with default port and empty headers, query and cookies.
 put ::
   Host ->
   Path ->
@@ -101,6 +114,7 @@
 put host path =
   simple Put host path
 
+-- |Create a TLS DELETE request with default port and empty headers, query and cookies.
 delete ::
   Host ->
   Path ->
@@ -108,6 +122,7 @@
 delete host path =
   simple Delete host path ""
 
+-- |Parse the URL and create a request or return a parse error.
 fromUrl ::
   Method ->
   Body ->
@@ -117,12 +132,14 @@
   (tls, host, port, path) <- parseUrl url
   pure (withPort port tls method host path body)
 
+-- |Parse URL for a GET.
 getUrl ::
   Text ->
   Either Text Request
 getUrl =
   fromUrl Get ""
 
+-- |Parse URL for a POST.
 postUrl ::
   Body ->
   Text ->
@@ -130,6 +147,7 @@
 postUrl =
   fromUrl Post
 
+-- |Parse URL for a PUT.
 putUrl ::
   Body ->
   Text ->
@@ -137,8 +155,47 @@
 putUrl =
   fromUrl Put
 
+-- |Parse URL for a DELETE.
 deleteUrl ::
   Text ->
   Either Text Request
 deleteUrl =
   fromUrl Delete ""
+
+neverExpire :: UTCTime
+neverExpire =
+  UTCTime (fromGregorian 9999 1 1) 0
+
+epoch :: UTCTime
+epoch =
+  posixSecondsToUTCTime 0
+
+-- |Create a cookie with default values.
+cookie ::
+  Text ->
+  Text ->
+  Text ->
+  Cookie
+cookie domain name value =
+  Cookie (encodeUtf8 name) (encodeUtf8 value) neverExpire (encodeUtf8 domain) "/" epoch epoch False False False False
+
+-- |Add multiple cookies to a request.
+addCookies ::
+  [Cookie] ->
+  Request ->
+  Request
+addCookies cookies =
+  Request.cookies %~ update
+  where
+    update =
+      CJ . (cookies <>) . expose
+
+-- |Add a cookie to a request, using default values.
+addCookie ::
+  Text ->
+  Text ->
+  Text ->
+  Request ->
+  Request
+addCookie domain name value =
+  addCookies (pure (cookie domain name value))
diff --git a/polysemy-http.cabal b/polysemy-http.cabal
--- a/polysemy-http.cabal
+++ b/polysemy-http.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           polysemy-http
-version:        0.2.0.4
+version:        0.3.0.0
 synopsis:       Polysemy effect for http-client
 description:    Please see the README on Github at <https://github.com/tek/polysemy-http>
 category:       Network
@@ -70,7 +70,6 @@
     , either >=5.0.1
     , http-client >=0.6.4
     , http-client-tls >=0.3.5
-    , http-conduit >=2.3.7
     , http-types >=0.12.3
     , lens >=4
     , polysemy >=1.3.0
@@ -79,6 +78,7 @@
     , string-interpolate >=0.2.1
     , template-haskell >=2.14.0
     , text >=1.2.3
+    , time
   mixins:
       base hiding (Prelude)
   if impl(ghc < 8.10)
@@ -89,6 +89,7 @@
   type: exitcode-stdio-1.0
   main-is: Main.hs
   other-modules:
+      Polysemy.Http.CookieTest
       Polysemy.Http.RequestTest
       Polysemy.Http.Server
       Polysemy.Http.StreamTest
@@ -113,7 +114,6 @@
     , hedgehog
     , http-client >=0.6.4
     , http-client-tls >=0.3.5
-    , http-conduit >=2.3.7
     , http-types >=0.12.3
     , lens >=4
     , network
@@ -129,6 +129,7 @@
     , tasty-hedgehog
     , template-haskell >=2.14.0
     , text >=1.2.3
+    , time
     , warp
   mixins:
       base hiding (Prelude)
@@ -165,7 +166,6 @@
     , hedgehog
     , http-client >=0.6.4
     , http-client-tls >=0.3.5
-    , http-conduit >=2.3.7
     , http-types >=0.12.3
     , lens >=4
     , polysemy >=1.3.0
@@ -177,6 +177,7 @@
     , tasty-hedgehog
     , template-haskell >=2.14.0
     , text >=1.2.3
+    , time
   mixins:
       base hiding (Prelude)
     , polysemy-http hiding (Prelude)
