diff --git a/mobile/app/(app)/(tabs)/pets.tsx b/mobile/app/(app)/(tabs)/pets.tsx
index 50bfcc4..7b8e36c 100644
--- a/mobile/app/(app)/(tabs)/pets.tsx
+++ b/mobile/app/(app)/(tabs)/pets.tsx
@@ -4,6 +4,7 @@ import { useRouter } from "expo-router";
import { useTranslation } from "react-i18next";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import Constants from "expo-constants";
+import * as Updates from "expo-updates";
import * as Sentry from "@sentry/react-native";
import { useAuth } from "@clerk/expo";
import { Check, Sun, Moon, SunMoon } from "lucide-react-native";
@@ -216,12 +217,41 @@ function PetSuggestionsSection() {
);
}
-/** Links to the fixed-language legal pages (see root CLAUDE.md: not localized, always German) plus the installed app version, for anyone who needs to reach them without going through the web app. */
+/**
+ * Reads expo-updates' launch info defensively — these are plain native-module-backed exports, not
+ * function calls, but a stripped/misconfigured build (e.g. a dev client without the module properly
+ * linked) throwing here would otherwise crash LegalSection's render, and LegalSection sits outside
+ * FooterErrorBoundary (that only wraps LogoutSection below it), so there's no fallback UI to catch it.
+ * Not meaningful on the web target (the web shim always reports isEmbeddedLaunch=false/updateId=null) —
+ * this app has no shipped web build (`eas update` only ever runs `--platform android`, see README), so
+ * that's a dead branch today, not a live bug.
+ */
+function readOtaUpdateId(): { isEmbeddedLaunch: boolean; updateId: string | null } {
+ try {
+ return { isEmbeddedLaunch: Updates.isEmbeddedLaunch, updateId: Updates.updateId };
+ } catch {
+ return { isEmbeddedLaunch: false, updateId: null };
+ }
+}
+
+/**
+ * Links to the fixed-language legal pages (see root CLAUDE.md: not localized, always German) plus
+ * the installed app version and current OTA update state, for anyone who needs to reach them without
+ * going through the web app. The OTA suffix exists so a support conversation ("did the update actually
+ * arrive?") can be answered by reading this screen instead of guessing — compare the short id shown
+ * here against the "Android update ID" an `eas update` publish prints.
+ */
function LegalSection() {
const { t } = useTranslation();
const { colors } = useTheme();
const styles = useMemo(() => makeStyles(colors), [colors]);
const version = Constants.expoConfig?.version ?? "?";
+ const { isEmbeddedLaunch, updateId } = readOtaUpdateId();
+ const ota = isEmbeddedLaunch
+ ? t("pets.otaEmbedded")
+ : updateId
+ ? t("pets.otaId", { id: updateId.slice(0, 8) })
+ : t("pets.otaUnknown");
const links = [
{ label: t("pets.legalImpressum"), path: "impressum" },
@@ -237,7 +267,7 @@ function LegalSection() {
{link.label}
))}
- {t("pets.versionLabel", { version })}
+ {t("pets.versionLabel", { version, ota })}
);
}
diff --git a/mobile/src/i18n/locales/de.json b/mobile/src/i18n/locales/de.json
index b32f9ec..d2e5120 100644
--- a/mobile/src/i18n/locales/de.json
+++ b/mobile/src/i18n/locales/de.json
@@ -209,7 +209,10 @@
"legalChildSafety": "Kinderschutz",
"petSuggestionsTitle": "Tier-Vorschläge",
"petSuggestionsLabel": "Erhalte gelegentlich eine Benachrichtigung zu einem Tier, das dir gefallen könnte.",
- "versionLabel": "Version {{version}}",
+ "versionLabel": "Version {{version}} - {{ota}}",
+ "otaId": "OTA {{id}}",
+ "otaEmbedded": "Build (kein OTA)",
+ "otaUnknown": "OTA unbekannt",
"logoutButton": "Abmelden",
"logoutConfirmTitle": "Abmelden?",
"logoutConfirmMessage": "Du wirst von deinem Konto abgemeldet und zum Login zurückgeschickt."
diff --git a/mobile/src/i18n/locales/en.json b/mobile/src/i18n/locales/en.json
index 11aec4a..6287050 100644
--- a/mobile/src/i18n/locales/en.json
+++ b/mobile/src/i18n/locales/en.json
@@ -209,7 +209,10 @@
"legalChildSafety": "Child Safety Standards",
"petSuggestionsTitle": "Pet suggestions",
"petSuggestionsLabel": "Occasionally get notified about a pet you might like.",
- "versionLabel": "Version {{version}}",
+ "versionLabel": "Version {{version}} - {{ota}}",
+ "otaId": "OTA {{id}}",
+ "otaEmbedded": "Build (no OTA)",
+ "otaUnknown": "OTA unknown",
"logoutButton": "Log out",
"logoutConfirmTitle": "Log out?",
"logoutConfirmMessage": "You'll be signed out of your account and sent back to the login screen."