Blog

Meta Conversions API and Cookie Consent: The Complete Setup Guide

Key Takeaways

  • Meta CAPI sends data server-to-server, bypassing browser consent, but still requires user consent under GDPR
  • Event match quality (EMQ) scores drop when you strip personal data from non-consented events
  • The consent_status field in CAPI lets you flag events as opted-in or opted-out for Meta to filter
  • Running CAPI without consent checks risks regulatory action and advertising account restrictions
  • ConsentStack propagates consent state to your server so CAPI events only fire with valid consent
ScenarioPixel BehaviorCAPI BehaviorLDU Setting
EU user, consent grantedFires normallyFires normally with full user datadata_processing_options: []
EU user, consent deniedBlocked by CMPMust NOT fireN/A
California user, no opt-outFires normallyFires normallydata_processing_options: []
California user, opted outLDU enabled or blockedMust fire with LDU or be skippeddata_processing_options: ['LDU'] with country/state codes
GPC-enabled browserTreat as CCPA opt-outApply LDU or skipdata_processing_options: ['LDU'] with country/state codes

Key takeaway: The Pixel and CAPI must behave consistently. If the Pixel is blocked for a user, CAPI should not fire either (or must fire with appropriate restrictions).

Read our CCPA cookie consent requirements guide

Meta's Limited Data Use (LDU): CCPA Compliance

When LDU is enabled, Meta will count the conversion for reporting but will not use the data for ad targeting, custom audiences, or lookalike modeling. LDU is designed for CCPA's opt-out model, where you still want to count conversions but can't let Meta use the data for advertising.

The data_processing_options Parameter

javascript
// California user who has opted out
const eventPayload = {
  data: [{
    event_name: 'Purchase',
    event_time: Math.floor(Date.now() / 1000),
    action_source: 'website',
    user_data: {
      em: [hashSHA256(userEmail)],
      ph: [hashSHA256(userPhone)],
      client_ip_address: clientIP,
      client_user_agent: userAgent,
      fbp: fbpCookieValue,
      fbc: fbcCookieValue
    },
    custom_data: { currency: 'USD', value: 99.99 },
    data_processing_options: ['LDU'],
    data_processing_options_country: 1,    // United States
    data_processing_options_state: 1000    // California
  }]
};

Setting data_processing_options to [] (empty array) is different from omitting it. The empty array explicitly signals "no restrictions apply."

Do not apply LDU as a substitute for consent in GDPR jurisdictions. For EU users who haven't consented, do not send the CAPI event at all.

Read our US state privacy laws guide

EMQ is Meta's scoring system (1-10) measuring how well server events match to user profiles. Higher EMQ means better attribution and lower CPA.

User Data FieldMatch ImpactConsent Dependency
em (hashed email)HighRequires marketing consent
ph (hashed phone)HighRequires marketing consent
fbp (_fbp cookie)Medium-HighRequires cookie consent
fbc (_fbc click ID)HighRequires cookie consent
client_ip_addressMediumGenerally operational data
client_user_agentLowTypically not consent-gated
external_idMediumRequires marketing consent

When a user declines marketing consent under GDPR, you cannot send their hashed email, phone, external_id, fbp, or fbc. Sending IP and user agent alone produces an EMQ so low the event is essentially unmatchable.

There is no EMQ vs. compliance tradeoff. Sending user data without consent to improve EMQ is a GDPR violation that will cost far more than any ad performance improvement. Maximize EMQ within the consent boundary: send every available field for consenting users, skip the event entirely for non-consenting GDPR users, and use LDU for CCPA opt-outs.

Read about cookie consent banner performance

Architecture Overview

  1. Browser: CMP collects consent, stores state in cookie/localStorage
  2. Client-to-server: Consent state passes to backend via cookie or request body
  3. Server: Backend reads consent state and decides: send, send with LDU, or skip
  4. Server-to-Meta: Event sent with appropriate data_processing_options
javascript
function getDataProcessingOptions(consentState) {
  if (consentState.jurisdiction === 'gdpr') {
    if (!consentState.marketing) {
      return { shouldSend: false, reason: 'GDPR: marketing consent not granted' };
    }
    return { shouldSend: true, options: { data_processing_options: [] } };
  }

  if (consentState.jurisdiction === 'ccpa') {
    if (consentState.optedOut) {
      return {
        shouldSend: true,
        options: {
          data_processing_options: ['LDU'],
          data_processing_options_country: 1,
          data_processing_options_state: getStateCode(consentState.region)
        }
      };
    }
    return { shouldSend: true, options: { data_processing_options: [] } };
  }

  return { shouldSend: true, options: { data_processing_options: [] } };
}

Most CMPs store consent in a first-party cookie your server can read:

javascript
function getConsentStateFromRequest(req) {
  const consentCookie = req.cookies['cs_consent'];
  if (!consentCookie) {
    return {
      marketing: false,
      jurisdiction: detectJurisdiction(req),
      optedOut: false,
      region: detectRegion(req)
    };
  }
  const consent = JSON.parse(decodeURIComponent(consentCookie));
  return {
    marketing: consent.categories?.marketing === true,
    jurisdiction: consent.jurisdiction || 'none',
    optedOut: consent.optedOut || false,
    region: consent.region || null
  };
}

A platform adapter translates CMP consent categories into platform-specific signals. For Meta, this means:

  1. Pixel script blocking until marketing consent is granted (GDPR)
  2. Consent event signaling via fbq('consent', 'revoke') and fbq('consent', 'grant')
  3. LDU flag management on Pixel events for CCPA opt-outs
  4. Advanced Matching control based on consent state

ConsentStack's Meta platform adapter handles all of this automatically. For CAPI, the consent state stored in the consent cookie is available for your backend to read and make send/skip decisions.

See ConsentStack's platform integrations

Common Mistakes

CAPI is often built by backend engineers who don't know consent checking is needed. The frontend CMP blocks the Pixel, but the server sends every conversion to Meta regardless.

Fix: Add consent-state checking to every CAPI event handler.

Mistake 2: Not Setting LDU for California Users

Teams conflate GDPR's opt-in model with CCPA's opt-out model. Under CCPA, you don't need prior consent. You need to respect opt-outs via LDU.

Fix: Default: track with data_processing_options: []. On opt-out: switch to ['LDU'] with state code.

If the Pixel set _fbp and _fbc cookies before consent was properly granted, using those values in CAPI events means processing non-consensual data.

Fix: Only include fbp and fbc when cookies were set after consent. If your CMP properly blocks the Pixel before consent, these cookies won't exist for non-consenting users.

Mistake 4: Inconsistent Logic Between Pixel and CAPI

Different teams, different codebases, different consent checks. The Pixel is blocked by the CMP. CAPI uses a custom backend check. The two don't agree on what "marketing consent" means.

Fix: Use a single source of truth. The CMP's consent cookie should drive both frontend (Pixel blocking) and backend (CAPI decisions).

User grants consent, triggers CAPI events, then revokes. Future events should stop immediately. If data deletion is requested, use Meta's User Data Deletion API.

Deduplication: Pixel and CAPI Together

Meta deduplicates based on event_id and event_name. If consent is denied, neither channel fires. If granted, both fire with the same event_id:

javascript
// Pixel (browser, only if consent granted)
fbq('track', 'Purchase', { value: 99.99, currency: 'USD' }, { eventID: serverEventId });

// CAPI (server, only if consent allows)
await sendConsentAwareCAPIEvent({
  eventName: 'Purchase',
  eventId: serverEventId,
  // ... rest of payload
});

Frequently Asked Questions

Conclusion

Meta's Conversions API doesn't eliminate consent requirements. It moves them from the browser to the server, where there's no CMP automatically blocking scripts. Your code is the only enforcement layer.

For GDPR: check consent before sending CAPI events. For CCPA: apply LDU when users opt out. Include data_processing_options in every payload. Use the same consent state for both Pixel and CAPI. Test every scenario in Meta's Events Manager.

ConsentStack's platform adapters handle the Pixel-side consent flow and provide the consent cookie your backend needs for CAPI decisions. One CMP configuration, consistent consent state across all channels.

Start free with ConsentStack

Try ConsentStack free. No credit card. No sales call. Meta consent signaling working correctly alongside Google, TikTok, and every other platform in under 10 minutes.