A really useful group of events are ones that can detect the error messages displayed on your site. But these can be difficult to get right. Lets go through creating events to detect error messages, and some pitfalls to watch out for.
What’s the difference between an error message and an error code? In some sites, no difference at all – all you have to work with is a message string the user sees. But if you have a site that supports multiple languages, you may have the same error message presented in two or more language-specific strings. If you have this situation, you are going to want to know not just the specific string being shown, but how often each error condition displayed regardless of the language. For this, you will need for the site developers to insert an error code (it can be "non-displayable” in the page), as well as the error message.
Here’s an example: class="fError">! There are no ...<!--ErrCode:FA65—></
After you’ve isolated the error string from it’s surroundings, to break that string into the language-specific error message as well as the error code requires only two simple regular expressions:
$REMessage = /(.*?)<--/;
$RECode = /<!--ErrCode:(.*?)-/;
Getting the error string separated from its surroundings, though, that may be tricky…
First, Last, Count, and Aggregate Field Errors
If the site has only one error message on a page, a simple hit attribute and pattern is all you need, but in practice it is seldom that simple. Most often, the site may have multiple error messages on a single page. In order to understand which error messages are most common, we need to extract every error message.Hit attributes combined with Basic mode events can record the first error, or the last error, or the number of errors on a single page, but there is no provision in tealeaf for an event to record a collection of errors. The best we can do is create an event that will aggregate all of the errors into one string. We are going to need an advanced mode event to do the aggregation.
Visible and Invisible Errors
The event to aggregate the errors would be much easier if all error messages were visible, but alas that is not always so. In many sites, the developers will deliver all the error messages as part of the HTML of the page, but will use a CSS display attribute to control the visibility of the message. So we need to further refine our event so it only records Visible errors. Here are examples that show the same error message in multiple visible and invisible forms.
Visible:
class="fError">! There are no ...<!--ErrCode:FA65--></div>
class="fError"><br />! Make a selection for ...<!--ErrCode:TI1--></span>
class="fError">! Please enter a valid...<!--ErrCode:A21--><BR></span>
class="fError">! Please select a proper option.</span></p> – Note that the developers left out the error Code!
class="fError" style="color:#CC0000;">! Please enter a New ...<!--ErrCode:V1--><br/></span>
Invisible:
_CustomValidator1" class="fError" style="color:#CC0000;display:none;"></span><p class="fError" visible="False"></p> -- Note that this doesn't even have the trailing <span>
class="fError">< – This is an “empty” error message
Ignored: (our business users have told us don’t want to include this error when analyzing message)
class="fError" style="font-size:80%">! Your membership is expired.</div><
Regular Expression Patterns
The following Regular Expressions (RE) will capture each type of field error. There is some overlap - patterns which are both invisible and empty will fire both of their respective REs. Instead of writing down what each pattern is doing, let me send you to a on-line tool for making REs that will do a great job – just paste the RE into the online tool, check ‘Explain’ and hit submit. I’ve looked at dozens of RE test tools – this is my personal favorite, and the one I use when developing advanced mode events: http://myregextester.com/index.php
$REVisible = /class="fError(?:" style="color:#CC0000;){0,1}">(.+)<\/(?:span|div)/;
$REInvisible = /(?:class="fError" style="color:#CC0000;display:none;"|class="fError" visible="False">)/;
$REEmpty = /class="FError"><\/(?:span||div)/;
$REIgnored = /class="FError" style="font-size:80%">/;
Known Error Patterns
Grouping together the known, invisible, empty, and ignored patterns into one pattern “Known”:
$REknown = /class="FError"(?: style="color:#CC0000;display:none;">| style="color:#CC0000;">| visible="False">| style="font-size:80%">|><\/span|><\.+/span|><\.+/div)/;
Event Coverage
Because of the complexity, we’ll also want to have some code to check our event coverage – are we counting every visible error, and ignoring every invisible error? are there any errors that don’t fit our definition of either visible or invisible or ignored?
We can do this on every page with the following events
- [BB] count every occurrence of “class=”ferror” (and alternate formulation with one apostrophe, and no apostrophe or double-quote characters, and zero or multiple white-space characters.
- /class\s*=\s*([‘”])ferror\1\s/ig
- [BB] count every occurrence of Known Field Errors
- [E] count every occurrence of unknown field errors on a page (total – visible – invisible)
Events and Dimensions for Error Codes and Messages.
Finally! We get to the actual events, dimensions, and report groups. In the interest of brevity, I’ll present the Aggregate Visual Field Error Code information. If you want the details on First Visible Field Error and Last Visible Field Error on a page, you can copy/modify these. I will show you the “guts” of the javascript in the advanced mode event for each of these, as well.
All of these events depend on the triggering event G:Err:NumberOfVisibleFieldErrorCode:E When the event G:Err:NumberOfVisibleFieldErrorCode:E appears on a hit, then each of the following events are evaluated. In this event, we set the conditions “statuscode = 200, URL does not include tealeaftarget”, and whatever other conditions you may want to exclude (for example,excluding a specific domain).
In order to search repeatedly through a response, we need a hit attribute (HI) that will extract the response; G:ResponseBody with start tag of <html and end tag </html. In each of the following events, we use the HI to extract the entire response body into a local variable. When Regular Expressions are applied repeatedly to a string, there are internal pointers that remember how much of the string was parsed. If we tried to call the HI function for the response body in each loop , those pointers get reset. So we make a local copy, and loop the regular expression against the local copy.
Events:
G:Err:AggregateVisibleFieldErrorCodeOnPage:BB – [ADV] string consisting of all the visible field-level error codes on a page. Iterate over the response body for the REVisible pattern. Each time a match occurs, extract from the match string the error code. Accumulate the multiple error codes with ‘:::’ as a separator. Store this string as the value of the event.
function YOURNAMESPACE$E__G_ERR_AGGREGATEVISIBLEFIELDERRORCODEONPAGE_E__634853855183542782()
{
if ($F.getLastFact("YOURNAMESPACE.F_E__G_ERR_NUMBEROFVISIBLEFIELDERRORCODEONPAGE_E__634761380708236960").HitNumber == $H.HitNumber)
{
$REVisible = /class="fError(?:" style="color:#CC0000;){0,1}">(.+)<\/(span|div)/ig;
var $str = $P["YOURNAMESPACEL.P__G_RESPONSEBODY__634753590986008896"].firstValue();
var $cnt = 0;
var $resultstr = "";
while ($matches = $REVisible.exec($str)) {
if ($matches != null) {
if ($matches[1] != null) {
$RECode = /<!--ErrCode:(.*?)-/;
var $RECodeMatch = $RECode.exec($matches[1]);
if ($RECodeMatch != null) {
if ($RECodeMatch[1] != null) {
$cnt++;
$resultstr += $RECodeMatch[1]; $resultstr += ":::";
}
}
}
}
}
if ($cnt > 0) {
// Set fact for Report Group: No Dimension Report Group
$F.setFact("YOURNAMESPACE.F_E__G_ERR_AGGREGATEVISIBLEFIELDERRORCODEONPAGE_E__634853855183542782", $resultstr);
}
}
}
G:Err:FirstVisibleFieldErrorCodeOnPage:BB Iterate over the response body for the VisibleRE pattern. Each time a match occurs, do nothing until the last match. Then split the match string into message and code. Store the code string as the value of the event
G:Err:FirstVisibleFieldErrorCodeOnPage:BB Test the VisibleRE pattern against the response body. Take just the first match. Split the match string into message and code. Store the code string as the value of the event
$REVisible = /class="fError(?:" style="color:#CC0000;){0,1}">(.+)<\/(span|div)/ig;
var $matches = $REVisible.exec($P["UNITEDCONTINENTAL.P__G_RESPONSEBODY__634753590986008896"].firstValue());
if ($matches != null) {
if ($matches[1] != null) {
$RECode = /<!--ErrCode:(.*?)-/;
var $RECodeMatch = $RECode.exec($matches[1]);
if ($RECodeMatch != null) {
if ($RECodeMatch[1] != null) {
// Set fact for Report Group: No Dimension Report Group
$F.setFact("UNITEDCONTINENTAL.F_E__G_ERR_FIRSTVISIBLEFIELDERRORCODEONPAGE_BB__634761678018624416", $RECodeMatch[1]);
}
}
}
}
G:Err:AnyVisibleFieldErrorOnPage:E Is the reportable event we look at to see what errors are happening on a page. This event is a simple “OR” of the six BB events, so that, if the first/last/aggregate Visible Error Code/Message events fire, any of them, the Report Groups on this event will record the six values, and the URL (page) on which they occurred.
Note that recording all six dimension values may be overkill for your analytics group. I like to record all six for a few days, and review them with the business information consumers. If they agree that the aggregate dimensions are all they need, it’s easy to remove the unneeded dimensions. You will also want to be wary of the Message dimensions. While these are certainly more consumer-friendly than the error codes, storage for long strings of aggregated error messages may prove to be a concern. If you decide to record this information, keep an eye on the aggregate table usage over a few weeks, and plan to re-evaluate its usefulness and it’s storage cost.
The Results
After putting these together we can analyze the errors that happen on a specific page. We do this by looking at the event G:Err:AnyVisibleFieldErrorOnPage:E, and homing in on specific URL or groups of URLs, and looking at the error dimensions. When this event fires, we are recording (and viewing) the errors that appear on that page.
On what pages do field errors occur the most often?
On any specific URL, what are the most common visible field errors (aggregate of all errors on the page)?
What are the most common “last seen” error codes when a user abandons the checkout process
The truly actionable information you can glean is “last seen error when purchase is abandoned”. This is the favorite information for a lot of data consumers. Understanding this helps understand what it is about the site that most often impedes the purchase process.
This works because we defined our dimension to record the “lastest” value of a visible error event. We define an event that fires at the end of a session if we detect that abandonment took place (e.g. FPR:Abandoned:S, which is defined as FPR:ReviewRevenueR:S AND NOT FPR:ConfirmRevenueV:S), and we assign our six error dimensions to report groups assigned to this event. We don’t need the URL as part of this Report group, because as a end-of-session event, the URL dimension would haphazardly record whatever URL happened to be the last one in the session (and most often that would be the tealeaftarget which occurs when the uiSDK phones home the information for the last page). However, the “lastest” error messages may not be the error messages on the last page of the checkout process abandonment, if the user goes and visits other parts of the site, like searches, after their last checkout process page.
So this event is the closest we can get using the built-in tealeaf reporting tools. To get closer to the truth, a better approach would be to use cxConnect to record the error event in an external BI data warehouse, and use analysis queries to ask “for every abandoned sessions, which was the last checkout process page seen, and what were the errors shown”.
Within the limits of the tealeaf reports, here are the “last seen visible error codes when purchase is abandoned”.
We’ve filtered to eliminate the [Null} value. If a checkout process is abandoned, and there are no visible field errors in the session, then [Null] is recorded for this dimensions. In this specific site, many automated tools get to the first page of the checkout processes, producing a “Null” entry here when the automata “abandons” its checkout. An external BI data warehouse would allow better refining these numbers to eliminate robots.
Good luck error hunting! I hope this piece will help you better understand some of the event and dimension concepts in Tealeaf V8.