Working with journeys

The expected state and how to read a diff

Updated: October 3, 2026 For: analyst, head of analytics

Every scan replays the recorded journey, and the scanner writes down what each step sent to the dataLayer and to analytics tools. On its own that tells you little. It becomes useful once there is something to compare against. That yardstick is the expected state: a record of which events and parameters each step should send.

This guide explains how the expected state is built, what is compared against it and what is not, and what the buttons next to a change actually do.

How the expected state is built

You do not write the expected state by hand. It is set up automatically; until it is ready, the test detail shows this notice:

The “Preparing” state in the test detail
Warm-up: no scan yet has been good enough to build the expected state from.

A scan can establish the expected state when it:

  • ended with the status “Completed”,
  • covered every recorded step, with none of them failing or skipped,
  • ended every step on the recorded page and not somewhere else,
  • found every target through your recording, meaning the recorded selector or a fallback selector, and not by text, by coordinates or by a substitute element the replay inferred on its own,
  • had no fix proposal waiting for any of its steps,
  • measured at least some analytics events on at least half of the steps.

Events that appear only occasionally do not trigger alerts.

If several scans in a row fail these conditions, the notice changes to “Monitoring is not running for this journey” and says what needs doing. Usually that means re-recording the journey or finding out why the replay does not reach the end.

What is compared

For every step the scanner compares three things: whether the same events arrived, whether they carry the same parameters, and whether each parameter has the same JavaScript type (string, number, boolean, array, object). Nested objects are compared field by field, for example ecommerce.items[].price.

Values are not compared. A journey may well add a different product to the cart on every run, so item_id and price change, and that is fine. A change from 1290 to 990 is therefore not reported. When value arrives as the string "990" instead of a number, though, that is a type change.

Expected state Scan Changes dataLayer · purchase value: 1290 number dataLayer · purchase value: 990 number number = number dataLayer · purchase value: 1290 number dataLayer · purchase value: "990" string number → string Google Analytics 4 · page_view adStorage: granted CZ Google Analytics 4 · page_view adStorage: denied CZ granted → denied
A value may change freely between scans. A type change is reported, and for consent signals so is a value change.

Two details. An empty value (null, undefined, an empty string) does not count as a type, so a move into or out of it is not reported. And in requests to tool servers, the scanner leaves out parameters that change on every page load, such as timestamps or random identifiers. From dataLayer pushes it leaves out only Google Tag Manager's own events and keys (gtm.*) and pushes without an event name, such as consent or configuration calls.

For consent, the value is what matters. The scanner reads the Google Consent Mode signals (adStorage, analyticsStorage, adUserData, adPersonalization) from the gcs and gcd parameters that Google tags send, and compares them with the expected state. When a step that had granted now shows denied (or the other way round), the scan reports it as “Consent changed”.

Expected consent values are kept separately for each country a scan runs from. When you scan from a new country, the first usable scan from there only records its consent values. If the scanner cannot read a value, it reports “Consent unreadable”. That is a measurement failure, not a fault on your site.

Which changes a scan reports

In the dashboard API value
Event removed missing_event
Event added extra_event
Param removed missing_param
Param added extra_param
Type changed param_type_changed
Event drifted event_drifted
Consent changed consent_value_changed
Consent unreadable consent_unreadable
Step not verified step_not_reached

A change's colour is its severity. Critical changes are red, typically “Event removed” and “Consent changed”: the site stopped doing what the expected state says it does. Warnings for you to judge are amber, for example “Param removed”, “Type changed” or “Event added”. Information is white, for example “Param added”. “Step not verified” and “Consent unreadable” mean we could not measure. They take the colour of their severity like any other change, but they say nothing about your site.

The changes panel of one step with a removed event, a type change, an added parameter, a drifted event and a consent change
The changes of one step. Each pending change has three actions; an approved one carries a label.

Drifted events and required events

An event belongs to the step during which it arrived. A slow tag therefore sometimes fires only in the next step. So that this does not turn into a “removed” plus “added” pair, a tolerance of ±1 step applies. An event that arrived one step away is therefore not reported at all. Its parameters and consent are still compared, and the scan shows any change in them at the step where the expected state places the event. The same applies when an event repeated over consecutive steps moves by one step as a whole. An event that moved by more than one step is reported as “Event drifted”. It is a warning, so for a vendor you watch it can trigger an alert like any other change.

The tolerance does not apply to the required events purchase, begin_checkout, add_payment_info, consent_update, consent_default. When the site's own tagging (dataLayer, adobeDataLayer, Google Analytics 4, Google Tag Manager) does not send one in its step, the scan reports it as “Event removed”, not as drifted. Events with the same name that other tools send on their own are not covered by this rule. The one exception is a purchase in Adobe Analytics: a request to Adobe Analytics whose success events include purchase counts as a required purchase too.

When a step does not complete during the replay, the events missing from it are not held against the site. Instead the scan shows one “Step not verified” row.

Which vendors are monitored

Captured data of every vendor stays visible in the step tabs. Changes are listed and alerted only for vendors you watch. Every test watches dataLayer, adobeDataLayer, Google Analytics 4, Adobe Analytics by default, each only if the site uses it. In a mobile app, the app's own Google Tag Manager container is watched too. In “Monitored vendors” you can switch any vendor on or off, the dataLayer included; a vendor switched back on is watched from then on. A vendor marked “May report false changes” has not passed our noise check yet. The pull request check does not depend on this list.

What the buttons next to a change do

  • “Correct” writes the change into the expected state as it is now. An added event or parameter becomes required, so its later disappearance is reported; a removed one is taken out of the expected state. A type change writes the new type, a consent change the new value, and a drifted event is moved to the step where it appeared. “Approve all” does the same for every pending change, in a step's changes panel for that step and in the scan's toolbar for the whole scan.
  • “May be missing”, next to an added or removed event or parameter, writes it as optional: neither its presence nor its absence is reported again, but its type is still checked whenever it appears.
  • “Ignore” stops reporting the change. Ignoring a whole event also covers its future parameters.
  • “It's an error” keeps the change as a “Known regression” until a later scan no longer finds it.

Hover over a button or reach it with Tab to see what it does.

Why a person must review the first expected state

The expected state is built from the first usable scans exactly as they measured it. The scanner does not know what your tagging should look like. It only knows what it looked like then. If the site was already sending value as a string at that point, the order confirmation had no purchase, or a consent signal was granted earlier than it should be, that becomes the expected state. Later scans then report only departures from the bug, not the bug itself.

So once the warm-up is over, open the scans the expected state was built from and go through them step by step:

  • do the steps contain the events that belong there, for example purchase on the order confirmation step,
  • do the key parameters have the right type, for example value as a number,
  • do the consent signals match what the visitor chose on the banner at that point.

If something is off, fix the site. The next scan shows the fix as a change, and you write it in with “Correct”. You get the most out of monitoring when the tagging is right before the first scan.



Found a mistake in this guide, or is something missing? Tell us

All guides