This is cross-posted from the 33 Sticks blog.
Adobe’s Opt-In Service is a tool provided by Adobe to help decide which Adobe tools should or should not fire, based on the user’s consent preferences. It has some advantages I don’t see folks talk about much:
- It manages your Adobe tags (Analytics, ECID, Target) at a global level. If you’ve got it set up right, you don’t need to make any changes to your logic that sets variables and fires beacons (you don’t need a ton of conditions in your TMS)- any rule’s Analytics or Target actions will still run, but not set cookies or send info to Adobe.
- When your existing variable-and-beacon-setting logic runs while the user is opted out, Adobe queues that logic up, holding on to it just in case the user does opt in. Any Adobe logic can run, but no cookies are created and no beacons get fired until Adobe’s opt-in service says it’s ok.
This latter point is very important, because in an opt-in situation, frequently consent happens after the initial page landing – the page that has campaign and referrer information. If you miss tracking on that page altogether, you will lose that critical traffic source information. Some folks just re-trigger the page load rule, which (depending on how you do it) can mess up (or at bare minimum, add complexity) to your data layer or rule architecture. So I’m a big fan of this “queue” of unconsented data.
You can even experiment and see for yourself- this site has a globally-scoped s object, and an already-instantiated Visitor object. Open the developer console, keep an eye on your network tab, and put this in, to opt out of analytics tracking on my site:
adobe.optIn.deny('aa');//opt out analytics
Then run code that would usually fire a beacon:
s.pageName="messing up Jenn's Analytics data?" //you can tell me a joke here, if you want
s.t()
No beacon!
Now let’s pretend you’ve clicked a Cookie Banner and granted consent. Fire this in the console:
adobe.optIn.approve('aa');//opt in analytics
And watch the beacon from earlier appear! Isn’t that magical?
Side note: The variables sent in the beacon will reflect the state when time the beacon would have fired. I tested this- if I do this sequence:
adobe.optIn.denyAll()
s.prop15="firstValue"
s.t() //no beacon fires because consent was denied
s.prop15="secondValue"
adobe.optIn.approveAll() //now my beacon fires
…the beacon that fires will have prop15 set to “firstValue”- it reflects things at the time the beacon would have fired.
To re-iterate: if you have the ECID service set up correctly, it will still look like your Analytics/Target rules fire, but the cookies and beacons won’t happen until consent is granted.
How to Use within Adobe Launch*
Most of Adobe’s documentation assumes you’re using Adobe Launch*, and even then, leaves out some key bits. The Experience Cloud ID extension has what you need to get things set up, but is not the complete solution (you can skip this and go straight to the Update Preferences section below if you want the part that’s not particularly well documented). Let’s walk through it, end-to-end:
Opt-In Required
First, tell Launch when to require Opt-in.
If it’s just “yes” or “no”, then it’s simple enough. If you want to decide dynamically (based on region, for example), then you need to create a separate Data Element that returns true or false. For example:
if(_satellite.getVar("region")=="Georgia"){
return false //Georgia doesn't care about consent. Yet.
}else{
return true
}
To be honest, to me it’s always made more sense to just click the “yes” option, then further down, change up people’s default pre opt-in settings based on region.
Store Preferences
I’ll admit, I’ve never used these, but I think they’re self-explanatory enough: the ECID is offering to store the user’s consent settings for you. This seems convenient, but I’ve never seen a set up where the overall CMP solution doesn’t already store the consent preferences somewhere, usually in a way that is not Adobe-specific.
Previous Permissions/Pre Opt In Approvals:
The “Previous Permissions” and “Pre-Opt-In Approval” settings work very similarly, but “Pre-Opt-In Approval” is more of a global setting, and “Previous Permissions” is user-specific (and overwrites “Pre-Opt In Approval”). In other words: Pre-Opt-In Approval settings are used when we don’t have Previous Permissions for the user.
The key here is the format of the object, usually in a Custom Code Data Element, that Adobe is looking for:
{
aam:true,
aa:true,
ecid:true,
target:true
}
…where true/false for each category would be figured out dynamically based on the user. So your data element might have something like this:
var consent={}
if(_satellite.cookie.get("OptInInfoFromMyCMS").indexOf("0002")!=-1){
consent.aa=true
consent.target=true
consent.ecid=true
}else{
consent.aa=false
consent.target=false
consent.ecid=false
}
return consent
Important but often missed: updating preferences
All of the above is great for when the ECID extension first loads. But what about when there is a change in the user’s preferences? As far as I know, this can’t be done within the ECID extension interface, and it’s not particularly well documented… this is where you have to use some custom code which is kind of buried in the non-Launch optIn service documentation or directly in the Opt-In reference documentation. (I think we’re up to 4 different Adobe docs at this point?)
When your user’s preferences change, perhaps because they interacted with your banner, there are various objects on adobe.optIn that you can use:
adobe.optIn.approve(categories, shouldWaitForComplete)
adobe.optIn.deny(categories, shouldWaitForComplete)
adobe.optIn.approveAll():
adobe.optIn.denyAll():
adobe.optIn.complete(); //have adobe register your changes if you set shouldWaitForComplete to True
The “shouldWaitForComplete” bit is a true or false- if true, then Adobe won’t register your changes until you fire adobe.optIn.complete(). If false, or omitted, then Adobe will immediately recognize those changes.
So I might have a rule in Launch that fires when the user clicks “approve all” on my banner (or if I’m using oneTrust, within their OptanonWrapper function), with a custom code action that looks something like this:
adobe.optIn.approve('target',true);//opt in target
adobe.optIn.approve('aa',true);//opt in analytics
adobe.optIn.approve('ecid',true);//opt in the visitor ID service
adobe.optIn.complete();
Which could also be accomplished like this:
adobe.optIn.approve(['target','aa','ecid']);
Or even just this (in my tests, this did not require adobe.optIn.complete()):
adobe.optIn.approveAll();
What if I’m Not Using Launch?
If you’re not using the Launch ECID extension, then the initial stuff- the stuff that WOULD be in the extension, as detailed above, is all handled when you instantiate the Visitor object. This is all covered Adobe’s Opt-In Service documentation, which I personally found a bit confusing, so I’ll go through it a bit here.
As far as I can tell, this bit from their documentation:
adobe.OptInCategories = {
AAM: "aam",
TARGET: "target",
ANALYTICS: "aa",
ECID: "ecid",
};
// FORMAT: Object<adobe.OptInCategories enum: boolean>
var preOptInApprovalsConfig = {};
preOptInApprovalsConfig[adobe.OptInCategories.ANALYTICS] = true;
// FORMAT: Object<adobe.OptInCategories enum: boolean>
// If you are storing the OptIn permissions on your side (in a cookie you manage or in a CMP),
// you have to provide those permissions through the previousPermissions config.
// previousPermissions will overwrite preOptInApprovals.
var previousPermissionsConfig = {};
previousPermissionsConfig[adobe.OptInCategories.AAM] = true;
previousPermissionsConfig[adobe.OptInCategories.ANALYTICS] = false;
Visitor.getInstance("YOUR_ORG_ID", {
"doesOptInApply": true, // NOTE: This can be a function that evaluates to true or false.
"preOptInApprovals": preOptInApprovalsConfig,
"previousPermissions": previousPermissionsConfig,
"isOptInStorageEnabled": true
});
Could be simplified down to this, if we skip the extra OptInCategory mapping and the preOptInApprovalsConfig and previousPermissionsConfig objects:
Visitor.getInstance("YOUR_ORG_ID", {
"doesOptInApply": true,
"preOptInApprovals":{
"aa":true,
},
"previousPermissions": {
"aam":true,
"aa":false,
},
"isOptInStorageEnabled": true
});
Literally, that’s it. That’s what that whole chunk of the code in the documentation is trying to get you to do.
Beyond that, updating preferences happens just like it would within Launch, as detailed above.
Side note- what’s up with adobe.OptInCategories?
I’m not sure why Adobe has that adobe.OptInCategories object in their docs. These two lines of code have the same effect, but one seems much more straightforward to me:
previousPermissionsConfig[adobe.OptInCategories.AAM] = true;
previousPermissionsConfig["aam"] = true;
The adobe.OptInCategories mapping is set by Adobe- despite it being in their code example, you don’t need to define it, it comes like this:
I’m guessing this was to make it so folks didn’t have to know that analytics is abbreviated as “aa”, but… if you find the extra layer doesn’t add much, you can bypass it entirely if you want.
Conclusion
Once I understood it, I came to really like how Adobe handles consent.
I am by no means considering myself an expert, or trying to make a comprehensive guide. But the documentation is lacking or spread out, so most of this took some trial and error to really understand, and I’m hoping my findings will prevent others from having to do that same trial and error. That said, I’d love to hear if folks have experienced something different, or have any best practices or gotchas they feel I left out.
*still not calling it “Adobe Experience Platform Data Collection Tags”