diff --git a/app/src/main/assets/error.html b/app/src/main/assets/error.html
new file mode 100644
index 0000000..3e35b65
--- /dev/null
+++ b/app/src/main/assets/error.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+ Connection Error
+
+
+
+
+
📡
+
Connection Problem
+
Unable to load the page. Please check your internet connection and try again.
+
+
+
+
+
+
diff --git a/app/src/main/kotlin/farm/hobbs/kioskbrowser/ErrorHandler.kt b/app/src/main/kotlin/farm/hobbs/kioskbrowser/ErrorHandler.kt
new file mode 100644
index 0000000..d6d7b9a
--- /dev/null
+++ b/app/src/main/kotlin/farm/hobbs/kioskbrowser/ErrorHandler.kt
@@ -0,0 +1,80 @@
+package farm.hobbs.kioskbrowser
+
+import android.webkit.WebResourceError
+import android.webkit.WebResourceRequest
+import android.webkit.WebView
+
+/**
+ * Handles WebView errors with user-friendly error pages.
+ *
+ * Usage in WebViewClient:
+ * ```
+ * override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
+ * ErrorHandler.handleError(view, request, error)
+ * }
+ * ```
+ */
+object ErrorHandler {
+
+ private const val ERROR_PAGE = "file:///android_asset/error.html"
+
+ /**
+ * Network error codes that should show the error page
+ */
+ private val NETWORK_ERRORS = setOf(
+ android.webkit.WebViewClient.ERROR_HOST_LOOKUP,
+ android.webkit.WebViewClient.ERROR_CONNECT,
+ android.webkit.WebViewClient.ERROR_TIMEOUT,
+ android.webkit.WebViewClient.ERROR_IO,
+ android.webkit.WebViewClient.ERROR_UNKNOWN
+ )
+
+ /**
+ * Handle WebView errors - show error page for main frame network errors
+ */
+ fun handleError(
+ view: WebView?,
+ request: WebResourceRequest?,
+ error: WebResourceError?
+ ): Boolean {
+ // Only handle main frame errors
+ if (request?.isForMainFrame != true) return false
+
+ val errorCode = error?.errorCode ?: return false
+
+ // Show error page for network errors
+ if (errorCode in NETWORK_ERRORS || errorCode < 0) {
+ view?.loadUrl("$ERROR_PAGE?code=$errorCode")
+ return true
+ }
+
+ return false
+ }
+
+ /**
+ * Handle HTTP errors (4xx, 5xx)
+ */
+ fun handleHttpError(
+ view: WebView?,
+ request: WebResourceRequest?,
+ statusCode: Int
+ ): Boolean {
+ // Only handle main frame errors
+ if (request?.isForMainFrame != true) return false
+
+ // Show error page for server errors
+ if (statusCode >= 500) {
+ view?.loadUrl("$ERROR_PAGE?code=$statusCode")
+ return true
+ }
+
+ return false
+ }
+
+ /**
+ * Check if current URL is the error page
+ */
+ fun isErrorPage(url: String?): Boolean {
+ return url?.startsWith(ERROR_PAGE.substringBefore("?")) == true
+ }
+}
diff --git a/app/src/test/kotlin/farm/hobbs/kioskbrowser/ErrorHandlerTest.kt b/app/src/test/kotlin/farm/hobbs/kioskbrowser/ErrorHandlerTest.kt
new file mode 100644
index 0000000..e4531e4
--- /dev/null
+++ b/app/src/test/kotlin/farm/hobbs/kioskbrowser/ErrorHandlerTest.kt
@@ -0,0 +1,29 @@
+package farm.hobbs.kioskbrowser
+
+import org.junit.Assert.*
+import org.junit.Test
+
+/**
+ * Unit tests for ErrorHandler utility
+ */
+class ErrorHandlerTest {
+
+ @Test
+ fun `isErrorPage returns true for error page URL`() {
+ assertTrue(ErrorHandler.isErrorPage("file:///android_asset/error.html"))
+ assertTrue(ErrorHandler.isErrorPage("file:///android_asset/error.html?code=-2"))
+ }
+
+ @Test
+ fun `isErrorPage returns false for regular URLs`() {
+ assertFalse(ErrorHandler.isErrorPage("https://hobbs.farm"))
+ assertFalse(ErrorHandler.isErrorPage("https://google.com"))
+ assertFalse(ErrorHandler.isErrorPage(null))
+ }
+
+ @Test
+ fun `isErrorPage returns false for similar but different URLs`() {
+ assertFalse(ErrorHandler.isErrorPage("file:///android_asset/other.html"))
+ assertFalse(ErrorHandler.isErrorPage("https://error.html"))
+ }
+}