From 45403aa06f5e1888619dc8539af6587b276121a8 Mon Sep 17 00:00:00 2001
From: Ben Senescu <44480372+bensenescu@users.noreply.github.com>
Date: Fri, 7 Aug 2026 22:56:31 -0400
Subject: [PATCH] fix(ga4): hide every GA4 connect surface until the OAuth app
is approved (#466)
---
src/client/features/ai-mcp/AvailableTools.tsx | 8 +++-----
src/client/features/dashboard/DashboardPage.tsx | 7 ++-----
.../ga4/GoogleAnalyticsConnectionCard.tsx | 15 ++++++++++++++-
src/shared/ga4.ts | 6 ++++++
4 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/src/client/features/ai-mcp/AvailableTools.tsx b/src/client/features/ai-mcp/AvailableTools.tsx
index 97d6881..acb5f66 100644
--- a/src/client/features/ai-mcp/AvailableTools.tsx
+++ b/src/client/features/ai-mcp/AvailableTools.tsx
@@ -1,3 +1,5 @@
+import { GA4_OAUTH_APP_PENDING } from "@/shared/ga4";
+
type McpTool = {
name: string;
title: string;
@@ -207,11 +209,7 @@ const toolCategories: ToolCategory[] = [
},
];
-// Google hasn't approved the GA4 OAuth app yet, so connecting fails.
-// Flip to false once the app is approved.
-const GA4_TOOLS_HIDDEN = true;
-
-const visibleCategories = GA4_TOOLS_HIDDEN
+const visibleCategories = GA4_OAUTH_APP_PENDING
? toolCategories.filter((cat) => cat.label !== "Google Analytics")
: toolCategories;
diff --git a/src/client/features/dashboard/DashboardPage.tsx b/src/client/features/dashboard/DashboardPage.tsx
index de98772..9644d40 100644
--- a/src/client/features/dashboard/DashboardPage.tsx
+++ b/src/client/features/dashboard/DashboardPage.tsx
@@ -25,12 +25,9 @@ import {
refreshDashboardBacklinkSnapshot,
} from "@/serverFunctions/dashboard";
import { setProjectDomain } from "@/serverFunctions/projects";
+import { GA4_OAUTH_APP_PENDING } from "@/shared/ga4";
import type { DashboardHeroStep } from "@/types/schemas/dashboard";
-// Google hasn't approved the GA4 OAuth app yet, so connecting fails.
-// Flip to false once the app is approved.
-const GA4_CARD_HIDDEN = true;
-
const HERO_COPY: Record<
DashboardHeroStep,
{ title: string; body: string; cta: string }
@@ -336,7 +333,7 @@ export function DashboardPage({ projectId }: { projectId: string }) {
hasData: gscConnected,
node: ,
},
- ...(!GA4_CARD_HIDDEN &&
+ ...(!GA4_OAUTH_APP_PENDING &&
(ga4Connected || !activation.ga4.cardDismissedAt)
? [
{
diff --git a/src/client/features/ga4/GoogleAnalyticsConnectionCard.tsx b/src/client/features/ga4/GoogleAnalyticsConnectionCard.tsx
index 2c9eb73..8ba977f 100644
--- a/src/client/features/ga4/GoogleAnalyticsConnectionCard.tsx
+++ b/src/client/features/ga4/GoogleAnalyticsConnectionCard.tsx
@@ -19,7 +19,10 @@ import {
listGa4Properties,
setGa4Property,
} from "@/serverFunctions/ga4";
-import { GA4_SELF_HOSTED_SETUP_DOCS_URL } from "@/shared/ga4";
+import {
+ GA4_OAUTH_APP_PENDING,
+ GA4_SELF_HOSTED_SETUP_DOCS_URL,
+} from "@/shared/ga4";
export function GoogleAnalyticsConnectionCard({
projectId,
@@ -43,6 +46,14 @@ export function GoogleAnalyticsConnectionCard({
});
const connection = connectionQuery.data;
const connected = Boolean(connection?.connected);
+ // Hide the hosted connect surface while the OAuth app awaits Google's
+ // approval, but keep the card for users who already hold a grant so they
+ // can finish property selection or disconnect.
+ const hiddenPendingApproval =
+ GA4_OAUTH_APP_PENDING &&
+ hosted &&
+ !connected &&
+ !connection?.currentUserHasGrant;
const selfHostedNeedsSetup =
!hosted && connectionQuery.isSuccess && !connection?.googleOAuthConfigured;
const showPicker = picking || (connection?.currentUserHasGrant && !connected);
@@ -101,6 +112,8 @@ export function GoogleAnalyticsConnectionCard({
});
const handleConnect = () => void startGoogleLink("ga4", window.location.href);
+ if (hiddenPendingApproval) return null;
+
return (