Execute a rule only once in Adobe Launch

When you are managing an implementation of Adobe tools like Analytics, chances are you are using Adobe Experience Platform Data Collection, formerly known as Adobe Launch, Adobe Dynamic Tag Management, or the Adobe Tag Manager (and no, this is not a SEO text, it’s the actual list of names. I will still call it Launch for the near future) to implement other tags as well. While Launch is great for making implementation of Adobe’s own tools very fast and easy, managing other tools is not always so straight forward.

A common requirement for those 3rd Party tags is to fire a certain tag or pixel only once. What once really means (once per session, user, day, year?) might differ from tag to tag, so as a result it can be surprisingly difficult to fulfill those requirements reliably and consistently. On top of those varying definitions of once, Adobe Launch has some matching functionality built-in which is rarely completely understood by the end users. In the end your data might end up being less reliable than you might think.

Because of this situation and my own experiences debugging those discrepancies, I wanted to create this post to look at what Launch has built in already, find out how it works under the hood, and give recommendations on which approach should be used in which situation. So, let’s start!

The test setup

First, we need a very simple rule that we can use for testing. In Launch, I created this simple rule that, on every click, shows an alert message to show the rule just ran:

Test rule in Launch

When I put this rule on a (very real) page and click anywhere, I see the alert as expected:

The rule just ran!

Now that it is immediately obvious if our rule fired, we can take a look at what Adobe Launch has in store for us to limit my enthusiasm when it comes to clicking on very real pages.

Max Frequency condition in Adobe Launch

Back in Launch, we can add a condition to our test rule and select the Max Frequency Condition Type of the Core extension. Doing that, we are greeted with a set of two options: The count and the unit, the latter with quite an assortment of options:

Max Frequency settings in Adobe Launch

To start, I didn’t change any settings and went with the “once every 1 page views” default. A quick build later, my rule does exactly what we would expect. Only the first click on the page now triggers the alert to show up. But how does this work? How does Launch remember what has happened? Let’s reverse-engineer this. As a first step, we go to the dev tools of our browser (typically by hitting F12 on the keyboard), open the Application tab (1) and look at the Local Storage on our page (2):

Launch’s local storage objects

We can see that Launch is automatically keeping track of a bunch of information using Local Storage. If you want to ruin someone’s day, ask them if those values are listed on their page’s privacy notice. Anyways, there is a very interesting key that keeps track of how many pages were viewed (3). Now, what happens when I click anywhere on the page?

Launch’s local storage after our condition executed

Interesting! Now we have one more key in our Local Storage with a very peculiar name (again, have fun with that privacy notice). The key includes something that looks like the id of a Launch rule, and the value equals the pagesViewed key we saw before. So when the condition is evaluated, Launch checks the persisted value that belongs to the rule that should execute and, if it exists, compares its value to the number of pages viewed. That pages viewed counter is incremented, you guessed it, on page load. If the persisted value is lower or not existent, the rule is good to run. That way we can also cover cases like “every 3 page views”, by simply shifting the count a bit. Quite elegant!

But wait a minute! You may call me pedantic, but I know the rule id of each and every rule I have ever created (don’t challenge me on that, just believe me), and that one in the screenshot ain’t it! And even worse: When I change the name of the rule in Launch, push the changes live, and click on the page again, there now is a second Local Storage value:

New version of the rule, new Local Storage key

What the heck? Where does that come from?! As it turns out, Launch doesn’t actually namespace that Local Storage object with the rule id, but with the id of the rule revision. To refresh your memory, a new revision is created every time you change the rule so you can go back to a previous version in the interface:

Selecting rule revisions in the Adobe Launch interface

So if we use this condition type, a new version of the storage key will be created with every new version of the rule. This may lead to a lot of scruffy keys in your user’s browsers if you change those rules around a lot. On the other hand, this gives us the option to “reset” the rule execution memory simply by changing the name and revert the change immediately, creating new revisions every time. That detail will become even more important later on!

Firing a rule once per Session in Adobe Launch

Now that we know how the “every x page views” rule works, let’s turn to the other options. For testing, I configured the rule to fire “once every 1 sessions”. On the page, it again does exactly what we would expect: Regardless of the number of pages I viewed, it only shows the alert once every session. But how is a session defined in this case? Let’s take a look at the Local Storage again:

Session restricted max frequency rule

We can see that our key again includes the rule revision, but this time is named with a .session suffix. And instead of using the pagesViewed value, it is equal to the sessionCount key. But how does Launch know when a session starts and ends? In the screenshot above, there are no timestamps to be found, so how does it keep track of that information? The answer again lies in our dev tools, but on the Session Storage tab instead of the Local Storage:

Hunting for session information in Adobe Launch

There is quite a bit of information about the session here. When Launch loads, it tries to figure out if a new session has just begun. It does that by looking for the landingPage key in the Session Storage (had to learn that myself by looking at the source code of the extension). If it doesn’t exist, Launch assumes a new session has started and increments the number of sessions. But there are a number of things to keep in mind when using the “once every x sessions” logic because it is based on the Session Storage:

  • A session for Launch is not the same as for, for example, your analytics system. Session Storage elements persist for as long as a current tab is open. That means that if the rule is executed but the user reopens their browser, the rule will execute again. If the user never closes your page, the rule never executes again. So you may see a rule triggering more than once per Visit or less than once in analytics because of this.
  • Another important detail is that Session Storage is specific to only a certain browser tab, not the browser window. If I trigger the rule on my page and immediately open it in another tab, the rule will execute there again. That is because the landingPage Session Storage object is not available in the new tab, causing Launch to think a new session has started.
  • Because the storage objects are namespace with the rule’s revision id, there may be cases where a rule fires multiple times within a session if you publish a new version of the rule.

Firing a rule once per User or timeframe in Adobe Launch

Now that we know all that, let’s change our rule one more time to fire “once every visitor”. One build and click later, this is how my Local Storage looks:

Local Storage for rule firing once per Visitor

Having done everything above by now, there is little surprise here. Instead of holding a numerical value, this condition only sets the value “true” to signify that the rule has fired. Contrary to Session Storage, Local Storage works across tabs, so a new tab can’t fool this condition to fire again. Nice, no surprises for once!

The last option to evaluate are the time related options. For my test, I changed the rule to fire “once every 1 minutes”. Building, reloading, clicking, we see this:

Once per minute persistence

Just as we would expect: A Local Storage object (nice, tab-persistence!) with a .minute suffix. Now we have a timestamp as value, so Launch can keep track of when the rule executed. One thing that I noticed here: With this kind of namespacing, using a “every x minutes” twice in a rule may trigger some weird behavior, since two conditions try to work with the same Local Storage key. But I wouldn’t know why you would want to do that, so I don’t think it’s an issue if you keep your conditions in order. With all this information, there is just one little thing we should talk about when creating conditions like that in Launch…

Order of rule conditions matters in Adobe Launch

There is one important thing in rule conditions in Launch that not a lot of people think about: What happens if we have more than one condition in a rule, but the first one fails? The answer is simple. Conditions are checked from left to right, and if one fails, everything after that condition is never checked. But why does this matter to us here?

Let’s pretend we have two conditions in our rule. One is the familiar “once per 1 page views” condition from above, the other is a domain check that, in this case on purpose, always fails. What do you think is the difference between those two ways of organizing those conditions show on this screenshot?

Conditions in different ordering

Let’s first try out the left variant, with Max Frequency being the last thing to check. Build, reload, click, look at the Local Storage. What do we see?

Rule execution is not persisted on failing conditions

Nothing! That is very important to notice. Because the condition never gets to execute after the first one, it also doesn’t persist the value in Local Storage. So with this order of conditions, having Max Frequency as the last condition, the rule would only count the times all other conditions were true as well. So far, so good. But what happens if we reverse the order like on the right, checking Max Frequency as the first thing? Build, reload, click, no alert showing up (as expected), but what do we have here:

What are you doing in my (swamp of a) Local Storage?

What? It still counted although the rule didn’t execute? That’s right! Remember that the condition does not know anything about the context it is executed in. It doesn’t know if the rule, after all conditions were evaluated, actually fired. So it only knows if things worked out until the point where it is checked itself. This is a fundamentally important thing to know about conditions in general and this one in particular. We don’t count “rules fired” but “conditions evaluated to true” here!

My creativity is certainly limited, but I would imagine you would always want to put the Max Frequency condition as the very last thing in your chain of conditions. For example, you may have a requirement like “fire this tag once per session on the homepage”. With this requirement, it is crucial to respect the correct order. If a user starts their session on a different page than the homepage, the Max Frequency may evaluate to true before the page is checked. If the user then goes to the homepage, the rule will not fire, since the Max Frequency condition was already triggered on the page before.

Of course this situation might also cause you headaches if you create some custom logic using cookies. As long as you don’t set the cookie in a dedicated action after everything else in the rule, your result might not be what you actually want. Pro tip: Use the Launch debug mode (just put _satellite.setDebug(true) in your browser’s console and hit enter) to check which conditions in your rule fail or succeed at runtime.

Summary

I think we all learned a lot today about how the Max Frequency condition works, how conditions are executed, and what to do with it all. To summarize, here is what to look out for:

  • Max Frequency conditions use Local Storage and Session Storage. Depending on your browser support matrix, this may or may not be an issue for you. For example, I’ve seen some issues with this for in-app browsers on Android (those are very popular for social media apps), which don’t support Local Storage at all by default.
  • Those Local Storage objects are named according to the rule’s revision id, not the rule id. As a result, your rules might fire unexpectedly if you publish a new version of the rule (which might especially be an issue for “once for every visitor” requirements like consent management).
  • The page views restriction counts page loads, which might not be what you expect if you use a single page application (SPA).
  • If you want your rule to fire only once per session, be aware that Launch does not follow the same definition of a session as your analytics system. Especially if users use multiple tabs or never close their browser, you may see some funky results. If that is an issue, using custom logic in Custom Code may be the way to go for you.
  • Instead of counting “executions of rule” the Max Frequency condition only counts “times condition evaluated to true”.
  • Because of the previous point, order of execution of conditions matter a lot for Max Frequency. Make sure your conditions are in the correct order. If you are unsure, you probably want to have the frequency conditions as the very last condition in your rules.

Overall, there are quite a few things to keep in mind when using the Max Frequency condition in Adobe Launch. But once I understood how I need to set things up, everything started to make a lot of sense. I hope this post was useful for you and you now too feel confident using this condition!