feat(capi): server-side Meta Conversions API for signup (CompleteRegistration)
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
The browser pixel under-counts signups badly: ~96% of paid traffic is mobile in-app browsers where iOS ITP / ad-blockers drop client events, and the OAuth path never fired it reliably. Meta recorded ~0 registrations for a 7.5K-spend campaign while PostHog saw 98 facebook signups — so Meta could neither optimize toward nor attribute signups, which is the main driver of the low signup rate. This adds a server-side CAPI CompleteRegistration: - MetaCapiService + @Global module. Fail-open: no-ops unless META_CAPI_PIXEL_ID + META_CAPI_ACCESS_TOKEN are set; never throws (signup must not break). SHA-256 hashed email + fbp/fbc/IP/UA. - Fired from the better-auth user.create.after hook for ALL signups (reliable, covers Google OAuth which the browser pixel missed entirely). - A session-gated POST /analytics/meta/complete-registration endpoint adds fbp/fbc/IP/UA (ad-click attribution) for the email path. - The browser pixel now passes a shared event_id (signup_<userId>); the premature Google client-pixel fire (fired on click, before completion) is removed. - All sources dedupe via event_id=signup_<userId>. Activate by setting META_CAPI_PIXEL_ID + META_CAPI_ACCESS_TOKEN (Events Manager) in the api env; META_CAPI_TEST_EVENT_CODE routes to Test Events for verification. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -150,7 +150,13 @@ function RegisterPage() {
|
||||
// onboarding modal on the search page is the single place that applies it
|
||||
// (covers both email and Google OAuth signups).
|
||||
capture("user_signed_up", { method: "email" });
|
||||
trackMeta("CompleteRegistration", { method: "email" });
|
||||
// CompleteRegistration: browser pixel + server-side CAPI (adds fbp/fbc/IP/UA
|
||||
// for ad-click attribution), deduped via the shared event id `signup_<userId>`.
|
||||
const metaEventId = data?.user ? `signup_${data.user.id}` : undefined;
|
||||
trackMeta("CompleteRegistration", { method: "email" }, metaEventId);
|
||||
api
|
||||
.post("/analytics/meta/complete-registration", { eventSourceUrl: window.location.href })
|
||||
.catch(() => {});
|
||||
if (plan) localStorage.setItem(PENDING_PLAN_KEY, plan);
|
||||
toast.success("Hesap oluşturuldu!");
|
||||
window.location.href = redirectUrl;
|
||||
@@ -237,7 +243,10 @@ function RegisterPage() {
|
||||
onClick={() => {
|
||||
startAction("register", { method: "google" });
|
||||
capture("user_signed_up", { method: "google" });
|
||||
trackMeta("CompleteRegistration", { method: "google" });
|
||||
// Meta CompleteRegistration for Google is sent SERVER-SIDE on actual
|
||||
// account creation (auth databaseHook). The browser pixel here fired on
|
||||
// click (before the user even finished Google auth) and would double-
|
||||
// count, so it's intentionally not sent client-side for OAuth.
|
||||
if (plan) localStorage.setItem(PENDING_PLAN_KEY, plan);
|
||||
signIn.social({ provider: "google", callbackURL: redirectUrl });
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user