diff --git a/Plugin/Framework/App/Response/Http.php b/Plugin/Framework/App/Response/Http.php
new file mode 100644
index 0000000..6d8b694
--- /dev/null
+++ b/Plugin/Framework/App/Response/Http.php
@@ -0,0 +1,161 @@
+config->getType() !== Config::BUILT_IN || !$this->isEnabled()) {
+ return;
+ }
+
+ $cacheControlHeader = $subject->getHeader('Cache-Control');
+ if (!$cacheControlHeader) {
+ return;
+ }
+
+ $cacheControl = $cacheControlHeader->getFieldValue();
+ $requestURI = ltrim($this->request->getRequestURI(), '/');
+
+ if ($this->isRequestCacheable($cacheControl) && !$this->isRequestInExcludePatterns($requestURI)) {
+ $this->isRequestCacheable = true;
+ }
+ }
+
+ /**
+ * Update cache headers after setting no-cache headers
+ *
+ * @param \Magento\Framework\App\Response\Http $subject
+ * @param mixed $result
+ * @return mixed
+ */
+ public function afterSetNoCacheHeaders(\Magento\Framework\App\Response\Http $subject, $result)
+ {
+ if ($this->config->getType() !== Config::BUILT_IN || !$this->isEnabled()) {
+ return $result;
+ }
+
+ $cacheControlHeader = $subject->getHeader('Cache-Control');
+ if (!$cacheControlHeader) {
+ return $result;
+ }
+
+ if ($this->isRequestCacheable === true) {
+ $cacheControlHeader = $subject->getHeader('Cache-Control');
+ $cacheControlHeader->removeDirective('no-store');
+ }
+ $this->isRequestCacheable = false;
+
+ return $result;
+ }
+
+ /**
+ * Check if request is cacheable based on cache control header
+ *
+ * @param string $cacheControl
+ * @return bool
+ */
+ private function isRequestCacheable(string $cacheControl): bool
+ {
+ return (bool) preg_match('/public.*s-maxage=(\d+)/', $cacheControl);
+ }
+
+ /**
+ * Check if the request URI contains any excluded URL patterns (case-insensitive, partial match).
+ *
+ * @param string $requestURI
+ * @return bool
+ */
+ private function isRequestInExcludePatterns(string $requestURI): bool
+ {
+ $patterns = $this->getConfig(self::XML_PATH_EXCLUDE_URL_PATTERNS);
+
+ if (empty($patterns)) {
+ return false;
+ }
+
+ foreach ($this->parseExcludePatterns($patterns) as $pattern) {
+ if ($pattern !== '' && mb_stripos($requestURI, $pattern, 0, 'UTF-8') !== false) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Parse exclude patterns from config string.
+ *
+ * @param string $patterns
+ * @return array
+ */
+ private function parseExcludePatterns(string $patterns): array
+ {
+ return array_filter(array_map('trim', explode("\n", $patterns)));
+ }
+
+ /**
+ * Check if BFCache is enabled
+ *
+ * @return bool
+ */
+ private function isEnabled(): bool
+ {
+ return $this->scopeConfig->isSetFlag(
+ self::XML_PATH_ENABLE,
+ ScopeInterface::SCOPE_STORE
+ );
+ }
+
+ /**
+ * Get configuration value by path
+ *
+ * @param string $configPath
+ * @param int|string|null $store
+ * @return string
+ */
+ private function getConfig(string $configPath, $store = null): string
+ {
+ return (string)$this->scopeConfig->getValue(
+ $configPath,
+ ScopeInterface::SCOPE_STORE,
+ $store
+ );
+ }
+}
diff --git a/ViewModel/BfCache.php b/ViewModel/BfCache.php
new file mode 100644
index 0000000..53f1a55
--- /dev/null
+++ b/ViewModel/BfCache.php
@@ -0,0 +1,71 @@
+scopeConfig->isSetFlag(
+ self::XML_PATH_ENABLE_USER_INTERACTION_RELOAD_MINICART,
+ ScopeInterface::SCOPE_STORE
+ );
+ }
+
+ /**
+ * Check if mobile menu should auto-close
+ *
+ * @return bool
+ */
+ public function autoCloseMenuMobile(): bool
+ {
+ return $this->scopeConfig->isSetFlag(
+ self::XML_PATH_AUTO_CLOSE_MENU_MOBILE,
+ ScopeInterface::SCOPE_STORE
+ );
+ }
+
+ /**
+ * Check if customer is logged in
+ *
+ * @return bool
+ */
+ public function isCustomerLoggedIn(): bool
+ {
+ return (bool) $this->httpContext->getValue(CustomerContext::CONTEXT_AUTH);
+ }
+}
diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml
index 974bf87..83f8ce5 100644
--- a/etc/adminhtml/system.xml
+++ b/etc/adminhtml/system.xml
@@ -51,5 +51,61 @@
+
Use the blacklist below if you have custom cached URLs that load private data via JavaScript.
+ ]]>customercheckoutaccount
+ ]]>