Skip to content

Build1 publisher3 min readPublished

A weekend inside KYC pushes the funded-deposit event to the edge of Meta's seven-day window

A dev.to walkthrough moves fintech conversion tracking into a Node.js worker that posts hashed deposit events to Meta's Conversions API. Its own latency numbers do not survive a Thursday signup.

The Engineer · Build desk

Illustration accompanying A weekend inside KYC pushes the funded-deposit event to the edge of Meta's seven-day window

What happened

  • A dev.to walkthrough lays out the fintech funnel as ad click, registration, KYC document submission, back-office identity verification, then a first-time deposit into a wallet or trading balance.
  • Client-side pixels cannot observe that deposit, because it lands behind authenticated banking portals, payment gateway webhooks, or native MT4, MT5 and cTrader terminals.
  • The proposed fix stores the click IDs at registration and has an internal worker SHA-256 hash the identifiers and POST a FundedAccount or Purchase event to Meta's Conversions API once the deposit clears.
  • The post's first listed trap is a trader who takes ten days from ad click to cleared compliance and deposit, where an event sent without fbp or fbc is hard for Meta to map back to revenue.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint A seven-day click-through window caps how slow compliance can be before a funded deposit stops counting as paid-media revenue. The KYC queue sets that deadline, not the media team.
  • decision Attribution becomes a schema decision made at signup. Either the user row carries _fbp and _fbc from the first pageview or the deposit event has nothing to match on days later.
  • exposure The backend becomes the only sender of the conversion, and the sample's error path is a console.error that returns false, so a dropped event is revenue the ad platform never learns about.
  • cost Normalization of PII moves onto the operator's payroll: Meta's requirement covers phone and name as well as email, and every field the sample does not handle is code someone has to write and test.

The post's two numbers do not agree with each other. The architecture diagram puts 24 to 72 hours between the registration that stores the click IDs and the payment gateway webhook that clears the deposit [5]. The prose puts KYC document review alone at anywhere from two hours to three business days [1]. Three business days that start on a Thursday finish on Monday, which is 120 hours before anyone funds anything [18]. Meta's standard click-through attribution window is seven days [14]. Give that trader one more day to wire the money and six of the seven days are spent [19].

The load-bearing part of this design is the row written at registration. A client-side helper reads _fbp and _fbc out of document.cookie and posts them to /api/register alongside the email and navigator.userAgent [16]. The dispatcher that fires later takes fbp, fbc, clientIp and userAgent as arguments [10]. At webhook time there is no browser to ask, so every one of those values has to come back out of the database.

hashParam trims a value, lowercases it, and returns a SHA-256 hex digest [8]. The post says Meta requires email, phone and name to be normalized and hashed before transmission [9]. Lowercasing a phone number does nothing, and the helper removes no punctuation, spaces or country-code formatting, so anyone extending user_data past the single hashed email in the sample payload [10] is writing their own normalizer.

Delivery is one POST to graph.facebook.com pinned at API version v19.0 [7]. A non-ok response logs "Meta CAPI Error" and returns false; a network failure logs and returns false [17]. There is no queue and no retry in the sample, so a lost FundedAccount event is a conversion that no browser will re-fire. The event_id is the transaction ID, which the post calls critical for deduplication [11]; that only dedupes against a second sender using the same ID, so the pixel side has to be built to agree. The payload also declares action_source as "website" on an event triggered by a payment gateway [12].

The claim carrying the whole argument is that optimizing only on top-of-funnel form fills trains Meta and Google to flood the funnel with bot signups and unverified users who never deposit [3]. The sources measure none of it. There is no bot rate, no cost per funded account before and after, and no volume floor at which a FundedAccount event starts moving the optimizer at all. The same walkthrough appears on dev.to twice under different slugs [20], which is one author's assertion published twice.

For the mechanism to transfer to your funnel, two things have to hold: enough verified deposits per week for the platform to learn from the event, and a click ID still attached to the user when it fires. The second one is cheap and I would do it regardless of whether you ever call the Conversions API. Reading two cookies at registration costs a column and a write [16]. You cannot backfill a cookie you never read, and the deposit webhook does not arrive for another 24 to 72 hours [5].

What to watch

  • Whether Graph API deprecation forces a change to the v19.0 version pin in the sample dispatcher.
  • A measured before-and-after from anyone running this: cost per funded account with and without the server-side event.
  • Whether the same author publishes the Google side, since gclid is stored at registration but never sent anywhere in the code.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories