diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,6 +1,8 @@
 # Changelog for hs-opentelemetry-instrumentation-yesod
 
-## Unreleased changes
+## 0.1.1.0
+
+- Set exception details when using WAI and Yesod instrumentation together (#121).
 
 ## 0.1.0.0
 
diff --git a/hs-opentelemetry-instrumentation-yesod.cabal b/hs-opentelemetry-instrumentation-yesod.cabal
--- a/hs-opentelemetry-instrumentation-yesod.cabal
+++ b/hs-opentelemetry-instrumentation-yesod.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.35.2.
+-- This file has been generated from package.yaml by hpack version 0.36.0.
 --
 -- see: https://github.com/sol/hpack
 
 name:               hs-opentelemetry-instrumentation-yesod
-version:            0.1.0.0
+version:            0.1.1.0
 synopsis:           Yesod middleware for providing OpenTelemetry instrumentation
 description:        Please see the README on GitHub at <https://github.com/iand675/hs-opentelemetry/tree/main/instrumentation/yesod#readme>
 category:           OpenTelemetry, Web
@@ -13,7 +13,7 @@
 bug-reports:        https://github.com/iand675/hs-opentelemetry/issues
 author:             Ian Duncan, Jade Lovelace
 maintainer:         ian@iankduncan.com
-copyright:          2023 Ian Duncan, Mercury Technologies
+copyright:          2024 Ian Duncan, Mercury Technologies
 license:            BSD3
 license-file:       LICENSE
 build-type:         Simple
@@ -35,33 +35,9 @@
   ghc-options: -Wall
   build-depends:
       base >=4.7 && <5
-    , hs-opentelemetry-api ==0.1.*
+    , hs-opentelemetry-api ==0.2.*
     , hs-opentelemetry-instrumentation-wai >=0.0.1 && <0.2
     , microlens
-    , mtl
-    , template-haskell
-    , text
-    , unliftio
-    , unordered-containers
-    , wai
-    , yesod-core
-  default-language: Haskell2010
-
-test-suite hs-opentelemetry-instrumentation-yesod-test
-  type: exitcode-stdio-1.0
-  main-is: Spec.hs
-  other-modules:
-      Paths_hs_opentelemetry_instrumentation_yesod
-  hs-source-dirs:
-      test
-  ghc-options: -threaded -rtsopts -with-rtsopts=-N
-  build-depends:
-      base >=4.7 && <5
-    , hs-opentelemetry-api ==0.1.*
-    , hs-opentelemetry-instrumentation-wai >=0.0.1 && <0.2
-    , hs-opentelemetry-instrumentation-yesod
-    , microlens
-    , mtl
     , template-haskell
     , text
     , unliftio
diff --git a/src/OpenTelemetry/Instrumentation/Yesod.hs b/src/OpenTelemetry/Instrumentation/Yesod.hs
--- a/src/OpenTelemetry/Instrumentation/Yesod.hs
+++ b/src/OpenTelemetry/Instrumentation/Yesod.hs
@@ -1,9 +1,16 @@
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE TemplateHaskell #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
+{- |
+[New HTTP semantic conventions have been declared stable.](https://opentelemetry.io/blog/2023/http-conventions-declared-stable/#migration-plan) Opt-in by setting the environment variable OTEL_SEMCONV_STABILITY_OPT_IN to
+- "http" - to use the stable conventions
+- "http/dup" - to emit both the old and the stable conventions
+Otherwise, the old conventions will be used. The stable conventions will replace the old conventions in the next major release of this library.
+-}
 module OpenTelemetry.Instrumentation.Yesod (
   -- * Middleware functionality
   openTelemetryYesodMiddleware,
@@ -16,6 +23,7 @@
   handlerEnvL,
 ) where
 
+import Control.Monad (when)
 import qualified Data.HashMap.Strict as H
 import Data.List (intercalate)
 import Data.Maybe (catMaybes)
@@ -26,9 +34,8 @@
 import Lens.Micro
 import Network.Wai (requestHeaders)
 import qualified OpenTelemetry.Context as Context
-import OpenTelemetry.Context.ThreadLocal
-import OpenTelemetry.Contrib.SpanTraversals
 import OpenTelemetry.Instrumentation.Wai (requestContext)
+import OpenTelemetry.SemanticsConfig
 import OpenTelemetry.Trace.Core hiding (inSpan, inSpan', inSpan'')
 import OpenTelemetry.Trace.Monad
 import UnliftIO.Exception
@@ -50,7 +57,7 @@
 instance MonadTracer (HandlerFor site) where
   getTracer = do
     tp <- getGlobalTracerProvider
-    OpenTelemetry.Trace.Core.getTracer tp "hs-opentelemetry-instrumentation-yesod" tracerOptions
+    pure $ makeTracer tp $detectInstrumentationLibrary tracerOptions
 
 
 {- | Template Haskell to generate a function named routeToRendererFunction.
@@ -174,11 +181,9 @@
           pieces -> pieces
       , case frDispatch of
           Methods {..} ->
-            concat
-              [ case methodsMulti of
-                  Nothing -> []
-                  Just t -> ["/+", t]
-              ]
+            case methodsMulti of
+              Nothing -> []
+              Just t -> ["/+", t]
           Subsite {} -> []
       ]
   where
@@ -210,20 +215,31 @@
 openTelemetryYesodMiddleware rr m = do
   req <- waiRequest
   mr <- getCurrentRoute
+  semanticsOptions <- liftIO getSemanticsOptions
   let mspan = requestContext req >>= Context.lookupSpan
-      sharedAttributes = H.fromList $
-        ("http.framework", toAttribute ("yesod" :: Text))
-          : catMaybes
-            [ do
-                r <- mr
-                pure ("http.route", toAttribute $ pathRender rr r)
-            , do
-                r <- mr
-                pure ("http.handler", toAttribute $ nameRender rr r)
-            , do
-                ff <- lookup "X-Forwarded-For" $ requestHeaders req
-                pure ("http.client_ip", toAttribute $ T.decodeUtf8 ff)
-            ]
+      sharedAttributes =
+        H.fromList $
+          ("http.framework", toAttribute ("yesod" :: Text))
+            : catMaybes
+              [ do
+                  r <- mr
+                  Just ("http.route", toAttribute $ pathRender rr r)
+              , do
+                  r <- mr
+                  Just ("http.handler", toAttribute $ nameRender rr r)
+              , do
+                  ff <- lookup "X-Forwarded-For" $ requestHeaders req
+                  case httpOption semanticsOptions of
+                    Stable -> Just ("client.address", toAttribute $ T.decodeUtf8 ff)
+                    StableAndOld -> Just ("client.address", toAttribute $ T.decodeUtf8 ff)
+                    Old -> Nothing
+              , do
+                  ff <- lookup "X-Forwarded-For" $ requestHeaders req
+                  case httpOption semanticsOptions of
+                    Stable -> Nothing
+                    StableAndOld -> Just ("http.client_ip", toAttribute $ T.decodeUtf8 ff)
+                    Old -> Just ("http.client_ip", toAttribute $ T.decodeUtf8 ff)
+              ]
       args =
         defaultSpanArguments
           { kind = maybe Server (const Internal) mspan
@@ -231,18 +247,33 @@
           }
   case mspan of
     Nothing -> do
-      eResult <- inSpan' (maybe "notFound" (\r -> nameRender rr r) mr) args $ \_s -> do
+      eResult <- inSpan' (maybe "notFound" (nameRender rr) mr) args $ \_s -> do
         catch (Right <$> m) $ \e -> do
-          -- We want to mark the span as an error if it's an InternalError,
-          -- the other HCError values are 4xx status codes which don't
-          -- really count as a server error in OpenTelemetry spec parlance.
-          case e of
-            HCError (InternalError _) -> throwIO e
-            _ -> pure ()
+          when (isInternalError e) $ throwIO e
           pure (Left (e :: HandlerContents))
       case eResult of
         Left hc -> throwIO hc
         Right normal -> pure normal
     Just waiSpan -> do
       addAttributes waiSpan sharedAttributes
-      m
+
+      -- Explicitly record any exceptions here. When Yesod is in use, exceptions
+      -- are handled as error-pages before reaching the WAI middleware's inSpan,
+      -- meaning the exception details would not be otherwise attached.
+      withException m $ \ex -> do
+        when (shouldMarkException ex) $ do
+          recordException waiSpan mempty Nothing ex
+          setStatus waiSpan $ Error $ T.pack $ displayException ex
+
+
+shouldMarkException :: SomeException -> Bool
+shouldMarkException = maybe True isInternalError . fromException
+
+
+-- We want to mark the span as an error if it's an InternalError, the other
+-- HCError values are 4xx status codes which don't really count as a server
+-- error in OpenTelemetry spec parlance.
+isInternalError :: HandlerContents -> Bool
+isInternalError = \case
+  HCError (InternalError _) -> True
+  _ -> False
diff --git a/test/Spec.hs b/test/Spec.hs
deleted file mode 100644
--- a/test/Spec.hs
+++ /dev/null
@@ -1,3 +0,0 @@
-
-main :: IO ()
-main = putStrLn "Test suite not yet implemented"
