Skip to main content

Cross-Channel Matches

Cross-channel matches enrich your users' profiles, enabling you to reach them across several channels.

Match Providers

Match Providers are first or third-party data sources that have their own user IDs (such as cookies, email hashes or login IDs), which can be matched to your first-party IDs.

Match Providers can be added to the system using the Dashboard under Collect > ID Matches, by clicking the Match Providers tab, followed by the New Match Provider button.

Dashboard Match Providers

The following fields are available:

  • Name: Name for the Match Provider.

  • ID: Identifier for the Match Provider. It is used later to create matches for this specific match provider.

  • Active: Enables/Disables matches from this Match Provider.

  • Allow extra iFrame Activations: Enables activations on match requests to this provider, replying to the match request with the appropriate HTML or Image tag as set in the Activation.

  • Encryption Key: When enabled, the new user ID parameter must be base64-encoded and encrypted using AES/ECB with the SHA256 hash of this key kept secret. Using encryption, particularly when done server-side, ensures the user ID is unusable in the event of a data leak during transport.

    Examples of how to encrypt your ID with the configured encryption Key:

    JavaScript
    <script src="//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/sha256.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/mode-ecb-min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/pad-nopadding-min.js"></script>

    <script type="text/javascript">
    var EmailHash = {
    generate: function(email, secret) {
    var hash = CryptoJS.SHA256(email.trim().toLowerCase());
    var aesKey = CryptoJS.SHA256(secret);
    var encrypted = CryptoJS.AES.encrypt(hash, aesKey, {
    mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7
    });
    var b64 = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
    return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
    }
    }
    </script>
    PHP
    <?php
    class Security {
    private static function encryptAES($input, $key) {
    $data = openssl_encrypt($input, "AES-256-ECB", $key, $options=OPENSSL_RAW_DATA);
    return $data;
    }

    private static function base64url_encode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
    }

    public static function encrypt($input, $key) {
    $hashValue = hash("sha256", strtolower(trim($input)), $raw_output = true);
    $aes256Key = hash("sha256", $key, $raw_output = true);
    $encryptedHashValue = Security::encryptAES($hashValue, $aes256Key);
    return Security::base64url_encode($encryptedHashValue);
    }
    }
    ?>
    Java
    import java.io.UnsupportedEncodingException;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.util.Locale;
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.SecretKeySpec;
    import org.apache.commons.codec.binary.Base64;
    import org.apache.commons.codec.digest.DigestUtils;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;

    public class EmailHash {

    public static String generate(String email, String secret) throws
    UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException,
    nvalidKeyException, IllegalBlockSizeException, BadPaddingException {

    byte[] hash = DigestUtils.sha256(email.trim().toLowerCase(Locale.US).getBytes("UTF-8"));
    byte[] key = DigestUtils.sha256(secret.getBytes("UTF-8"));
    BouncyCastleProvider provider = new BouncyCastleProvider();
    Cipher encryptor = Cipher.getInstance("AES/ECB/PKCS5Padding", provider);
    SecretKeySpec skey = new SecretKeySpec(key, "AES/ECB/PKCS5Padding");
    encryptor.init(Cipher.ENCRYPT_MODE, skey);
    byte[] encrypted = encryptor.doFinal(hash);
    return Base64.encodeBase64URLSafeString(encrypted);
    }
    }

Matching User IDs

To merge together 2 or more User IDs under the same user profile we provide 2 approaches:

Recognizing Users across Sites and Devices

The adstax_uid cookie is per-browser. To recognize the same profile across different sites, devices, or after login, match additional stable identifiers (such as a hashed email or a CRM ID) to the profile. Do not replace one identifier with another; link them so they resolve to a single profile.

A single match request can carry several identifiers at once:

pcdp("event", "match", {
"providerId": "web",
"user": [
{ "type": "email_sha256", "id": "d1df1acbdc99f3d0f80dc298471b0a2a01124e9371ea9e707805b19f4ffe8b6e" },
{ "type": "crm", "id": "customer-12345" }
]
});

Use distinct ID types for distinct identifiers, and prefer reliable ID types when using them to match profiles.

Matching a stable identifier at login is especially important when Audience is served from a Kevel-managed domain, since the third-party adstax_uid cookie may not persist. See Domain Delegation and First-party Cookie for more guidance.

Considerations for Matching User IDs

Invalid IDs

Matched IDs need to be well structured. When sending an invalid ID for a given type, such as an MD5 hash to a SHA256 ID type, the match is refused. Refer to User IDs for details on supported user IDs.

Limit of IDs per ID Type

It is possible to configure a limit on the number of IDs of a given type a profile might have. For example, limiting email_sha256 IDs to 3. This prevents profiles from being incorrectly merged, for example, when using shared computers without clearing the cookies. After that limit is reached, matches with a new ID of that type are discarded. The maximum number of entries per ID type can be agreed upon with your Customer Success Manager.

Unreliable IDs

Match requests with unreliable User IDs do not merge user profiles. This means that user attributes are not changed when matching a reliable User ID with an unreliable one. For more information about unreliable IDs, see the section about User Identifiers.

IDs from Offline Imports

By default, online order and imported transaction data that share the same order ID provide a hint that the user doing both is the same. If two different user IDs are used to identify these data points, we will merge those IDs into a single profile.

Customers can opt out of this behavior if they want to keep offline and online data isolated, for example, for data privacy reasons. One of the primary consequences of this option is the duplication of metrics related to orders. Since two separate user profiles are associated with the same order ID, metrics such as order count, revenue, and other order-related analytics may reflect duplicated values.

If you want to prevent order IDs from merging user profiles, please ask your Customer Success Manager to enable this option.

Insights