diff --git a/.env.example b/.env.example
index 9eefb4d..927ff37 100644
--- a/.env.example
+++ b/.env.example
@@ -16,3 +16,7 @@
# Password required to view the site (login page at /login).
# Leave empty/unset to disable the gate.
SITE_PASSWORD=""
+
+# Umami analytics (optional). Omit NEXT_PUBLIC_UMAMI_WEBSITE_ID to disable tracking.
+# NEXT_PUBLIC_UMAMI_WEBSITE_ID="your-website-uuid"
+# NEXT_PUBLIC_UMAMI_SCRIPT_URL="https://cloud.umami.is/script.js"
diff --git a/README.md b/README.md
index 1d6b4ce..3597f38 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Medscribe Web
-Marketing homepage for [Medscribe](../README.md) — a privacy-first, on-device medical companion for iOS.
+Marketing homepage for [Medscribe](../README.md) — a privacy-first, on-device medical companion for iOS and Android.
Built with [create-t3-app](https://create.t3.gg/) (Next.js + TypeScript + Tailwind). Single-page site; no database or API routes.
@@ -15,6 +15,15 @@ bun run dev
Open [http://localhost:3000](http://localhost:3000).
+### Analytics (optional)
+
+Set in `.env` (see `.env.example`):
+
+- `NEXT_PUBLIC_UMAMI_WEBSITE_ID` — website UUID from your Umami dashboard
+- `NEXT_PUBLIC_UMAMI_SCRIPT_URL` — optional; defaults to `https://cloud.umami.is/script.js` (use your self-hosted URL if needed)
+
+Leave the website ID unset to disable tracking (default for local dev).
+
## Build
```bash
@@ -26,10 +35,10 @@ Screenshots live in `public/screenshots/`. They are wrapped in an iPhone-style f
### Capturing raw screenshots for the site
-Export **in-app content only** from the simulator or device — no simulator chrome or macOS capture toolbar. A normal in-app iOS status bar/tab bar is fine.
+Export **in-app content only** from the simulator or device — no simulator chrome or macOS capture toolbar. A normal in-app status bar/tab bar is fine.
-1. Run the app on **iPhone 17 Pro** (or 16 Pro) simulator or device.
-2. Capture each screen (⌘S in Simulator saves to Desktop).
+1. Run the app on **iPhone 17 Pro** (or 16 Pro) simulator or device, or on an **Android** emulator/device.
+2. Capture each screen (⌘S in Simulator saves to Desktop; `adb exec-out screencap -p` on Android).
3. Drop PNGs into `public/screenshots/` and update paths in `src/app/page.tsx` / `src/components/feature-showcase.tsx`.
The frame dimensions assume tall iPhone screenshots and are controlled in `src/components/phone-mockup.tsx`. Use `captureMode="simulator"` only for old captures that already include device chrome.
diff --git a/src/app/(marketing)/executive-summary/page.tsx b/src/app/(marketing)/executive-summary/page.tsx
index 0fc83e0..aed9a8d 100644
--- a/src/app/(marketing)/executive-summary/page.tsx
+++ b/src/app/(marketing)/executive-summary/page.tsx
@@ -9,6 +9,7 @@ import { MedscribeLogo } from "~/components/medscribe-logo";
import { PhoneMockup } from "~/components/phone-mockup";
import { PrintButton } from "~/components/print-button";
import { SectionLabel } from "~/components/section-label";
+import { BETA_FOOTER_NOTE, BETA_SUMMARY } from "~/lib/beta";
import { Badge } from "~/components/ui/badge";
import {
Card,
@@ -326,9 +327,7 @@ export default function ExecutiveSummaryPage() {
{/* Beta */}
- A beta is available on iOS through TestFlight. Everything runs
- privately on the device, so no health data leaves the phone. If
- you'd like to try it, reach out.
+ {BETA_SUMMARY} If you'd like to try it, reach out.
@@ -459,9 +458,7 @@ export default function ExecutiveSummaryPage() {
>
diff --git a/src/app/(marketing)/page.tsx b/src/app/(marketing)/page.tsx
index e8ceed6..b235ad3 100644
--- a/src/app/(marketing)/page.tsx
+++ b/src/app/(marketing)/page.tsx
@@ -13,6 +13,11 @@ import {
import { FeatureShowcase } from "~/components/feature-showcase";
import { PhoneMockup } from "~/components/phone-mockup";
import { SectionLabel } from "~/components/section-label";
+import {
+ BETA_CTA_BODY,
+ BETA_CTA_TITLE,
+ BETA_INVITE_MAILTO,
+} from "~/lib/beta";
import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button";
import {
@@ -119,8 +124,9 @@ export default function HomePage() {
- On TestFlight
- iOS
+ Beta available
+ iOS · TestFlight
+ Android · Play internalEmergency-readyNo cloud AI
@@ -319,11 +325,9 @@ export default function HomePage() {
- Try Medscribe on iOS
+ {BETA_CTA_TITLE}
- The app is live on TestFlight. Reach out for an invite if
- you're managing medications, visits, or emergency context for
- someone you love.
+ {BETA_CTA_BODY}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index ecc238f..c4283e2 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -3,6 +3,8 @@ import "~/styles/globals.css";
import { type Metadata } from "next";
import { Instrument_Sans, Playfair_Display } from "next/font/google";
+import { UmamiAnalytics } from "~/components/umami-analytics";
+
const instrumentSans = Instrument_Sans({
subsets: ["latin"],
variable: "--font-instrument-sans",
@@ -42,7 +44,10 @@ export default function RootLayout({
}: Readonly<{ children: React.ReactNode }>) {
return (
- {children}
+
+ {children}
+
+
);
}
diff --git a/src/components/umami-analytics.tsx b/src/components/umami-analytics.tsx
new file mode 100644
index 0000000..42cc0ba
--- /dev/null
+++ b/src/components/umami-analytics.tsx
@@ -0,0 +1,25 @@
+import Script from "next/script";
+
+import { env } from "~/env";
+
+const DEFAULT_UMAMI_SCRIPT_URL = "https://cloud.umami.is/script.js";
+
+/**
+ * Privacy-friendly page analytics via Umami. Enabled when
+ * `NEXT_PUBLIC_UMAMI_WEBSITE_ID` is set in `.env`.
+ */
+export function UmamiAnalytics() {
+ const websiteId = env.NEXT_PUBLIC_UMAMI_WEBSITE_ID;
+ if (!websiteId) return null;
+
+ const src = env.NEXT_PUBLIC_UMAMI_SCRIPT_URL ?? DEFAULT_UMAMI_SCRIPT_URL;
+
+ return (
+
+ );
+}
diff --git a/src/env.js b/src/env.js
index 05877b7..6bd80c8 100644
--- a/src/env.js
+++ b/src/env.js
@@ -18,7 +18,10 @@ export const env = createEnv({
* `NEXT_PUBLIC_`.
*/
client: {
- // NEXT_PUBLIC_CLIENTVAR: z.string(),
+ /** Umami website ID — omit to disable analytics. */
+ NEXT_PUBLIC_UMAMI_WEBSITE_ID: z.string().optional(),
+ /** Umami script URL (defaults to Umami Cloud). */
+ NEXT_PUBLIC_UMAMI_SCRIPT_URL: z.string().url().optional(),
},
/**
@@ -28,7 +31,8 @@ export const env = createEnv({
runtimeEnv: {
NODE_ENV: process.env.NODE_ENV,
SITE_PASSWORD: process.env.SITE_PASSWORD,
- // NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
+ NEXT_PUBLIC_UMAMI_WEBSITE_ID: process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID,
+ NEXT_PUBLIC_UMAMI_SCRIPT_URL: process.env.NEXT_PUBLIC_UMAMI_SCRIPT_URL,
},
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
diff --git a/src/lib/beta.ts b/src/lib/beta.ts
new file mode 100644
index 0000000..27215c4
--- /dev/null
+++ b/src/lib/beta.ts
@@ -0,0 +1,15 @@
+/** Shared beta / early-access copy for the marketing site. */
+
+export const BETA_SUMMARY =
+ "A beta is available on iOS (TestFlight) and Android (Google Play internal testing). Everything runs privately on the device, so no health data leaves the phone.";
+
+export const BETA_CTA_TITLE = "Try Medscribe";
+
+export const BETA_CTA_BODY =
+ "The app is in beta on iOS and Android. Reach out for an invite if you're managing medications, visits, or emergency context for someone you love.";
+
+export const BETA_INVITE_MAILTO =
+ "mailto:sean@soconnor.dev?subject=Medscribe%20beta%20invite%20request&body=Hi%20Sean%2C%0D%0A%0D%0AI%27d%20like%20a%20beta%20invite%20to%20try%20Medscribe%20(iOS%20or%20Android).%20I%27m%20managing%20medications%2C%20visits%2C%20or%20emergency%20context%20for%20someone%20I%20care%20for.%0D%0A%0D%0AThanks%21";
+
+export const BETA_FOOTER_NOTE =
+ "Beta on iOS (TestFlight) and Android (Google Play internal testing).";