Documentation

Meta project setup

From one tracked landing page to a report with spend and verified outcomes

1. Use one environment for the whole flow

Use a project public key, ingest endpoint, Convex conversion endpoint and integration credentials from the same environment. The dashboard install page requires its operator to set REALANALYTICS_INGEST_URL. It does not select a production endpoint automatically.

Run bun run pack:local in the Realanalytics repository. Install the local SDK and server tarballs, or host browser.global.js on the tracked site. See installation. The local examples/meta-leadgen integration core shows the browser and server flow. Connect it to your own database and durable outbox before use.

2. Confirm an observed browser event

Add the SDK, connect your consent manager, then perform a normal page or form action. A local ready signal proves only that the SDK loaded. An accepted delivery receipt proves ingestion accepted an event. Find that event in Event Debugger to confirm it is queryable.

Analytics, advertising user data and advertising personalization are separate choices. Do not grant advertising purposes just to improve attribution. A form submission in the browser is an observed action, not a verified lead or payment.

3. Carry stable Meta IDs

When you choose to update an ad, apply this example yourself in its URL parameters field. Realanalytics does not edit or publish ads. Preserve other parameters your site needs.

utm_source=meta&utm_medium=paid_social&utm_campaign={{campaign.id}}&campaign_id={{campaign.id}}&adset_id={{adset.id}}&ad_id={{ad.id}}

Verify the final landing URL has actual campaign, ad-set and ad IDs rather than unresolved double braces. Check that redirects retain them. Stable IDs keep reporting joins independent of campaign renames. Do not manufacture fbclid values or share click IDs between visitors.

4. Confirm the outcome on a trusted server

Save the lead, booking or payment first. Then use a dedicated conversion key to report the verified outcome. Keep the conversion key and CLI deploy key out of browser code. Use a stable conversion ID so retries do not create new outcomes.

Browser context contains attribution hints. The server must validate those hints, use consent from its trusted record, and derive person identity, lifecycle stage and money from authoritative records. A browser payload must not decide whether it became a customer.

// Browser, after SDK readiness; null when collection is denied:
const browserContext = analytics.getContext()

// Server, after loading a trusted consent receipt for the session:
const context = parseBrowserContext(input.browserContext, {
  trustedConsent: storedConsent,
  allowedOrigins: ['https://your-site.example'],
})
// Use context only as hints alongside the saved backend outcome.
// Do not spread the incoming form payload into a conversion.

Conversion API reference covers lifecycle stages, revenue rules, idempotency and server responses.

Record every consent decision, including each withdrawal, through the server consent API with recordConsent(). Use the CMP receipt ID as the updateId and include the saved person and anonymous IDs. The browser SDK also reports withdrawals and retries them, but it can name only the browser visitor, so it does not replace the server record. Attio and other CRM stages use current consent when they are processed, and a queued Meta delivery rechecks consent before it sends. See consent decisions and withdrawals.

5. Save Meta settings, then check access

Save the ad account, currency, project timezone and optional dataset settings. Connect a server-side credential. Use Check connection to perform read-only account checks. A passed read check does not import spend, send a conversion, or prove CAPI acceptance.

Check received-data timestamps separately. Spend evidence is specific to the integration. Conversion evidence is project-wide. A Meta CAPI delivery remains a separate, explicit enablement step.

6. Read one complete reporting day

For the local starter, use a cvk_test_ conversion key and select Test above the report, or add ?environment=test to the attribution URL. Keep the same anonymous ID on each lifecycle outcome so it can join the consented browser touch. Test spend requires a Meta integration in test mode with its testEventCode. Use isolated deployment credentials and endpoints throughout.

Deploy the attribution definition and select a complete day in the project timezone. Today's test activity is not part of a complete-day report yet. Check the imported spend date, attributed conversion credit and account mapping before comparing campaign costs.

EvidenceNext step
No spend or conversion creditConfirm installation, account access and a server-verified outcome. Check the selected dates.
Spend onlyInspect the conversion ledger and identity/touchpoint mapping. Zero credit is not proof of zero leads.
Conversion credit onlyCheck spend import, currency, timezone and the received spend date.
Unmapped or ambiguous rowsInspect stable ad IDs and the conversion journey before assuming an account match.
Partial lifecycle coverageDo not treat unavailable stage counts as zero. Complete the lifecycle report projection before using stage costs.

Browser observation, verified server outcomes, attribution credit and provider delivery are separate evidence. Use Reconciliation for the last of these.

7. Recover a delivery whose acceptance is unknown

Open Delivery recovery to see each attempt and its provider receipts. A receipt records the provider's response: status code, request ID and, for Meta, the number of events received. An Ambiguous attempt started a send but has no conclusive response. The event may already be in Meta. Realanalytics never resends it automatically.

Owners and admins can recover it. Viewers can read the evidence.

  1. Copy the event ID from the attempt. Look for that event ID in Meta Events Manager for the same dataset and mode. Allow for Meta's processing delay.
  2. Select Record provider evidence. Choose whether Meta has the event, describe what you checked and type the event ID to confirm. Do not paste access tokens or customer data.
  3. If Meta has the event, recovery is complete. If Meta does not have it, select Resend same event and type the event ID again.

A resend uses the original event ID and the next attempt number. It is available only in Live, only for the latest attempt, only within Meta's 7-day event window and only while current consent allows delivery. The panel shows the reason when it is unavailable.

A queued resend is not yet sent. Before any call to Meta, Realanalytics checks the connection, credentials, delivery switches and consent again. If one of these blocks it, the attempt pauses and nothing is sent. Check the new attempt's status and receipt afterwards.

8. Import historical spend

The daily import reads only the last three closed days. To fill an older range, open Imports and select Import history. Owners and admins can request up to 90 closed days for one ad account. The account timezone must match the project timezone.

  • Each day uses the same one-day import as recovery. Days that already have a completed receipt are skipped.
  • The request is pinned to the connection it was created for. If the connection, account, currency or timezone changes, the request stops as Blocked and imports nothing under the new settings.
  • If the deployment's provider switches are off, the request is Blocked and makes no call to Meta.
  • Cancel stops the request before its next day. A day already in progress finishes or fails as usual.
  • A failed day does not stop the request. Retry it later as a single account day.

9. Acknowledge and assign alerts

The Alerts page lists open issues from delivery, connections and spend imports. Owners and admins can acknowledge an alert with an optional note and assign it to a project member. Acknowledgment shows that someone is handling the issue. It does not resolve it: the alert keeps its severity until its evidence clears. If the issue happens again, the alert opens again. The page sends no notifications.