Hogsend is brand new.Try it
Hogsend
Conversions, Pixels & Ad Platforms

Meta (Facebook & Instagram)

Feed valued conversions to the Meta Conversions API first-party with @hogsend/plugin-meta-capi — deterministic dedup, reconstructed fbc, CRM-grade action_source.

Meta's Conversions API (CAPI) receives conversions server-side, so you keep attribution even when the browser Pixel is blocked by ad blockers, iOS, or cookie restrictions. @hogsend/plugin-meta-capi is Hogsend's native destination for it: every fired conversion point with destinations: ["meta-capi"] becomes one CAPI event, delivered by the engine's durable dispatch with retries and deterministic dedup.

What you need

CredentialWhere to get it
Pixel ID (Dataset ID)Events Manager → your dataset → Settings. Use the same Pixel ID your browser Pixel uses so server + browser events reconcile.
Access TokenEvents Manager → your dataset → SettingsConversions APIGenerate access token. Self-serve — no App Review or Meta app needed. Copy it immediately (it's shown once).

Setup

src/index.ts / src/worker.ts
import { createMetaCapiDestination } from "@hogsend/plugin-meta-capi";

const client = createHogsendClient({
  conversions,
  conversionDestinations: [
    createMetaCapiDestination({
      pixelId: process.env.META_PIXEL_ID!,
      accessToken: process.env.META_CAPI_TOKEN!,
      // eventNames: { "deal-sold": "Purchase", "lead-submitted": "Lead" },
      // testEventCode: "TEST1234",   // while validating — remove for live
    }),
  ],
});

Then point conversion points at it: destinations: ["meta-capi"] on each defineConversion that should reach Meta.

What the plugin sends

One server event per fired conversion:

CAPI fieldValueWhy it matters
event_namePer-definition eventNames mapping; else Purchase when the conversion has a value, Lead when it doesn'tMeta optimizes best against standard event names
event_idThe engine's deterministic dedup id (sha256(contact:definition:event-row))Stable across retries; a browser Pixel sending the same id dedups against it
event_timeThe conversion's occurredAt, Unix secondsHonest timing, even for backfilled CRM events
action_sourcesystem_generatedThe home for CRM/offline conversions since Meta retired the Offline Conversions API (May 2025)
user_data.em / ph / external_idSHA-256 hashed per Meta's normalization (email lowercased/trimmed; phone digits-only)The top match-quality signals
user_data.fbcReconstructed as fb.1.<click_ts>.<fbclid> from the stored click evidenceThe ad click-id — sent plain per spec, never fabricated
custom_data.value / currencyThe conversion's resolved valueWhat ROAS and value-based bidding read

fbc is real or absent. The engine recovers the contact's most recent campaign.arrived touchpoint before the conversion — the fbclid and the actual click timestamp captured first-party by @hogsend/js. No Meta click on record → no fbc, because a fabricated one poisons match quality.

Match quality

The two highest-impact matchers are hashed email and fbc. Both are already flowing if you've wired the front of the loop:

  • Run @hogsend/js on your landing pages so ad clicks fire campaign.arrived (captures fbclid with its timestamp).
  • Use lead intake hidden fields so the browser session stitches to the email-anchored contact.

Conversion Leads (optimizing on funnel stages)

Meta's Conversion Leads performance goal optimizes lead campaigns on what leads become, not just that they arrived. It wants your funnel stages as CRM events: define one conversion point per stage (lead-submittedcontactedquotedsold), map each to the stage name you configure in Events Manager's Leads Funnel via eventNames, and send them all to meta-capi. Meta's stated requirements: roughly 200+ leads a month and a lead→stage conversion rate between 1–40%. This works for website-form leads, not just Instant Forms.

Testing

Set testEventCode in the config, fire a conversion (e.g. re-ingest a deal.sold stage change in a dev environment), and watch it appear in Events Manager → Test Events. Delivery state is also on your side: conversion_dispatches records attempts, the platform's fbtrace_id receipt, and any error. Remove the test code before going live.

Deduplication vs the browser Pixel

If you also run Meta's browser Pixel for the same conversion, have the Pixel send the same event_id — Meta counts each conversion once (within ~48h, matching on event_name + event_id). If CAPI via Hogsend is the only source for that conversion (typical for CRM-stage events — the browser never sees a deal close), there's nothing to dedupe.

Alternative: via PostHog

PostHog's Meta Ads Conversions destination can forward PostHog-captured events to CAPI instead — Hogsend's analytics mirror keeps PostHog populated (including value/currency), so the plumbing exists. Prefer the native plugin when the conversion carries money or CRM stage evidence: it sends the engine's deterministic event_id, the recovered first-party click, and action_source: system_generated — none of which a mirror can reconstruct as faithfully. The PostHog route remains a fine choice for browser-context-rich, value-less events, and is the documented path for Google, TikTok, LinkedIn, and Reddit until those get native destinations.