FreeThe +45-page Authentication Analytics Whitepaper — measuring real login journeysDownload
Back to Overview

Track Login and Form Errors in Adobe Analytics

Events, dimensions and link calls for tracking login and form errors in Adobe Analytics, plus the error classes that never reach a report at all.

Vincent Delitz
Vincent Delitz

Created: August 13, 2026

Updated: August 13, 2026

Track Login and Form Errors in Adobe Analytics

1. Login and Form Errors are the Part nobody instrumented#

Most Adobe Analytics implementations track what worked. The form submitted, the page loaded, the order completed. Errors get added later, usually after somebody asks why conversion dropped on the login page and nobody in the room can answer.

Key Facts
  • Track an error with a counter event, a stable error code and a custom link hit so it is recorded without creating a page view.
  • Keep validation errors, system errors and user decisions separate, because they have different owners and require different responses.
  • Do not send raw error messages as dimension values: identifiers, timestamps and uncontrolled text create privacy and cardinality problems.
  • Browser and operating system prompts need authentication-specific instrumentation; an ignored passkey autofill offer does not generate an event Adobe can report.
WhitepaperAuthenticationAnalytics Icon

Authentication Analytics Whitepaper. Practical guidance, rollout patterns and KPIs for passkey programs.

Get Whitepaper

Adobe has everything you need for that: a counter event for the error, a dimension holding the error code and a link call to send both without a page view. None of it is switched on by default. The way you set it up decides whether the report stays readable once real traffic hits it.

1.1 What this article covers#

Sections 2 to 6 build the implementation: which events and dimensions to create, how to fire them without a page view, how to measure form abandonment now that the old plugin is gone and how to keep the error dimension out of Adobe's Low Traffic bucket. Section 7 is the part no tagging plan reaches, because on a login page a whole class of errors never touches your page at all.

2. Split Validation Errors, System Errors and User Decisions#

Three kinds of failure get lumped together under "error" and each one needs different treatment.

ClassExampleWho fixes it
Validation errorEmail format rejected, password too short, one-time code expiredProduct and UX
System errorIdentity provider returns 500, rate limit hit on code requestsEngineering
User decisionBiometric prompt dismissed, passkey offer ignoredNobody, until it is measured

Mixed together they produce a chart that goes up and tells you nothing. Separate them as they arrive, with a dimension that names the class. Doing it later in a report is not possible, because the data no longer says which kind of error it was.

The third class is where authentication differs from a checkout form. A dismissed Face ID sheet is not a bug and it is not a neutral event either. It is a user who wanted to log in and did not.

One common case fits none of the three, and it is worth naming before you build the taxonomy: a one-time code requested and then never used. The message may have failed to arrive, it may have landed in a spam folder, or the user may have given up waiting. From the page all three look identical. Classifying it as a user decision would put a possible delivery failure in the wrong bucket, which is exactly what section 2 is trying to prevent. Keep it as its own drop-off, unclassified until another signal tells you which it was. Section 7 comes back to it.

3. Create the Error Event and the Error Dimensions#

3.1 The Error and Form Events#

Under Success events in report suite settings, create counter events:

EventNameFires when
event10ErrorAny tracked error surfaces
event11Form StartThe user interacts with the first field of a form
event12Form CompleteThe form submits successfully

Counter is the default type and simply counts the hits that carried the event. Keep the error event generic and let the dimensions carry the detail. Ten separate error events would cost ten slots in the report suite and tell you nothing a breakdown does not.

3.2 The Error Dimensions and their Expiry#

DimensionHoldsExpiry
eVar20Error code, e.g. auth_invalid_credentialsHit
eVar21Error class: validation, system or userHit
eVar22Flow step where it happenedHit

Hit expiry is the right default here, because an error belongs to the moment it happened. Let the dimension persist and the failure gets attached to every later hit in the visit, which inflates every breakdown built on it.

The third row is the one people skip. A custom link call carries no page name, so the page report cannot tell you where the error happened. Put the step of the flow into its own dimension instead.

3.3 Track several Errors on one Hit with a List Variable#

A form that fails validation on four fields produces four errors at once. An eVar holds one value, so four eVar hits would misreport both the error count and the form count.

Use a list variable instead. It holds several values in one variable, separated by a delimiter you set in the report suite settings. Adobe gives you three of them, each value can be up to 255 bytes, there is no limit on the variable as a whole and it takes up to 250 unique values per visitor.

A list prop is the cheaper alternative, but the whole variable is capped at 100 bytes including the delimiters. That ceiling arrives faster than it sounds. Four codes the length of auth_invalid_credentials, 24 bytes each, already come to 99 bytes with the delimiters counted, so the fifth error on that hit is lost.

4. Fire the Error Event without a Page View#

An error usually does not navigate, so a page view call is the wrong vehicle. Use a custom link call.

4.1 Send Errors with AppMeasurement#

The s.tl() method takes three arguments: the element that was clicked, the type of link and a name for the report. Type o stands for a custom link, d for a download and e for an exit link. Adobe never tracks custom links on its own, so every error call has to be written by hand.

s.events = "event10"; s.eVar20 = "auth_invalid_credentials"; s.eVar21 = "system"; s.eVar22 = "login_submit"; s.linkTrackVars = "events,eVar20,eVar21,eVar22"; s.linkTrackEvents = "event10"; s.tl(true, "o", "Login Error");

Three things have to line up. The event has to be in s.events, events has to be listed in linkTrackVars and the specific event has to be listed in linkTrackEvents.

Those two lists are filters, not requirements. Adobe documents that an empty or undefined linkTrackVars sends all variables and an undefined linkTrackEvents sends all events. The moment you set them, as the snippet above does and as every tag manager does, they become the complete list of what is allowed through. Anything not named gets dropped.

That is the trap. Forget one entry and the call still goes out, the event is just missing from it and nothing anywhere warns you. It is the most common reason a correctly written error tracking implementation reports nothing at all.

Write eVar20 in linkTrackVars, not s.eVar20. The object identifier belongs in the assignment, not in the list.

4.2 Send Errors with the Web SDK#

With the Web SDK the same information travels in a sendEvent call:

alloy("sendEvent", { data: { __adobe: { analytics: { events: "event10", eVar20: "auth_invalid_credentials", eVar21: "system", eVar22: "login_submit", }, }, }, });

There are no allow-lists to forget here, so the trap from the previous section disappears with them.

Debugger Icon

Experiment with passkey flows in the Passkeys Debugger.

Try for Free

5. Measure Form Abandonment without the Form Analysis Plugin#

Adobe once shipped a Form Analysis plugin that flagged which field a user last touched before leaving a form. It did not survive the move to AppMeasurement.js and Adobe's plug-ins overview no longer carries it. Implementations that still reference it are usually running an archived copy.

Three pieces do the same job today:

  1. A form start event fired on the first meaningful interaction, typically the first field that receives focus. Do not fire it on page load, because that counts impressions as starts.
  2. A form complete event fired on successful submission, confirmed by the server, not by the click.
  3. A calculated metric that subtracts complete from start for abandonment or divides one by the other for a completion rate.

For field-level detail, instrument focus and blur yourself and write the last field touched into a dimension on the abandonment call. That is more work than the old plugin and it is the version that survives a framework migration.

One caveat applied to the plugin and applies to your own version too: every abandonment sends an extra link call and Adobe counts each one as a server call. On a high-traffic login page, that is a conversation about your licence rather than a code review.

6. Send Error Codes to keep the Dimension out of Low Traffic#

Error tracking breaks on cardinality more often than on bugs.

Adobe buckets dimension items under Low Traffic once a dimension exceeds its unique value threshold, by default 2,000,000 unique values per dimension, per report suite, per calendar month. Bucketed values are aggregated together instead of being reported individually.

The mechanism is easier to see than to describe. Three failures of the same kind collapse into one dimension item or into three:

Three rules keep the dimension under the threshold:

  • Send codes, not messages. auth_invalid_credentials is a dimension value. "Sorry Jane, the password for jane@example.com is incorrect (ref 8f2c1a)" is a new value for every user and every attempt.
  • Never send identifiers. Session IDs, request IDs and timestamps inside the error string are the fastest route into Low Traffic.
  • Use classifications for the human text. Upload a lookup that maps the code to a readable label. The report stays readable, the dimension stays small.
Igor Gjorgjioski Testimonial

Igor Gjorgjioski

Head of Digital Channels & Platform Enablement, VicRoads

We hit 80% mobile passkey activation across 5M+ users without replacing our IDP.

See how VicRoads scaled passkeys to 5M+ users, alongside their existing IDP.

Read the case study

7. Login Errors that never reach the Report#

Everything above assumes the error surfaces somewhere your code can see it. In authentication, a large class of failures does not.

  • A cancelled biometric prompt. The user dismisses Face ID or Windows Hello. Nothing renders, nothing navigates.
  • A login cancelled by a lost window focus. The Web Authentication API cancels a running passkey login as soon as the browser window loses focus, so switching to a password manager app ends the login in silence.
  • An ignored passkey offer. The browser offers the passkey in its own autofill dropdown, drawn outside your page. There is no element, no click handler and nothing submitted that you could instrument.
  • A login finished on a phone. The user scans a QR code on the desktop and confirms on the phone. The phone loads no page and fires no tag.
  • A one-time code that never arrives or never gets typed. The user requests an SMS or email code and leaves the page to fetch it. Whether the message was delivered, whether it was read and whether the user gave up in their inbox all happen outside the browser. Your page sees a code request followed by silence, which is indistinguishable from a user who simply left.

Those five fail in different ways, so it helps to sort them before planning any work.

Three of the first four are within reach of a wrapper around the navigator.credentials call. A dismissed prompt and a cancellation through lost focus both make that call fail, so the wrapper catches them. The phone case is the third: the call completes back on the desktop, because the phone only stands in as the authenticator, so the outcome is measurable even though the middle of the journey is not.

The ignored autofill offer is the one case with nothing to catch. The call never finishes, it just sits there until something else ends it.

The one-time code case needs a different instrument again, because nothing throws and nothing fails. What makes it readable is the shape of the step: how many code requests were followed by a submitted code, how long the gap between the two was, and how often a second code was requested before the first one was used. None of that is an error your code catches. All of it is a drop-off you can count, and it applies to every SMS, email OTP and step-up MFA flow you run today, with or without passkeys in the picture.

So a wrapper buys you the attempt and the outcome. It does not buy you the reason. When the call does fail, the browser returns NotAllowedError whether the user cancelled, the login timed out or no passkey was on the device. The W3C declined to split that into separate codes, because telling the cases apart would let any site test whether a visitor has a passkey.

That single code is a container, not a reason. No vendor including us can open it. What separates the cases is what surrounded the call: how long it ran, whether the browser could offer a passkey at all, what the user did next. Those signals have to be collected while the login is running, because no report can reconstruct them later. WebAuthn errors covers the full taxonomy.

8. How Corbado can help#

Everything up to section 6 makes the errors your page can see reportable. The section above is the remainder. In a login it is the part that matters most. Corbado Observe is the authentication observability layer that captures it, by measuring the passkey login itself instead of the page around it. It runs client-side next to your existing login, works with any identity provider and sends UUID-only telemetry with no PII.

  • Errors split by what they mean: user decisions, system errors and platform issues separated as they arrive, which is the three-way split from section 2 applied to authentication instead of rebuilt by hand.
  • A container error turned into a reason: the same NotAllowedError broken down by call duration, by client capability and by what the user did next.
  • Regressions visible as patterns: an error spike after a browser or OS update shows up as a shape in the funnel instead of noise in a support queue.
  • One user, end to end: when a ticket says "I cannot log in", replay that exact session with events, errors and device context.
  • The OTP step as a measured step: code requested, code submitted, code accepted, with the time between them and the repeat requests in view, so the silent version of section 7 becomes a drop-off you can act on.

None of this waits for a passkey rollout. The same instrumentation reads your existing password, SMS, email OTP and MFA flows, which is where most teams find their first surprise. Your Adobe error tracking keeps doing what it is good at. The login itself gets measured where it happens.

9. Conclusion: instrument the Error, then check what is missing#

Error tracking in Adobe Analytics is a solved problem for anything your code can catch. Create one generic error event, carry the detail in Hit-scoped dimensions, fire it through s.tl() with linkTrackVars and linkTrackEvents set correctly, use a list variable when a hit carries several errors and send codes instead of messages.

Then compare what your error report says against your identity provider and your support queue. The gap between them is made up of the failures from section 7, the ones that never reach a tag. That is usually the part to fix first. The authentication error rate definition and the authentication analytics playbook are the next two stops.

Corbado

About Corbado

Corbado is the Passkey Intelligence Platform for large-scale CIAM teams running consumer authentication. We help you see what IDP logs and generic analytics tools can't: where passkeys, passwords, OTP, social login and fallback journeys succeed, stall or fail, which devices and browsers create friction, and when an OS update silently breaks login. Two products: Corbado Observe layers process mining and observability across authentication journeys. Corbado Connect adds managed passkeys with analytics built in alongside your IDP. VicRoads runs passkeys for 5M+ users with Corbado (+80% passkey activation). Talk to a Passkey Expert

Frequently Asked Questions#

How do I track error messages in Adobe Analytics?#

Create a counter event for the error, a dimension for the error type and fire both through a custom link call instead of a page view. With AppMeasurement the event has to be in s.events, events has to be listed in linkTrackVars and the specific event has to be listed in linkTrackEvents. Set the error dimension to expire on Hit, because an error belongs to the moment it happened and not to the rest of the visit.

Should I put the raw error message into an eVar?#

No. An eVar holds 255 bytes and Adobe buckets a dimension under Low Traffic once it exceeds 2,000,000 unique values per report suite per calendar month, so raw messages with identifiers or timestamps in them destroy the breakdown they were supposed to provide. Send a stable error code as the dimension value and keep the human-readable text in your own logs or in a classification.

How do I track more than one error on the same hit?#

Use a list variable. Adobe provides three of them, each value can be up to 255 bytes, the variable itself has no total byte limit and it supports up to 250 unique values per visitor. A form that fails validation on four fields at once is exactly the case list variables exist for, because four separate eVar hits would misreport both the error count and the form count.

Can Adobe Analytics track form abandonment?#

Not on its own. The legacy Form Analysis plugin that flagged the last field a user touched did not survive the move to AppMeasurement.js and has no official replacement. What works today is a form start event, a form complete event and a calculated metric that subtracts one from the other, plus a field-level dimension if you instrument focus and blur yourself.

Why do login errors not show up in Adobe Analytics at all?#

Because a large class of authentication failures never produces a page event. A cancelled biometric prompt, a passkey ceremony that times out, a WebAuthn call cancelled by focus loss and an ignored passkey autofill offer render nothing, navigate nowhere and click nothing. A wrapper around the WebAuthn call catches most of it: a dismissed prompt and a focus-loss cancellation reject the call, while a completed cross-device flow resolves it on the desktop. An ignored autofill offer produces nothing to catch, because the call stays pending. Either way this is an instrumentation question, not a reporting one.

Substack Icon

Subscribe to our Passkeys Substack for the latest news.

Subscribe

See what's really happening in your passkey rollout.

Explore the Console

Share this article


LinkedInTwitterFacebook