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:
@@ -45,6 +45,11 @@ interface AuthOptions {
|
||||
novu?: NovuService;
|
||||
/** Called after a user's email is verified (referral qualification, etc.). */
|
||||
onEmailVerified?: (userId: string) => Promise<void>;
|
||||
/** Server-side Meta CAPI sender — reliable signup backstop for BOTH email and
|
||||
* Google OAuth (the browser pixel misses OAuth and is ad-blocked on mobile). */
|
||||
metaCapi?: {
|
||||
sendCompleteRegistration: (input: { userId: string; email?: string | null }) => Promise<void>;
|
||||
};
|
||||
}
|
||||
|
||||
export function createAuth(
|
||||
@@ -155,6 +160,14 @@ export function createAuth(
|
||||
};
|
||||
},
|
||||
after: async (user) => {
|
||||
// Server-side Meta CAPI signup event — reliable for BOTH email and
|
||||
// Google OAuth (the browser pixel misses OAuth and is ad-blocked on
|
||||
// mobile in-app). Deduped with the pixel/endpoint via
|
||||
// event_id=signup_<id>. Fire-and-forget; never break signup.
|
||||
void options?.metaCapi?.sendCompleteRegistration({
|
||||
userId: user.id,
|
||||
email: user.email,
|
||||
});
|
||||
// Fire-and-forget lifecycle e-mails on signup (covers password +
|
||||
// OAuth). Never await / never let a notification failure surface
|
||||
// into the signup response. `referral` is delay-stepped in Novu
|
||||
|
||||
Reference in New Issue
Block a user