diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+## 0.1.11
+
+* `getUnusedInflated`: Return uncompressed data following compressed data [#20](https://github.com/fpco/streaming-commons/issues/20)
+
 ## 0.1.10
 
 Support blaze-builder >= 0.4.  Add `newByteStringBuilderRecv` to Data.Streaming.ByteString.Builder; add modules Data.Streaming.ByteString.Builder.Buffer and  Data.Streaming.ByteString.Builder.Class.
diff --git a/Data/Streaming/Zlib.hs b/Data/Streaming/Zlib.hs
--- a/Data/Streaming/Zlib.hs
+++ b/Data/Streaming/Zlib.hs
@@ -26,6 +26,7 @@
     , feedInflate
     , finishInflate
     , flushInflate
+    , getUnusedInflate
       -- * Deflate
     , Deflate
     , initDeflate
@@ -51,13 +52,17 @@
 import Data.ByteString.Lazy.Internal (defaultChunkSize)
 import Data.Typeable (Typeable)
 import Control.Exception (Exception)
+import Data.IORef
 
 type ZStreamPair = (ForeignPtr ZStreamStruct, ForeignPtr CChar)
 
 -- | The state of an inflation (eg, decompression) process. All allocated
 -- memory is automatically reclaimed by the garbage collector.
 -- Also can contain the inflation dictionary that is used for decompression.
-newtype Inflate = Inflate (ZStreamPair, Maybe S.ByteString)
+data Inflate = Inflate
+    ZStreamPair
+    (IORef S.ByteString) -- last ByteString fed in, needed for getUnusedInflate
+    (Maybe S.ByteString) -- dictionary
 
 -- | The state of a deflation (eg, compression) process. All allocated memory
 -- is automatically reclaimed by the garbage collector.
@@ -107,7 +112,8 @@
     fbuff <- mallocForeignPtrBytes defaultChunkSize
     withForeignPtr fbuff $ \buff ->
         c_set_avail_out zstr buff $ fromIntegral defaultChunkSize
-    return $ Inflate ((fzstr, fbuff), Nothing)
+    lastBS <- newIORef S.empty
+    return $ Inflate (fzstr, fbuff) lastBS Nothing
 
 -- | Initialize an inflation process with the given 'WindowBits'. 
 -- Unlike initInflate a dictionary for inflation is set which must
@@ -121,7 +127,8 @@
 
     withForeignPtr fbuff $ \buff ->
         c_set_avail_out zstr buff $ fromIntegral defaultChunkSize
-    return $ Inflate ((fzstr, fbuff), Just bs)
+    lastBS <- newIORef S.empty
+    return $ Inflate (fzstr, fbuff) lastBS (Just bs)
 
 -- | Initialize a deflation process with the given compression level and
 -- 'WindowBits'. You will need to call 'feedDeflate' to feed uncompressed
@@ -171,7 +178,14 @@
     :: Inflate
     -> S.ByteString
     -> IO Popper
-feedInflate (Inflate ((fzstr, fbuff), inflateDictionary)) bs = do
+feedInflate (Inflate (fzstr, fbuff) lastBS inflateDictionary) bs = do
+    -- Write the BS to lastBS for use by getUnusedInflate. This is
+    -- theoretically unnecessary, since we could just grab the pointer from the
+    -- fzstr when needed. However, in that case, we wouldn't be holding onto a
+    -- reference to the ForeignPtr, so the GC may decide to collect the
+    -- ByteString in the interim.
+    writeIORef lastBS bs
+
     withForeignPtr fzstr $ \zstr ->
         unsafeUseAsCStringLen bs $ \(cstr, len) ->
             c_set_avail_in zstr cstr $ fromIntegral len
@@ -229,7 +243,7 @@
 -- data, you will likely have some data still sitting in the buffer. This
 -- function will return it to you.
 finishInflate :: Inflate -> IO S.ByteString
-finishInflate (Inflate ((fzstr, fbuff), _)) =
+finishInflate (Inflate (fzstr, fbuff) _ _) =
     withForeignPtr fzstr $ \zstr ->
         withForeignPtr fbuff $ \buff -> do
             avail <- c_get_avail_out zstr
@@ -246,6 +260,17 @@
 -- Since 0.0.3
 flushInflate :: Inflate -> IO S.ByteString
 flushInflate = finishInflate
+
+-- | Retrieve any data remaining after inflating. For more information on motivation, see:
+--
+-- <https://github.com/fpco/streaming-commons/issues/20>
+--
+-- Since 0.1.11
+getUnusedInflate :: Inflate -> IO S.ByteString
+getUnusedInflate (Inflate (fzstr, _) ref _) = do
+    bs <- readIORef ref
+    len <- withForeignPtr fzstr c_get_avail_in
+    return $ S.drop (S.length bs - fromIntegral len) bs
 
 -- | Feed the given 'S.ByteString' to the deflater. Return a 'Popper',
 -- an IO action that returns the compressed data a chunk at a time.
diff --git a/streaming-commons.cabal b/streaming-commons.cabal
--- a/streaming-commons.cabal
+++ b/streaming-commons.cabal
@@ -1,5 +1,5 @@
 name:                streaming-commons
-version:             0.1.10.0
+version:             0.1.11
 synopsis:            Common lower-level functions needed by various streaming data libraries
 description:         Provides low-dependency functionality commonly needed by various streaming data libraries, such as conduit and pipes.
 homepage:            https://github.com/fpco/streaming-commons
diff --git a/test/Data/Streaming/ZlibSpec.hs b/test/Data/Streaming/ZlibSpec.hs
--- a/test/Data/Streaming/ZlibSpec.hs
+++ b/test/Data/Streaming/ZlibSpec.hs
@@ -6,6 +6,7 @@
 import Test.Hspec.QuickCheck (prop)
 import Test.QuickCheck (Arbitrary (..))
 
+import Control.Exception (throwIO)
 import Data.Streaming.Zlib
 import Codec.Compression.Zlib
 import qualified Codec.Compression.GZip as Gzip
@@ -218,6 +219,26 @@
             output <- decompressRaw $ Raw.compress input
             L.all (== 10) output `shouldBe` True
             L.length output `shouldBe` L.length input
+
+    it "getUnusedInflate" $ do
+        let c = "This data is stored compressed."
+            u = "This data isn't."
+        def <- initDeflate 5 defaultWindowBits
+        let loop front popper = do
+                res <- popper
+                case res of
+                    PRDone -> return front
+                    PRNext bs -> loop (S.append front bs) popper
+                    PRError e -> throwIO e
+
+        c' <- feedDeflate def c >>= loop S.empty >>= flip loop (finishDeflate def)
+
+        inf <- initInflate defaultWindowBits
+        x <- feedInflate inf (S.append c' u) >>= loop S.empty
+        y <- finishInflate inf
+        S.append x y `shouldBe` c
+        z <- getUnusedInflate inf
+        z `shouldBe` u
 
 rawWindowBits :: WindowBits
 rawWindowBits = WindowBits (-15)
