From 71fd06143e8444e8edf2a29188a790642c499871 Mon Sep 17 00:00:00 2001 From: Vishakh Date: Mon, 4 May 2026 16:20:36 -0400 Subject: [PATCH 1/3] Added Google Ads tag. --- app/layout.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/layout.tsx b/app/layout.tsx index 9de87cd..768fa5b 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -87,6 +87,7 @@ export default function RootLayout({ gtag('config', 'G-HP3FB0GX80', { anonymize_ip: true, }); + gtag('config', 'AW-777857829'); `} {/* Reddit Pixel */} From be99be15dbc703b3eceab15619748026c2d0f197 Mon Sep 17 00:00:00 2001 From: Vishakh Date: Thu, 7 May 2026 10:49:10 -0400 Subject: [PATCH 2/3] Fine tuned GA4 events. --- app/components/AuthProvider.tsx | 3 ++- app/components/LLMChatInline.tsx | 2 +- app/components/LLMCommentaryModal.tsx | 2 ++ app/components/StudyResultReveal.tsx | 3 ++- app/dna-chat/page.tsx | 5 +++++ app/explore/page.tsx | 5 +++-- app/overview-report/page.tsx | 5 +++++ lib/analytics.ts | 29 ++++++++++++++++++++++----- 8 files changed, 44 insertions(+), 10 deletions(-) diff --git a/app/components/AuthProvider.tsx b/app/components/AuthProvider.tsx index a0c9772..33fcabc 100644 --- a/app/components/AuthProvider.tsx +++ b/app/components/AuthProvider.tsx @@ -4,7 +4,7 @@ import { DynamicContextProvider, DynamicWidget, useDynamicContext } from '@dynam import { EthereumWalletConnectors } from '@dynamic-labs/ethereum'; import { ZeroDevSmartWalletConnectors } from '@dynamic-labs/ethereum-aa'; import { createContext, useContext, useEffect, useState, useCallback, ReactNode } from 'react'; -import { trackSignInStarted, trackUserLoggedIn } from '@/lib/analytics'; +import { trackSignInStarted, trackUserLoggedIn, trackUserLoggedOut } from '@/lib/analytics'; import { hasValidPromoAccess } from '@/lib/promo-access'; interface SubscriptionData { @@ -305,6 +305,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { walletConnectors: [EthereumWalletConnectors, ZeroDevSmartWalletConnectors], events: { onLogout: () => { + trackUserLoggedOut(); setIsAuthenticated(false); setUser(null); setHasActiveSubscription(false); diff --git a/app/components/LLMChatInline.tsx b/app/components/LLMChatInline.tsx index 8c8beb9..28e5a8c 100644 --- a/app/components/LLMChatInline.tsx +++ b/app/components/LLMChatInline.tsx @@ -386,7 +386,7 @@ export default function AIChatInline({ onOpenTour }: AIChatInlineProps = {}) { setAttachmentError(null); // Track LLM question - trackLLMQuestionAsked(); + trackLLMQuestionAsked({ isFollowUp: messages.length > 0 }); // Process attachments if any let processedAttachments: Attachment[] = []; diff --git a/app/components/LLMCommentaryModal.tsx b/app/components/LLMCommentaryModal.tsx index d1ef4e5..76e7a0c 100644 --- a/app/components/LLMCommentaryModal.tsx +++ b/app/components/LLMCommentaryModal.tsx @@ -8,6 +8,7 @@ import StudyQualityIndicators from "./StudyQualityIndicators"; import { useResults } from "./ResultsContext"; import { useCustomization } from "./CustomizationContext"; import { callLLM, getLLMDescription } from "@/lib/llm-client"; +import { trackAIAnalysisRun } from "@/lib/analytics"; type LLMCommentaryModalProps = { isOpen: boolean; @@ -89,6 +90,7 @@ export default function LLMCommentaryModal({ localStorage.setItem(CONSENT_STORAGE_KEY, "true"); setHasConsent(true); setShowConsentModal(false); + trackAIAnalysisRun(); fetchCommentary(); } }; diff --git a/app/components/StudyResultReveal.tsx b/app/components/StudyResultReveal.tsx index e50e5e2..1e169f5 100644 --- a/app/components/StudyResultReveal.tsx +++ b/app/components/StudyResultReveal.tsx @@ -8,7 +8,7 @@ import { analyzeStudyClientSide, UserStudyResult, determineEffectTypeAndSize } f import DisclaimerModal from "./DisclaimerModal"; import LLMCommentaryModal from "./LLMCommentaryModal"; import { SavedResult } from "@/lib/results-manager"; -import { trackStudyResultReveal } from "@/lib/analytics"; +import { trackStudyResultReveal, trackStudyAnalysisStarted } from "@/lib/analytics"; type StudyResultRevealProps = { studyId: number; @@ -80,6 +80,7 @@ export default function StudyResultReveal({ studyId, studyAccession, snps, trait }, [savedResult]); const handleRevealClick = () => { + trackStudyAnalysisStarted(); setShowDisclaimer(true); }; diff --git a/app/dna-chat/page.tsx b/app/dna-chat/page.tsx index 1ac2bc9..eefb3d1 100644 --- a/app/dna-chat/page.tsx +++ b/app/dna-chat/page.tsx @@ -8,10 +8,15 @@ import { PremiumPaywall } from "../components/PremiumPaywall"; import LLMChatInline from "../components/LLMChatInline"; import GuidedTour, { hasCompletedTour } from "../components/GuidedTour"; import { dnaChatTour } from "../components/tours/tourContent"; +import { trackDNAChatViewed } from "@/lib/analytics"; export default function DNAChatPage() { const [tourOpen, setTourOpen] = useState(false); + useEffect(() => { + trackDNAChatViewed(); + }, []); + useEffect(() => { if (!hasCompletedTour(dnaChatTour.id)) { setTourOpen(true); diff --git a/app/explore/page.tsx b/app/explore/page.tsx index 0771c6a..875cd70 100644 --- a/app/explore/page.tsx +++ b/app/explore/page.tsx @@ -26,6 +26,7 @@ import { trackRunAllStarted, trackQueryRun, trackExploreTabViewed, + trackSearchModeChanged, } from "@/lib/analytics"; // Note: Metadata must be exported from layout.tsx or a server component @@ -808,7 +809,7 @@ function ExplorePage() { name="searchMode" value="similarity" checked={filters.searchMode === "similarity"} - onChange={(event) => updateFilter("searchMode", event.target.value as "similarity" | "exact")} + onChange={(event) => { const m = event.target.value as "similarity" | "exact"; updateFilter("searchMode", m); trackSearchModeChanged(m); }} /> Similarity @@ -818,7 +819,7 @@ function ExplorePage() { name="searchMode" value="exact" checked={filters.searchMode === "exact"} - onChange={(event) => updateFilter("searchMode", event.target.value as "similarity" | "exact")} + onChange={(event) => { const m = event.target.value as "similarity" | "exact"; updateFilter("searchMode", m); trackSearchModeChanged(m); }} /> Exact match diff --git a/app/overview-report/page.tsx b/app/overview-report/page.tsx index 0d5c536..5f28e97 100644 --- a/app/overview-report/page.tsx +++ b/app/overview-report/page.tsx @@ -13,6 +13,7 @@ import { useResults } from "../components/ResultsContext"; import { hasValidPromoAccess } from "@/lib/promo-access"; import GuidedTour, { hasCompletedTour } from "../components/GuidedTour"; import { overviewReportTour } from "../components/tours/tourContent"; +import { trackOverviewReportViewed } from "@/lib/analytics"; export default function OverviewReportPage() { const router = useRouter(); @@ -32,6 +33,10 @@ export default function OverviewReportPage() { return () => window.removeEventListener('premiumAccessUpdated', refreshPromoAccess); }, []); + useEffect(() => { + trackOverviewReportViewed(); + }, []); + useEffect(() => { if (!hasCompletedTour(overviewReportTour.id)) { setTourOpen(true); diff --git a/lib/analytics.ts b/lib/analytics.ts index 84ec091..32a1723 100644 --- a/lib/analytics.ts +++ b/lib/analytics.ts @@ -452,11 +452,18 @@ export function trackRunAllFailed(source: 'menu' | 'explore' | 'onboarding', rea }); } -/** - * User asked the LLM a question in chat - */ -export function trackLLMQuestionAsked() { - trackEvent('llm_question_asked'); +export function trackLLMQuestionAsked(params?: { isFollowUp?: boolean }) { + trackEvent('llm_question_asked', { + is_follow_up: params?.isFollowUp ?? false, + }); +} + +export function trackDNAChatViewed() { + trackEvent('dna_chat_viewed'); +} + +export function trackOverviewReportViewed() { + trackEvent('overview_report_viewed'); } /** @@ -597,6 +604,18 @@ export function trackSubscribedWithStablecoin(durationDays: number) { }); } +export function trackUserLoggedOut() { + trackEvent('user_logged_out'); +} + +export function trackSearchModeChanged(mode: 'similarity' | 'exact') { + trackEvent('search_mode_changed', { mode }); +} + +export function trackStudyAnalysisStarted() { + trackEvent('study_analysis_started'); +} + /** * User updated their personalization settings */ From 4ae9a331c21e33e6e6cc6e790b11cf6d85c3adf2 Mon Sep 17 00:00:00 2001 From: Vishakh Date: Thu, 7 May 2026 11:07:57 -0400 Subject: [PATCH 3/3] Finetuned SEO --- app/dna-chat/layout.tsx | 28 ++++++++++ app/layout.tsx | 4 +- app/overview-report/layout.tsx | 28 ++++++++++ app/page.tsx | 37 ++++++++++++- app/sitemap.ts | 95 ++++++++++++++++------------------ app/study/[id]/layout.tsx | 46 ++++++++++++++-- app/subscribe/layout.tsx | 28 ++++++++++ next-env.d.ts | 2 +- 8 files changed, 208 insertions(+), 60 deletions(-) create mode 100644 app/dna-chat/layout.tsx create mode 100644 app/overview-report/layout.tsx create mode 100644 app/subscribe/layout.tsx diff --git a/app/dna-chat/layout.tsx b/app/dna-chat/layout.tsx new file mode 100644 index 0000000..fead5fd --- /dev/null +++ b/app/dna-chat/layout.tsx @@ -0,0 +1,28 @@ +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "DNA Chat - Monadic DNA Explorer", + description: "Ask private AI questions about your saved genetic results. Your DNA data never leaves your device.", + keywords: ["DNA chat", "genetic AI", "private DNA analysis", "personal genomics AI", "DNA questions"], + alternates: { + canonical: "https://explorer.monadicdna.com/dna-chat", + }, + openGraph: { + title: "DNA Chat - Monadic DNA Explorer", + description: "Ask private AI questions about your saved genetic results. Your DNA data never leaves your device.", + type: "website", + url: "https://explorer.monadicdna.com/dna-chat", + siteName: "Monadic DNA Explorer", + locale: "en_US", + }, + twitter: { + card: "summary_large_image", + title: "DNA Chat - Monadic DNA Explorer", + description: "Ask private AI questions about your saved genetic results. Your DNA data never leaves your device.", + creator: "@MonadicDNA", + }, +}; + +export default function DNAChatLayout({ children }: { children: React.ReactNode }) { + return <>{children}; +} diff --git a/app/layout.tsx b/app/layout.tsx index 768fa5b..f45eb35 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -33,7 +33,7 @@ export const metadata: Metadata = { locale: "en_US", images: [ { - url: "https://monadicdna.com/og-image.png", + url: "/og-image.png", width: 1199, height: 630, alt: "Monadic DNA Explorer - Private DNA insights from trusted genetic research", @@ -45,7 +45,7 @@ export const metadata: Metadata = { title: "Monadic DNA | Personal DNA insights with privacy, autonomy, and boundless curiosity", description: "Private DNA insights from trusted genetic research. Learn from your DNA while your data remains private, protected, and entirely in your hands.", creator: "@MonadicDNA", - images: ["https://monadicdna.com/og-image.png"], + images: ["/og-image.png"], }, robots: { index: true, diff --git a/app/overview-report/layout.tsx b/app/overview-report/layout.tsx new file mode 100644 index 0000000..3bad550 --- /dev/null +++ b/app/overview-report/layout.tsx @@ -0,0 +1,28 @@ +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Overview Report - Monadic DNA Explorer", + description: "Generate an AI-powered report synthesizing your saved genetic results into patterns, themes, and suggested next steps.", + keywords: ["DNA overview report", "genetic analysis report", "AI genetics", "personal genomics report"], + alternates: { + canonical: "https://explorer.monadicdna.com/overview-report", + }, + openGraph: { + title: "Overview Report - Monadic DNA Explorer", + description: "Generate an AI-powered report synthesizing your saved genetic results into patterns, themes, and suggested next steps.", + type: "website", + url: "https://explorer.monadicdna.com/overview-report", + siteName: "Monadic DNA Explorer", + locale: "en_US", + }, + twitter: { + card: "summary_large_image", + title: "Overview Report - Monadic DNA Explorer", + description: "Generate an AI-powered report synthesizing your saved genetic results into patterns, themes, and suggested next steps.", + creator: "@MonadicDNA", + }, +}; + +export default function OverviewReportLayout({ children }: { children: React.ReactNode }) { + return <>{children}; +} diff --git a/app/page.tsx b/app/page.tsx index 43de08b..9f3ebc2 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -17,7 +17,7 @@ export const metadata: Metadata = { locale: "en_US", images: [ { - url: "https://monadicdna.com/og-image.png", + url: "/og-image.png", width: 1199, height: 630, alt: "Monadic DNA Explorer - Private DNA insights from trusted genetic research", @@ -28,13 +28,46 @@ export const metadata: Metadata = { card: "summary_large_image", title: "Monadic DNA | Personal DNA insights with privacy, autonomy, and boundless curiosity", description: "Private DNA insights from trusted genetic research. Learn from your DNA while your data remains private, protected, and entirely in your hands.", - images: ["https://monadicdna.com/og-image.png"], + images: ["/og-image.png"], + }, +}; + +const organizationJsonLd = { + "@context": "https://schema.org", + "@type": "Organization", + "name": "Monadic DNA", + "url": "https://explorer.monadicdna.com", + "logo": "https://explorer.monadicdna.com/explorer-logo.png", + "sameAs": ["https://x.com/MonadicDNA"], +}; + +const websiteJsonLd = { + "@context": "https://schema.org", + "@type": "WebSite", + "name": "Monadic DNA Explorer", + "url": "https://explorer.monadicdna.com", + "description": "Private DNA insights from trusted genetic research.", + "potentialAction": { + "@type": "SearchAction", + "target": { + "@type": "EntryPoint", + "urlTemplate": "https://explorer.monadicdna.com/explore?q={search_term_string}", + }, + "query-input": "required name=search_term_string", }, }; export default function HomePage() { return (
+