Documentation menu

Meta advertising costs

Revenue → Acquisition joins imported Meta campaign spend to verified provider payments. The connection only reads the ad account. It is independent of the Meta Conversions API destination.

Connect

  1. Obtain a Meta Marketing API access token with ads_read and access to your ad account. A business system-user token can support an unattended connection; its account assignment and expiry remain managed in Meta.
  2. Open Revenue → Acquisition → Manage connections. Enter a name, the numeric ad account ID without act_, and the token. If your Meta app requires app-secret proof, include its app secret.
  3. The worker imports the previous 90 complete days in the ad account's timezone, then repeats every six hours. Check connection status for the last successful sync or a failure reason. Replace an expired token under Edit connection.
  4. In Meta's ad URL parameters, use:
utm_source=meta&utm_medium=paid_social&utm_id={{campaign.id}}&utm_campaign={{campaign.name}}

Use the current browser SDK (or send context.utm.id from your SDK). Identify customers consistently with their billing identity. Costs can import before customer tracking is ready; unmatched payments remain visible.

This increment uses an operator-supplied token. A hosted Facebook Login approval flow is not yet included. Real-account access depends on your Meta app, permissions and account assignment; local fixture verification does not establish live-provider access.

Reading the report

  • Select one account, 7/30/90 completed days, and a 7/30-day visit lookback. Today is excluded. Payments are application-wide; only production visits participate.
  • The last retained visit at or before a payment wins, within the lookback. Its first retained page view supplies the campaign snapshot; page views after payment are excluded. It must have a Meta source (meta, facebook, instagram, fb, ig) and paid medium (cpc, ppc, paid, paid_social, paid-social, paidsocial). A later direct visit takes precedence.
  • Exact utm_id matches first. Without it, a numeric utm_campaign can match the campaign ID; other names require an exact saved mapping. Names are case-sensitive. Invalid/unrecognized IDs do not fall back to names. A click ID alone cannot identify a campaign.
  • ROAS = matched net payment revenue / spend in the selected period. Refunds reduce the original payment date. This is a period ratio, not cohort lifetime return or Meta's view-through/click attribution.
  • Cost per new customer = spend / matched first-time paying customers. The first positive verified payment across currencies determines newness; it must retain a positive net amount. Linked people deduplicate billing customers. Incomplete imported payment history can overstate newness.
  • Amounts stay in the ad account's original currency. No automatic FX conversion. Payment API records are excluded. Missing identity, unknown campaigns and other/unrecorded visits have separate counts.
  • Incomplete spend coverage suppresses ROAS and acquisition cost. Pausing preserves the last import; removing the connection deletes its spend and mappings, revokes its local vault credential, and preserves payments/visits. It does not revoke the token at Meta.

Protocol and limits

The adapter uses Graph API v26.0, GET /act_{id} for account metadata and GET /act_{id}/insights with level=campaign, time_increment=1, an explicit date window, and spend/impression/click fields. It requests only fixed Meta endpoints, sends bearer credentials server-side, computes app-secret proof when configured, refuses redirects, and follows opaque cursors rather than provider-returned URLs.

Requests are limited to 10 seconds and 2 MB; one import accepts at most 200 pages / 20,000 campaign-days and roughly two minutes. Data replaces the retained 90-day snapshot atomically after every page validates. A failed import leaves prior spend intact and does not advance coverage. Concurrent imports hold a short lease; credential changes, pausing or deletion invalidate in-flight results. Eight accounts and 200 explicit campaign mappings are allowed per application. Reports have an eight-second database budget and show the top 200 campaigns; summary totals include all campaigns. The console fixes the environment to production.

Source management uses revenue.write; reports additionally require revenue.read, analytics.read, and both enabled modules. Console changes require a passkey verified within ten minutes, CSRF and same-origin validation. Every change and completed/failed import is audited. Management API routes under /apps/{app}/revenue/acquisition use scoped management tokens; browser ingest keys cannot read reports or manage connections.

Protocol references: Meta's generated AdAccount API, AdsInsights fields, Meta Business SDK access-token and app-secret setup.