Skip to content

Per-Platform Consent Integration Specification

Technical specification for cookie consent banner developers to integrate per-platform consent with Conversion Bridge.

Overview

Conversion Bridge supports two consent models:

  1. Category-Based Consent - Traditional model where consent is granted for broad categories like "analytics" or "marketing"
  2. Per-Platform Consent - Granular model where consent is granted for individual platforms (e.g., Google Analytics, Meta Pixel, Microsoft Clarity)

This document covers per-platform consent integration for consent management platforms (CMPs) that allow users to grant or deny consent for specific tracking services rather than broad categories.

Platform Identifiers

Conversion Bridge uses the following platform identifiers:

PlatformIdentifierCategory Fallback
Google Analytics 4ga4analytics
Google Adsgoogleadsmarketing
Meta Pixel (Facebook)metamarketing
Microsoft Clarityclarityanalytics
Microsoft Adsmicrosoftmarketing
Conversion Bridge Journeysconversion_bridgeanalytics
TikTok Pixeltiktokmarketing
PostHogposthoganalytics
Matomomatomoanalytics
Pinterest Tagpinterestmarketing
LinkedIn Insightlinkedinmarketing
Twitter/X Pixeltwittermarketing
Snapchat Pixelsnapchatmarketing
Reddit Pixelredditmarketing

Consent State Architecture

Conversion Bridge maintains consent state in a JavaScript object:

var consent = {
    categories: [],  // e.g., ['analytics', 'marketing']
    platforms: []    // e.g., ['ga4', 'conversion_bridge', 'googleads']
};
// Presence in array = consent granted

Consent Mode Determination

The system automatically determines which consent mode is active:

  • Platform Mode: If consent.platforms.length > 0, the system uses platform-specific consent
  • Category Mode: Otherwise, it falls back to category-based consent

For Conversion Bridge internal tracking (journeys/sessions):

function can_cb_track() {
    if (consent.platforms.length > 0) {
        return consent.platforms.includes('conversion_bridge');
    }
    return consent.categories.includes('analytics');
}

JavaScript API

Setting Per-Platform Consent

Use ConversionBridge.platform_consent() to set consent for individual platforms:

/**
 * Set consent for a specific platform
 *
 * @param {string}  platform - Platform identifier (e.g., 'ga4', 'meta')
 * @param {boolean} allowed  - Whether consent is granted (default: false)
 */
ConversionBridge.platform_consent( platform, allowed );

Examples:

// Grant consent for Google Analytics
ConversionBridge.platform_consent( 'ga4', true );

// Deny consent for Meta Pixel
ConversionBridge.platform_consent( 'meta', false );

// Grant consent for multiple platforms
ConversionBridge.platform_consent( 'ga4', true );
ConversionBridge.platform_consent( 'clarity', true );
ConversionBridge.platform_consent( 'meta', true );
ConversionBridge.platform_consent( 'conversion_bridge', true ); // For CB journeys

Setting Category-Based Consent

Use ConversionBridge.category_consent() for category-based consent:

/**
 * Set category-based consent
 *
 * @param {string}  category - 'analytics' or 'marketing'
 * @param {boolean} allowed  - Whether consent is granted
 */
ConversionBridge.category_consent( category, allowed );

Examples:

// Grant analytics consent
ConversionBridge.category_consent( 'analytics', true );

// Deny marketing consent
ConversionBridge.category_consent( 'marketing', false );

Checking Consent State

/**
 * Check if consent is granted for a category
 *
 * @param {string} category - 'analytics' or 'marketing'
 * @returns {boolean}
 */
ConversionBridge.has_consent( category );

/**
 * Get full consent state object (for debugging)
 *
 * @returns {object} { categories: [...], platforms: [...] }
 */
ConversionBridge.get_consent();

Examples:

// Check if marketing consent is granted
if ( ConversionBridge.has_consent( 'marketing' ) ) {
    // Marketing tracking is allowed
}

// Get full consent state
console.log( ConversionBridge.get_consent() );
// { categories: ['analytics'], platforms: ['ga4', 'conversion_bridge'] }

Events

Events Dispatched by Conversion Bridge

Conversion Bridge dispatches these custom events on the window object when consent changes:

cb_consent_category

Fired when category-based consent changes. The event detail is the array of granted categories.

window.addEventListener( 'cb_consent_category', function( e ) {
    console.log( e.detail );
    // ['analytics', 'marketing']  - array of granted categories

    // Check specific category
    if ( e.detail.includes( 'marketing' ) ) {
        // Marketing consent was granted
    }
});

cb_consent_platform

Fired when per-platform consent changes. The event detail is the array of granted platforms.

window.addEventListener( 'cb_consent_platform', function( e ) {
    console.log( e.detail );
    // ['ga4', 'googleads', 'conversion_bridge']  - array of granted platforms

    // Check specific platform
    if ( e.detail.includes( 'meta' ) ) {
        // Meta consent was granted
    }
});

Platform Consent Listener Pattern

Each platform in Conversion Bridge listens for both events to handle consent updates:

// Category consent listener
window.addEventListener( 'cb_consent_category', function( e ) {
    updatePlatformConsent( e.detail.includes( 'marketing' ) );
});

// Platform consent listener
window.addEventListener( 'cb_consent_platform', function( e ) {
    updatePlatformConsent( e.detail.includes( 'googleads' ) );
});

Integration Patterns

Pattern 1: Direct API Integration

Call Conversion Bridge methods directly from your consent banner's callback:

// Your consent banner's callback when user makes choices
function onConsentUpdated( userChoices ) {

    // Map your platform identifiers to Conversion Bridge identifiers
    const platformMapping = {
        'google-analytics': 'ga4',
        'google-ads': 'googleads',
        'facebook-pixel': 'meta',
        'microsoft-clarity': 'clarity',
        'microsoft-ads': 'microsoft',
        'tiktok-pixel': 'tiktok',
        'conversion-bridge': 'conversion_bridge'
    };

    // Iterate through user's choices
    Object.keys( userChoices ).forEach( function( yourPlatformId ) {
        const cbPlatform = platformMapping[ yourPlatformId ];
        if ( cbPlatform ) {
            ConversionBridge.platform_consent( cbPlatform, userChoices[ yourPlatformId ] );
        }
    });

    // Trigger pageview after consent is set (if analytics allowed)
    if ( ConversionBridge.has_consent( 'analytics' ) ) {
        ConversionBridge.pageview();
    }
}

Pattern 2: Event-Based Integration

If your CMP dispatches custom events:

// Listen for your CMP's consent event
document.addEventListener( 'your_cmp_consent_updated', function( e ) {
    const consent = e.detail.consent;

    // Example: Your CMP provides consent per service
    if ( consent.services ) {
        consent.services.forEach( function( service ) {
            // Map service names to CB platform identifiers
            const platform = mapServiceToPlatform( service.name );
            if ( platform ) {
                ConversionBridge.platform_consent( platform, service.allowed );
            }
        });
    }
});

Pattern 3: Initial State on Page Load

Set consent state on page load based on stored preferences:

document.addEventListener( 'DOMContentLoaded', function() {
    // Wait for both your CMP and Conversion Bridge to be ready
    if ( typeof ConversionBridge === 'undefined' ) {
        return;
    }

    // Get stored consent from your CMP
    const storedConsent = YourCMP.getStoredConsent();

    if ( storedConsent && storedConsent.platforms ) {
        Object.keys( storedConsent.platforms ).forEach( function( platform ) {
            ConversionBridge.platform_consent( platform, storedConsent.platforms[ platform ] );
        });
    }
});

Complete Integration Example

Here's a complete example for a hypothetical CMP called "ConsentManager":

(function() {
    'use strict';

    // Platform identifier mapping
    const PLATFORM_MAP = {
        // Your CMP's service IDs : Conversion Bridge platform IDs
        'google_analytics_4': 'ga4',
        'google_ads': 'googleads',
        'facebook_pixel': 'meta',
        'microsoft_clarity': 'clarity',
        'microsoft_ads': 'microsoft',
        'tiktok_pixel': 'tiktok',
        'pinterest_tag': 'pinterest',
        'linkedin_insight': 'linkedin',
        'twitter_pixel': 'twitter',
        'snapchat_pixel': 'snapchat',
        'reddit_pixel': 'reddit',
        'conversion_journeys': 'conversion_bridge'
    };

    /**
     * Sync consent state from your CMP to Conversion Bridge
     */
    function syncConsentToConversionBridge( consentData ) {
        if ( typeof ConversionBridge === 'undefined' ) {
            console.warn( 'ConversionBridge not loaded' );
            return;
        }

        // Handle per-platform consent
        if ( consentData.services && Array.isArray( consentData.services ) ) {
            consentData.services.forEach( function( service ) {
                const cbPlatform = PLATFORM_MAP[ service.id ];
                if ( cbPlatform ) {
                    ConversionBridge.platform_consent( cbPlatform, service.consented === true );
                }
            });
        }

        // Fallback: Handle category-based consent if no per-platform data
        if ( ! consentData.services && consentData.categories ) {
            if ( consentData.categories.analytics !== undefined ) {
                ConversionBridge.category_consent( 'analytics', consentData.categories.analytics );
            }
            if ( consentData.categories.marketing !== undefined ) {
                ConversionBridge.category_consent( 'marketing', consentData.categories.marketing );
            }
        }

        // Trigger pageview after consent sync
        ConversionBridge.pageview();
    }

    /**
     * Initialize integration
     */
    function init() {
        // 1. Sync initial consent state on page load
        if ( window.ConsentManager && window.ConsentManager.getConsent ) {
            const initialConsent = window.ConsentManager.getConsent();
            if ( initialConsent ) {
                syncConsentToConversionBridge( initialConsent );
            }
        }

        // 2. Listen for consent changes
        document.addEventListener( 'ConsentManager:updated', function( e ) {
            syncConsentToConversionBridge( e.detail );
        });

        // 3. Handle consent banner acceptance
        document.addEventListener( 'ConsentManager:accepted', function( e ) {
            syncConsentToConversionBridge( e.detail );
        });

        // 4. Handle consent withdrawal
        document.addEventListener( 'ConsentManager:withdrawn', function( e ) {
            // Set all platforms to false
            Object.values( PLATFORM_MAP ).forEach( function( platform ) {
                ConversionBridge.platform_consent( platform, false );
            });
        });
    }

    // Wait for DOM and ConversionBridge
    if ( document.readyState === 'loading' ) {
        document.addEventListener( 'DOMContentLoaded', init );
    } else {
        init();
    }

})();

Server-Side Consent Handling

When Conversion Bridge sends events to the server, consent state is included in the payload:

{
    "event_type": "form_submit",
    "event_name": "Contact Form",
    "consent": {
        "categories": ["analytics", "marketing"],
        "platforms": {
            "ga4": true,
            "meta": false,
            "clarity": true,
            "conversion_bridge": true
        }
    }
}

The server uses this to determine which platforms should receive the event data via server-side APIs (e.g., Meta Conversions API).

Consent Priority

Conversion Bridge uses this priority order when determining consent:

  1. Per-Platform Consent (highest priority) - If any platform consent is set, platform mode is active
  2. Category Consent - Falls back to category if no platform consent is set
  3. Default - If no consent plugin configured, all consent is granted
// Example: Platform consent takes priority
ConversionBridge.category_consent( 'analytics', true );  // Category: analytics = true
ConversionBridge.platform_consent( 'ga4', false );       // Platform: ga4 = false

// Result: GA4 will NOT receive data (platform consent overrides category)
// But other analytics platforms without explicit platform consent will use category

Event Queue Behavior

When analytics consent is not granted:

  1. Events are queued in localStorage (key: cb_event_queue)
  2. Maximum queue size: 100 events
  3. Events expire after 48 hours
  4. When consent is granted: queued events are sent
  5. When consent is denied: queue is cleared

This ensures no data is lost if users grant consent later in their session.

Debugging

Console Logging

Enable debug mode in Conversion Bridge settings to see consent operations in the browser console.

When consent is denied, platform events will show detailed status messages:

[Conversion Bridge] Google Ads event: conversion {...}
[Conversion Bridge] ↳ Google Ads Consent Mode: ad_storage=denied - conversion will be modeled, not tracked with cookies

[Conversion Bridge] Meta event: Lead (fbq not loaded - script blocked, event NOT sent) {...}

[Conversion Bridge] Microsoft Ads event: form_submit {...}
[Conversion Bridge] ↳ Microsoft Ads: UET SDK not loaded (script blocked) - event queued but will NOT be sent to Microsoft

[Conversion Bridge] TikTok event: SubmitForm (ttq not loaded - script blocked, event NOT sent) {...}

Checking Consent State

// Check current consent state
console.log( ConversionBridge.get_consent() );
// { categories: ['analytics'], platforms: ['ga4', 'conversion_bridge'] }

// Check specific category consent
console.log( ConversionBridge.has_consent( 'marketing' ) );
// false

// Listen for consent changes
window.addEventListener( 'cb_consent_category', function( e ) {
    console.log( 'Category consent changed:', e.detail );
});

window.addEventListener( 'cb_consent_platform', function( e ) {
    console.log( 'Platform consent changed:', e.detail );
});

Understanding Console Output

When you see platform events in the console with consent denied:

PlatformWhat Happens
Google Ads/GA4 (Consent Mode)Events are sent but Google "models" conversions instead of tracking with cookies
Meta (script blocked)fbq function not available, event NOT sent to Meta
Microsoft (script blocked)UET SDK not loaded, events queued in array but NOT processed
TikTok (script blocked)ttq object not functional, event NOT sent to TikTok

WordPress Consent API Compatibility

If your CMP implements the WordPress Consent API, Conversion Bridge automatically integrates with it. The plugin:

  1. Listens to wp_listen_for_consent_change events
  2. Maps WP categories: statisticsanalytics, marketingmarketing
  3. Uses wp_has_consent() for initial state

If you implement the WP Consent API, category-based consent works automatically. For per-platform consent, you'll still need to call ConversionBridge.platform_consent() directly.

Best Practices

  1. Always set consent before triggering pageview - Ensure all platform consent is set before calling ConversionBridge.pageview()
  2. Handle both initial state and changes - Sync consent on page load AND listen for updates
  3. Use the correct platform identifiers - Refer to the platform table above
  4. Test consent withdrawal - Verify that denying consent properly stops tracking
  5. Consider the event queue - Be aware that events may be queued and sent later
  6. Map your services accurately - Create a clear mapping between your service IDs and Conversion Bridge platform identifiers
  7. Include conversion_bridge for journeys - If you want CB's internal journey tracking, grant consent for the conversion_bridge platform

Support

For integration support or to request additional platform identifiers, contact the Conversion Bridge development team.

Still need help?

If you have not yet found your answer in the documentation articles, please contact support

Contact support