fix(analytics): OAuth kayıtlarında Google Ads sign-up conversion'ı ateşle
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Conversion sadece register.tsx email path'inde ateşleniyordu; Google OAuth signup'lar (register + login Google butonu) hiç ateşlemiyordu → ölçüm: paid- kaynaklı kayıtların ~%79'u OAuth, Google Ads'e görünmüyordu, Max Conversions sinyalsiz optimize ediyordu. Evrensel post-auth bileşeni (google-ads-signup- conversion.tsx, __root'a mount) yeni kullanıcıda (createdAt < 30dk) conversion'ı bir kez ateşler; transaction_id signup_<userId> Google tarafında dedup eder, register.tsx guard'ı email path'in çift-ateşini önler. _gcl_aw cookie OAuth roundtrip'inde korunduğu için atıf doğru. Playwright 6/6. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
59
apps/web/src/components/google-ads-signup-conversion.tsx
Normal file
59
apps/web/src/components/google-ads-signup-conversion.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { trackGoogleAdsConversion } from "@/lib/google-ads";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
/**
|
||||
* Universal post-auth Google Ads sign-up conversion.
|
||||
*
|
||||
* The register page fires the sign-up conversion only on the EMAIL path
|
||||
* (register.tsx). Google OAuth signups — both the register-page Google button
|
||||
* and the login-page Google button — complete server-side after a redirect and
|
||||
* never fire it, so Google Ads saw ~0 of them (measured: ~79% of paid-driven
|
||||
* signups were OAuth → invisible to Google Ads, starving Max Conversions of its
|
||||
* signal). This mounts at the root and fires for any brand-new authenticated
|
||||
* user, covering every signup path.
|
||||
*
|
||||
* Double-count safety: the conversion carries transaction_id `signup_<userId>`,
|
||||
* which Google dedupes on — so an email signup that already fired on the
|
||||
* register page counts once even though this fires again. The localStorage guard
|
||||
* additionally stops repeat fires across the new user's first-session pageviews;
|
||||
* register.tsx sets the same guard so email signups skip the redundant fire.
|
||||
*
|
||||
* Attribution: gtag's own `_gcl_aw` cookie (set from gclid on the ad landing)
|
||||
* survives the same-domain OAuth round-trip, so firing here still attributes to
|
||||
* the original click. Organic (non-ad) new users fire too, but Google only
|
||||
* counts conversions it can tie to an ad click — the rest are ignored.
|
||||
*/
|
||||
const NEW_USER_WINDOW_MS = 30 * 60 * 1000;
|
||||
|
||||
function guardKey(userId: string): string {
|
||||
return `sase-ga-signup-conv-${userId}`;
|
||||
}
|
||||
|
||||
export function GoogleAdsSignupConversion() {
|
||||
const { user, isLoading } = useAuth();
|
||||
const firedRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoading || !user || firedRef.current) return;
|
||||
const createdAt = user.createdAt ? new Date(user.createdAt).getTime() : 0;
|
||||
// Only genuinely fresh accounts — this is a signup conversion, not a login.
|
||||
if (!createdAt || Date.now() - createdAt > NEW_USER_WINDOW_MS) return;
|
||||
|
||||
const key = guardKey(user.id);
|
||||
try {
|
||||
if (localStorage.getItem(key)) return;
|
||||
localStorage.setItem(key, "1");
|
||||
} catch {
|
||||
// localStorage unavailable — firedRef still prevents in-session repeats.
|
||||
}
|
||||
firedRef.current = true;
|
||||
|
||||
trackGoogleAdsConversion(import.meta.env.VITE_GOOGLE_ADS_SIGNUP_LABEL, {
|
||||
transactionId: `signup_${user.id}`,
|
||||
email: user.email,
|
||||
});
|
||||
}, [user, isLoading]);
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user