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
- Obtain a Meta Marketing API access token with
ads_readand access to your ad account. A business system-user token can support an unattended connection; its account assignment and expiry remain managed in Meta. - 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. - 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.
- 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_idmatches first. Without it, a numericutm_campaigncan 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.