diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,11 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## 0.18.8
+### Added
+- Transaction and block timeouts for health check.
+- Raw blocks.
+
 ## 0.18.7
 ### Fixed
 - Missing tranasctions on xpub listings.
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -7,6 +7,8 @@
 {-# LANGUAGE RecordWildCards   #-}
 {-# LANGUAGE TemplateHaskell   #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
+module Main where
+
 import           Conduit
 import           Control.Arrow
 import           Control.Exception          ()
@@ -55,6 +57,7 @@
     , configDebug     :: !Bool
     , configReqLog    :: !Bool
     , configMaxLimits :: !MaxLimits
+    , configTimeouts  :: !Timeouts
     }
 
 defPort :: Int
@@ -76,6 +79,9 @@
         , maxLimitGap = 20
         }
 
+defTimeouts :: Timeouts
+defTimeouts = Timeouts {blockTimeout = 7200, txTimeout = 600}
+
 config :: Parser Config
 config = do
     configDir <-
@@ -120,8 +126,7 @@
         value (maxLimitFull defMaxLimits)
     maxLimitOffset <-
         option auto $
-        metavar "INT" <> long "maxoffset" <>
-        help "Max offset (0 for no limit)" <>
+        metavar "INT" <> long "maxoffset" <> help "Max offset (0 for no limit)" <>
         showDefault <>
         value (maxLimitOffset defMaxLimits)
     maxLimitDefault <-
@@ -134,7 +139,24 @@
         metavar "INT" <> long "gap" <> help "Extended public key gap" <>
         showDefault <>
         value (maxLimitGap defMaxLimits)
-    pure Config {configMaxLimits = MaxLimits {..}, ..}
+    blockTimeout <-
+        option auto $
+        metavar "INT" <> long "blocktimeout" <>
+        help "Unhealthy if no block for this many seconds" <>
+        showDefault <>
+        value (blockTimeout defTimeouts)
+    txTimeout <-
+        option auto $
+        metavar "INT" <> long "txtimeout" <>
+        help "Unhealthy if no new tx in this many seconds" <>
+        showDefault <>
+        value (txTimeout defTimeouts)
+    pure
+        Config
+            { configMaxLimits = MaxLimits {..}
+            , configTimeouts = Timeouts {..}
+            , ..
+            }
 
 networkReader :: String -> Either String Network
 networkReader s
@@ -194,6 +216,7 @@
            , configDebug = deb
            , configMaxLimits = limits
            , configReqLog = reqlog
+           , configTimeouts = tos
            } =
     runStderrLoggingT . filterLogger l . flip finally clear $ do
         $(logInfoS) "Main" $
@@ -251,6 +274,7 @@
                                 , webStore = str
                                 , webMaxLimits = limits
                                 , webReqLog = reqlog
+                                , webTimeouts = tos
                                 }
                      in runWeb wcfg
   where
diff --git a/haskoin-store.cabal b/haskoin-store.cabal
--- a/haskoin-store.cabal
+++ b/haskoin-store.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 484fc09cd43cad3fa46c71963e8d58bce072ca2aefb5f8c5fcabadb1b93c791b
+-- hash: 88361eb08860af74fe1889c4b02d3ae0e4289cc2d4b2d8249e19e22d94ea2b05
 
 name:           haskoin-store
-version:        0.18.7
+version:        0.18.8
 synopsis:       Storage and index for Bitcoin and Bitcoin Cash
 description:    Store blocks, transactions, and balances for Bitcoin or Bitcoin Cash, and make that information via REST API.
 category:       Bitcoin, Finance, Network
@@ -54,7 +54,7 @@
     , containers
     , data-default
     , hashable
-    , haskoin-core >=0.9.5
+    , haskoin-core >=0.9.7
     , haskoin-node
     , http-types
     , monad-logger
@@ -94,7 +94,7 @@
     , data-default
     , filepath
     , hashable
-    , haskoin-core >=0.9.5
+    , haskoin-core >=0.9.7
     , haskoin-node
     , haskoin-store
     , http-types
@@ -138,7 +138,7 @@
     , containers
     , data-default
     , hashable
-    , haskoin-core >=0.9.5
+    , haskoin-core >=0.9.7
     , haskoin-node
     , haskoin-store
     , hspec
diff --git a/src/Haskoin/Store.hs b/src/Haskoin/Store.hs
--- a/src/Haskoin/Store.hs
+++ b/src/Haskoin/Store.hs
@@ -38,6 +38,7 @@
     , LayeredDB(..)
     , WebConfig(..)
     , MaxLimits(..)
+    , Timeouts(..)
     , Offset
     , Limit
     , newLayeredDB
diff --git a/src/Network/Haskoin/Store/Data.hs b/src/Network/Haskoin/Store/Data.hs
--- a/src/Network/Haskoin/Store/Data.hs
+++ b/src/Network/Haskoin/Store/Data.hs
@@ -793,6 +793,14 @@
     binSerial _ = put
     binDeserial _ = get
 
+instance JsonSerial Block where
+    jsonSerial _ = toEncoding
+    jsonValue _ = toJSON
+
+instance BinSerial Block where
+    binSerial _ = put
+    binDeserial _ = get
+
 -- | Information about a connected peer.
 data PeerInformation
     = PeerInformation { peerUserAgent :: !ByteString
@@ -985,19 +993,23 @@
             forM xs $ \(k, v) ->
                 case k of
                     Right a -> return (a, v)
-                    Left _ -> mzero
+                    Left _  -> mzero
         return $ XPubSummary c z r u ext ch (M.fromList ys)
 
-data HealthCheck = HealthCheck
-    { healthHeaderBest   :: !(Maybe BlockHash)
-    , healthHeaderHeight :: !(Maybe BlockHeight)
-    , healthBlockBest    :: !(Maybe BlockHash)
-    , healthBlockHeight  :: !(Maybe BlockHeight)
-    , healthPeers        :: !(Maybe Int)
-    , healthNetwork      :: !String
-    , healthOK           :: !Bool
-    , healthSynced       :: !Bool
-    } deriving (Show, Eq, Generic, Serialize)
+data HealthCheck =
+    HealthCheck
+        { healthHeaderBest   :: !(Maybe BlockHash)
+        , healthHeaderHeight :: !(Maybe BlockHeight)
+        , healthBlockBest    :: !(Maybe BlockHash)
+        , healthBlockHeight  :: !(Maybe BlockHeight)
+        , healthPeers        :: !(Maybe Int)
+        , healthNetwork      :: !String
+        , healthOK           :: !Bool
+        , healthSynced       :: !Bool
+        , healthLastBlock    :: !(Maybe Word64)
+        , healthLastTx       :: !(Maybe Word64)
+        }
+    deriving (Show, Eq, Generic, Serialize)
 
 healthCheckPairs :: A.KeyValue kv => HealthCheck -> [kv]
 healthCheckPairs h =
@@ -1010,6 +1022,8 @@
     , "ok" .= healthOK h
     , "synced" .= healthSynced h
     , "version" .= P.version
+    , "lastblock" .= healthLastBlock h
+    , "lasttx" .= healthLastTx h
     ]
 
 instance ToJSON HealthCheck where
@@ -1029,6 +1043,8 @@
                             , healthNetwork = net
                             , healthOK = ok
                             , healthSynced = synced
+                            , healthLastBlock = lbk
+                            , healthLastTx = ltx
                             } = do
         put hbest
         put hheight
@@ -1038,8 +1054,13 @@
         put net
         put ok
         put synced
-
-    binDeserial _ = HealthCheck <$> get <*> get <*> get <*> get <*> get <*> get <*> get <*> get
+        put lbk
+        put ltx
+    binDeserial _ =
+        HealthCheck <$> get <*> get <*> get <*> get <*> get <*> get <*> get <*>
+        get <*>
+        get <*>
+        get
 
 data Event
     = EventBlock BlockHash
diff --git a/src/Network/Haskoin/Store/Web.hs b/src/Network/Haskoin/Store/Web.hs
--- a/src/Network/Haskoin/Store/Web.hs
+++ b/src/Network/Haskoin/Store/Web.hs
@@ -39,6 +39,7 @@
 import qualified Data.Text.Encoding                as T
 import qualified Data.Text.Lazy                    as T.Lazy
 import           Data.Time.Clock
+import           Data.Time.Clock.System
 import           Data.Vector                       (Vector, cons, (!))
 import qualified Data.Vector                       as V
 import           Data.Version
@@ -122,6 +123,7 @@
         , webStore     :: !Store
         , webMaxLimits :: !MaxLimits
         , webReqLog    :: !Bool
+        , webTimeouts  :: !Timeouts
         }
 
 data MaxLimits =
@@ -134,6 +136,13 @@
         }
     deriving (Eq, Show)
 
+data Timeouts =
+    Timeouts
+        { txTimeout    :: !Word64
+        , blockTimeout :: !Word64
+        }
+    deriving (Eq, Show)
+
 instance Parsable BlockHash where
     parseParam =
         maybe (Left "could not decode block hash") Right . hexToBlockHash . cs
@@ -211,43 +220,57 @@
     -> WebT m ()
 protoSerial net proto = S.raw . serialAny net proto
 
-scottyBestBlock :: MonadLoggerIO m => Network -> WebT m ()
-scottyBestBlock net = do
+scottyBestBlock :: MonadUnliftIO m => Network -> Bool -> WebT m ()
+scottyBestBlock net raw = do
     cors
     n <- parseNoTx
     proto <- setupBin
-    res <-
+    bm <-
         runMaybeT $ do
             h <- MaybeT getBestBlock
-            b <- MaybeT $ getBlock h
-            return $ pruneTx n b
-    maybeSerial net proto res
+            MaybeT $ getBlock h
+    b <-
+        case bm of
+            Nothing -> raise ThingNotFound
+            Just b -> return b
+    if raw
+        then rawBlock b >>= protoSerial net proto
+        else protoSerial net proto (pruneTx n b)
 
-scottyBlock :: MonadLoggerIO m => Network -> WebT m ()
-scottyBlock net = do
+scottyBlock :: MonadUnliftIO m => Network -> Bool -> WebT m ()
+scottyBlock net raw = do
     cors
     block <- param "block"
     n <- parseNoTx
     proto <- setupBin
-    res <-
-        runMaybeT $ do
-            b <- MaybeT $ getBlock block
-            return $ pruneTx n b
-    maybeSerial net proto res
+    b <-
+        getBlock block >>= \case
+            Nothing -> raise ThingNotFound
+            Just b -> return b
+    if raw
+        then rawBlock b >>= protoSerial net proto
+        else protoSerial net proto (pruneTx n b)
 
-scottyBlockHeight :: (MonadLoggerIO m, MonadUnliftIO m) => Network -> WebT m ()
-scottyBlockHeight net = do
+scottyBlockHeight ::
+       (MonadLoggerIO m, MonadUnliftIO m) => Network -> Bool -> WebT m ()
+scottyBlockHeight net raw = do
     cors
     height <- param "height"
     n <- parseNoTx
     proto <- setupBin
     hs <- getBlocksAtHeight height
     db <- askDB
-    stream $ \io flush' -> do
-        runStream db . runConduit $
-            yieldMany hs .| concatMapMC getBlock .| mapC (pruneTx n) .|
-            streamAny net proto io
-        flush'
+    if raw
+        then stream $ \io flush' -> do
+                 runStream db . runConduit $
+                     yieldMany hs .| concatMapMC getBlock .| mapMC rawBlock .|
+                     streamAny net proto io
+                 flush'
+        else stream $ \io flush' -> do
+                 runStream db . runConduit $
+                     yieldMany hs .| concatMapMC getBlock .| mapC (pruneTx n) .|
+                     streamAny net proto io
+                 flush'
 
 scottyBlockHeights :: (MonadLoggerIO m, MonadUnliftIO m) => Network -> WebT m ()
 scottyBlockHeights net = do
@@ -379,6 +402,16 @@
             streamAny net proto io
         flush'
 
+rawBlock :: (Monad m, StoreRead m) => BlockData -> m Block
+rawBlock b = do
+    let h = blockDataHeader b
+    txs <-
+        runConduit $
+        yieldMany (blockDataTxs b) .| concatMapMC getTransaction .|
+        mapC transactionData .|
+        sinkList
+    return Block {blockHeader = h, blockTxns = txs}
+
 scottyRawBlockTransactions ::
        (MonadLoggerIO m, MonadUnliftIO m) => Network -> WebT m ()
 scottyRawBlockTransactions net = do
@@ -653,11 +686,18 @@
     protoSerial net proto ps
 
 scottyHealth ::
-       (MonadLoggerIO m, MonadUnliftIO m) => Network -> Store -> WebT m ()
-scottyHealth net st = do
+       (MonadLoggerIO m, MonadUnliftIO m)
+    => Network
+    -> Store
+    -> Timeouts
+    -> WebT m ()
+scottyHealth net st tos = do
     cors
     proto <- setupBin
-    h <- lift $ healthCheck net (storeManager st) (storeChain st)
+    db <- askDB
+    h <-
+        liftIO . runStream db $
+        healthCheck net (storeManager st) (storeChain st) tos
     when (not (healthOK h) || not (healthSynced h)) $ status status503
     protoSerial net proto h
 
@@ -669,6 +709,7 @@
                  , webPublisher = pub
                  , webMaxLimits = limits
                  , webReqLog = reqlog
+                 , webTimeouts = tos
                  } = do
     req_logger <-
         if reqlog
@@ -677,12 +718,15 @@
     runner <- askRunInIO
     scottyT port (runner . withLayeredDB db) $ do
         case req_logger of
-            Just m -> middleware m
+            Just m  -> middleware m
             Nothing -> return ()
         defaultHandler (defHandler net)
-        S.get "/block/best" $ scottyBestBlock net
-        S.get "/block/:block" $ scottyBlock net
-        S.get "/block/height/:height" $ scottyBlockHeight net
+        S.get "/block/best" $ scottyBestBlock net False
+        S.get "/block/best/raw" $ scottyBestBlock net True
+        S.get "/block/:block" $ scottyBlock net False
+        S.get "/block/:block/raw" $ scottyBlock net True
+        S.get "/block/height/:height" $ scottyBlockHeight net False
+        S.get "/block/height/:height/raw" $ scottyBlockHeight net True
         S.get "/block/heights" $ scottyBlockHeights net
         S.get "/block/latest" $ scottyBlockLatest net
         S.get "/blocks" $ scottyBlocks net
@@ -713,7 +757,7 @@
         S.get "/dbstats" scottyDbStats
         S.get "/events" $ scottyEvents net pub
         S.get "/peers" $ scottyPeers net st
-        S.get "/health" $ scottyHealth net st
+        S.get "/health" $ scottyHealth net st tos
         notFound $ raise ThingNotFound
 
 getStart :: MonadUnliftIO m => WebT m (Maybe BlockRef)
@@ -802,7 +846,7 @@
           return $ case (t :: Text) of
             "segwit" -> deriveWitnessAddrs
             "compat" -> deriveCompatWitnessAddrs
-            _ -> deriveAddrs
+            _        -> deriveAddrs
     | otherwise = return deriveAddrs
 
 parseNoTx :: (Monad m, ScottyError e) => ActionT e m Bool
@@ -866,34 +910,47 @@
     monadLoggerLog loc src lvl = lift . monadLoggerLog loc src lvl
 
 healthCheck ::
-       (MonadUnliftIO m, StoreRead m)
+       (MonadUnliftIO m, StoreRead m, StoreStream m)
     => Network
     -> Manager
     -> Chain
+    -> Timeouts
     -> m HealthCheck
-healthCheck net mgr ch = do
-    n <- timeout (5 * 1000 * 1000) $ chainGetBest ch
-    b <-
-        runMaybeT $ do
-            h <- MaybeT getBestBlock
-            MaybeT $ getBlock h
-    p <- timeout (5 * 1000 * 1000) $ managerGetPeers mgr
-    let k = isNothing n || isNothing b || maybe False (not . Data.List.null) p
-        s =
+healthCheck net mgr ch tos = do
+    maybe_chain_best <- timeout (5 * 1000 * 1000) $ chainGetBest ch
+    maybe_block_best <- runMaybeT $ MaybeT . getBlock =<< MaybeT getBestBlock
+    now <- fromIntegral . systemSeconds <$> liftIO getSystemTime
+    peers <- timeout (5 * 1000 * 1000) $ managerGetPeers mgr
+    maybe_mempool_last <- runConduit $ getMempool .| mapC fst .| headC
+    let maybe_block_time_delta =
+            (now -) . fromIntegral . blockTimestamp . blockDataHeader <$>
+            maybe_block_best
+        maybe_tx_time_delta =
+            (now -) <$> maybe_mempool_last <|> maybe_block_time_delta
+        status_ok =
+            (isNothing maybe_chain_best ||
+             isNothing maybe_block_best ||
+             maybe False (not . Data.List.null) peers) &&
+            maybe False (<= blockTimeout tos) maybe_block_time_delta &&
+            maybe False (<= txTimeout tos) maybe_tx_time_delta
+        synced =
             isJust $ do
-                x <- n
-                y <- b
+                x <- maybe_chain_best
+                y <- maybe_block_best
                 guard $ nodeHeight x - blockDataHeight y <= 1
     return
         HealthCheck
-            { healthBlockBest = headerHash . blockDataHeader <$> b
-            , healthBlockHeight = blockDataHeight <$> b
-            , healthHeaderBest = headerHash . nodeHeader <$> n
-            , healthHeaderHeight = nodeHeight <$> n
-            , healthPeers = length <$> p
+            { healthBlockBest =
+                  headerHash . blockDataHeader <$> maybe_block_best
+            , healthBlockHeight = blockDataHeight <$> maybe_block_best
+            , healthHeaderBest = headerHash . nodeHeader <$> maybe_chain_best
+            , healthHeaderHeight = nodeHeight <$> maybe_chain_best
+            , healthPeers = length <$> peers
             , healthNetwork = getNetworkName net
-            , healthOK = k
-            , healthSynced = s
+            , healthOK = status_ok
+            , healthSynced = synced
+            , healthLastBlock = maybe_block_time_delta
+            , healthLastTx = maybe_tx_time_delta
             }
 
 -- | Obtain information about connected peers from peer manager process.
