diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,22 @@
 Changelog
 =========
 
+Version 0.2.11.0
+----------------
+
+*December 6, 2025*
+
+<https://github.com/mstksg/advent-of-code-api/releases/tag/v0.2.11.0>
+
+*   Add endpoint for `<year>/stats` to get current star counts. Use with care,
+    never cached.
+*   Add `inferSubmitRes`, `inferSubmitRes_` to add stats-based rank at time of
+    execution.
+*   Add `_aInferRankOnSubmission` (default `False`) to automatically tag your
+    `SubmitRes` with an inferred rank based on stats.
+
 Version 0.2.10.0
----------------
+----------------
 
 *December 1, 2025*
 
diff --git a/advent-of-code-api.cabal b/advent-of-code-api.cabal
--- a/advent-of-code-api.cabal
+++ b/advent-of-code-api.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           advent-of-code-api
-version:        0.2.10.0
+version:        0.2.11.0
 synopsis:       Advent of Code REST API bindings and servant API
 description:    Haskell bindings for Advent of Code REST API and a servant API.  Please use
                 responsibly! See README.md or "Advent" module for an introduction and
diff --git a/src/Advent.hs b/src/Advent.hs
--- a/src/Advent.hs
+++ b/src/Advent.hs
@@ -52,9 +52,14 @@
   , Part(..)
   , Day(..)
   , NextDayTime(..)
+  , DayStats(..)
+  , Stats
   , AoCOpts(..)
   , AoCUserAgent(..)
   , SubmitRes(..), showSubmitRes
+  , statsForDayPart
+  , inferSubmitRes
+  , inferSubmitRes_
   , runAoC
   , runAoC_
   , defaultAoCOpts
@@ -243,6 +248,15 @@
     AoCNextDayTime
         :: AoC NextDayTime
 
+    -- | Fetch the per-day completion stats for the current year.  Does not
+    -- require a session key.
+    --
+    -- /Cacheing rules/: Not cached.
+    --
+    -- @since 0.2.11.0
+    AoCStats
+        :: AoC Stats
+
 deriving instance Show (AoC a)
 deriving instance Typeable (AoC a)
 
@@ -255,6 +269,7 @@
 aocDay (AoCDailyLeaderboard d) = Just d
 aocDay AoCGlobalLeaderboard = Nothing
 aocDay AoCNextDayTime       = Nothing
+aocDay AoCStats             = Nothing
 
 -- | A possible (syncronous, logical, pure) error returnable from 'runAoC'.
 -- Does not cover any asynchronous or IO errors.
@@ -306,6 +321,10 @@
       -- | Throttle delay, in milliseconds.  Minimum is 1000000.  Default
       -- is 3000000 (3 seconds).
     , _aThrottle   :: Int
+      -- | Attempt to infer submission rank by fetching stats after a
+      -- correct submission that doesn't include rank information.
+      -- Default is False.
+    , _aInferRankOnSubmission :: Bool
     }
   deriving (Show, Typeable, Generic)
 
@@ -326,6 +345,7 @@
     , _aCache      = Nothing
     , _aForce      = False
     , _aThrottle   = 3000000
+    , _aInferRankOnSubmission = False
     }
 
 -- | HTTPS base of Advent of Code API.
@@ -339,14 +359,16 @@
     AoCInput  i       -> let _ :<|> r :<|> _ = adventAPIPuzzleClient aua yr i in r
     AoCSubmit i p ans -> let _ :<|> _ :<|> r = adventAPIPuzzleClient aua yr i
                          in  r (SubmitInfo p ans) <&> \(x :<|> y) -> (x, y)
-    AoCLeaderboard c  -> let _ :<|> _ :<|> _ :<|> _ :<|> r = adventAPIClient aua yr
+    AoCLeaderboard c  -> let _ :<|> _ :<|> _ :<|> _ :<|> _ :<|> r = adventAPIClient aua yr
                          in  r (PublicCode c)
-    AoCDailyLeaderboard d -> let _ :<|> _ :<|> _ :<|> r :<|> _ = adventAPIClient aua yr
+    AoCDailyLeaderboard d -> let _ :<|> _ :<|> _ :<|> _ :<|> r :<|> _ = adventAPIClient aua yr
                              in  r d
-    AoCGlobalLeaderboard  -> let _ :<|> _ :<|> r :<|> _ = adventAPIClient aua yr
+    AoCGlobalLeaderboard  -> let _ :<|> _ :<|> _ :<|> r :<|> _ :<|> _ = adventAPIClient aua yr
                              in  r
-    AoCNextDayTime        -> let r :<|> _ = adventAPIClient aua yr
+    AoCNextDayTime        -> let r :<|> _ :<|> _ :<|> _ :<|> _ :<|> _ = adventAPIClient aua yr
                              in  r
+    AoCStats              -> let _ :<|> r :<|> _ :<|> _ :<|> _ :<|> _ = adventAPIClient aua yr
+                             in  r
 
 
 -- | Cache file for a given 'AoC' command
@@ -363,6 +385,7 @@
     AoCDailyLeaderboard d  -> Just $ printf "daily/%04d/%02d.json" yr (dayInt d)
     AoCGlobalLeaderboard{} -> Just $ printf "global/%04d.json" yr
     AoCNextDayTime         -> Nothing
+    AoCStats               -> Nothing
   where
     keyDir = case sess of
       Nothing -> ""
@@ -375,7 +398,7 @@
 -- of leading and trailing whitespace and run through 'URI.encode'
 -- before submitting.
 runAoC :: AoCOpts -> AoC a -> IO (Either AoCError a)
-runAoC AoCOpts{..} a = do
+runAoC opts@AoCOpts{..} a = do
     (keyMayb, cacheDir) <- case _aCache of
       Just c  -> pure (Nothing, c)
       Nothing -> (Just _aSessionKey,) . (</> "advent-of-code-api") <$> getTemporaryDirectory
@@ -406,7 +429,12 @@
            . throttling aocThrottler (max 1000000 _aThrottle)
            $ runClientM (aocReq (Just _aUserAgent) _aYear a) =<< aocClientEnv _aSessionKey
       mcr <- maybe (throwError AoCThrottleError) pure mtr
-      either (throwError . AoCClientError) pure mcr
+      res <- either (throwError . AoCClientError) pure mcr
+      case (a, _aInferRankOnSubmission, res) of
+        (AoCSubmit d p _, True, (txt, sr)) -> do
+          sr' <- liftIO $ inferSubmitRes_ opts d p sr
+          pure (txt, sr')
+        _ -> pure res
 
 -- | A version of 'runAoC' that throws an IO exception (of type 'AoCError')
 -- upon failure, instead of an 'Either'.
@@ -415,6 +443,48 @@
 runAoC_ :: AoCOpts -> AoC a -> IO a
 runAoC_ o = either throwIO pure <=< runAoC o
 
+-- | Extract the relevant completion count for a given part on a day's stats.
+--
+-- @since 0.2.11.0
+statsForDayPart :: Day -> Part -> Stats -> Integer
+statsForDayPart d Part1 = maybe 0 dsSilver . M.lookup d
+statsForDayPart d Part2 = maybe 0 dsGold   . M.lookup d
+
+-- | If an Advent of Code submission returns 'SubCorrect' without an attached
+-- rank, attempt to infer the rank from 'AoCStats', assuming that it was just
+-- submitted and received at this moment.
+--
+-- If the response is anything other than 'SubCorrect Nothing', it is returned
+-- unchanged.
+--
+-- @since 0.2.11.0
+inferSubmitRes
+    :: AoCOpts
+    -> Day
+    -> Part
+    -> SubmitRes
+    -> IO (Either AoCError SubmitRes)
+inferSubmitRes opts d p sr = case sr of
+    SubCorrect Nothing -> do
+        stats <- runAoC opts AoCStats
+        pure $ stats >>= \st ->
+          case M.lookup d st of
+            Just _  -> Right . SubCorrect . Just $ statsForDayPart d p st
+            Nothing -> Right $ SubCorrect Nothing
+    _ -> pure $ Right sr
+
+-- | Variant of 'inferSubmitRes' that returns the original response if stats
+-- lookup fails.
+--
+-- @since 0.2.11.0
+inferSubmitRes_
+    :: AoCOpts
+    -> Day
+    -> Part
+    -> SubmitRes
+    -> IO SubmitRes
+inferSubmitRes_ opts d p sr = either (const sr) id <$> inferSubmitRes opts d p sr
+
 aocClientEnv :: String -> IO ClientEnv
 aocClientEnv s = do
     t <- getCurrentTime
@@ -473,6 +543,7 @@
             pure $ Right lb
         }
     AoCNextDayTime{} -> noCache
+    AoCStats{} -> noCache
   where
     expectedParts :: Set Part
     expectedParts
diff --git a/src/Advent/API.hs b/src/Advent/API.hs
--- a/src/Advent/API.hs
+++ b/src/Advent/API.hs
@@ -113,6 +113,9 @@
 -- | Interpret a response as a list of HTML 'T.Text' found in @<script>@ tags.
 type Scripts = HTMLTags "script"
 
+-- | Interpret a response as a list of HTML 'T.Text' found in @<pre>@ tags.
+type Pres = HTMLTags "pre"
+
 -- | Class for interpreting a list of 'T.Text' in tags to some desired
 -- output.
 --
@@ -229,6 +232,9 @@
           where
             t' = "var " <> t <> " = "
 
+instance FromTags "pre" Stats where
+    fromTags _ = listToMaybe . mapMaybe parseStats
+
 -- | A structured user agent, based on
 -- <https://www.reddit.com/r/adventofcode/comments/z9dhtd/please_include_your_contact_info_in_the_useragent/>
 data AoCUserAgent = AoCUserAgent
@@ -247,6 +253,7 @@
       Header "User-Agent" AoCUserAgent
    :> Capture "year" Integer
    :> (Get '[Scripts] NextDayTime
+  :<|> "stats" :> Get '[Pres] Stats
   :<|> "day" :> Capture "day" Day
              :> (Get '[Articles] (Map Part Text)
             :<|> "input" :> Get '[RawText] Text
@@ -273,6 +280,7 @@
     :: Maybe AoCUserAgent
     -> Integer
     -> ClientM NextDayTime
+  :<|> ClientM Stats
   :<|> (Day -> ClientM (Map Part Text) :<|> ClientM Text :<|> (SubmitInfo -> ClientM (Text :<|> SubmitRes)) )
   :<|> ClientM GlobalLeaderboard
   :<|> (Day -> ClientM DailyLeaderboard)
@@ -288,7 +296,34 @@
     -> ClientM (Map Part Text) :<|> ClientM Text :<|> (SubmitInfo -> ClientM (Text :<|> SubmitRes))
 adventAPIPuzzleClient aua y = pis
   where
-    _ :<|> pis :<|> _ = adventAPIClient aua y
+    _ :<|> _ :<|> pis :<|> _ = adventAPIClient aua y
+
+parseStats :: Text -> Maybe Stats
+parseStats = fmap M.fromList . traverse parseStatLine . filter asBranch . H.parseTree
+  where
+    asBranch TagBranch{} = True
+    asBranch _           = False
+
+parseStatLine :: TagTree Text -> Maybe (Day, DayStats)
+parseStatLine (TagBranch _ _ cs) = do
+    dayTxt <- listToMaybe [t | TagLeaf (H.TagText t) <- cs, not (T.null (T.strip t))]
+    dy     <- mkDay =<< readMaybe (T.unpack (T.strip dayTxt))
+    gold   <- findNum "stats-both" cs
+    silver <- findNum "stats-firstonly" cs
+    pure (dy, DayStats gold silver)
+  where
+    findNum cls = listToMaybe . mapMaybe (go cls)
+    go cls (TagBranch "span" attr inner) = do
+      guard $ ("class", cls) `elem` attr
+      readMaybe . T.unpack . T.strip $ innerText inner
+    go _ _ = Nothing
+parseStatLine _ = Nothing
+
+innerText :: [TagTree Text] -> Text
+innerText = T.concat . mapMaybe go . H.universeTree
+  where
+    go (TagLeaf (H.TagText t)) = Just t
+    go _                       = Nothing
 
 userNameNaked :: [TagTree Text] -> Maybe Text
 userNameNaked = (listToMaybe .) . mapMaybe $ \x -> do
diff --git a/src/Advent/Types.hs b/src/Advent/Types.hs
--- a/src/Advent/Types.hs
+++ b/src/Advent/Types.hs
@@ -43,6 +43,8 @@
   , GlobalLeaderboard(..)
   , GlobalLeaderboardMember(..)
   , NextDayTime(..)
+  , DayStats(..)
+  , Stats
   -- * Util
   , mkDay, mkDay_, dayInt
   , _DayInt, pattern DayInt
@@ -259,6 +261,20 @@
 data NextDayTime = NextDayTime Day Int
                  | NoNextDayTime
   deriving (Show, Eq, Ord, Typeable, Generic)
+
+-- | Stats for a single day on the event stats page.
+--
+-- @since 0.2.11.0
+data DayStats = DayStats
+    { dsGold   :: Integer   -- ^ Users who completed both parts
+    , dsSilver :: Integer   -- ^ Users who only completed the first part
+    }
+  deriving (Show, Read, Eq, Ord, Typeable, Generic)
+
+-- | Stats for all days on the event stats page.
+--
+-- @since 0.2.11.0
+type Stats = Map Day DayStats
 
 instance ToHttpApiData Part where
     toUrlPiece = T.pack . show . partInt
