annotate
The annotate action draws annotations into the page and leaves them there. They stay up across steps, survive navigation, and appear in any recording or screenshot taken while they’re visible.
Here’s how annotate differs from the annotations option on a screenshot:
Use screenshot.annotations to mark up a single image. Use annotate to narrate a video, or to keep a redaction up across a whole flow.
Both accept the same annotation objects, so { "outline": "#submit" } means the same thing in either.
Options
Give the object at least one of:
add: Annotations to draw. Give one anidto update or clear it later. Adding an annotation with an id that’s already on screen replaces it.update: Changes to annotations already on screen, matched byid. Each entry replaces the annotation with that id. Updating an id that isn’t on screen fails the step, since it usually means a typo or an already-cleared annotation.clear:trueclears everything; a list of ids clears just those. Clearing an id that isn’t on screen does nothing.
clear runs before add, so { "clear": ["a"], "add": [{ "id": "a", … }] } reads as replacing a.
The screenshot annotations page covers the annotation objects themselves: the six types, targets, style, and the annotationDefaults theme. Four fields matter here that do nothing in a still screenshot:
id: A handle, so a later step can update or clear this annotation.track: Follow the element as the page scrolls or the layout shifts.transition: How the annotation enters and leaves.enteracceptsnone,fade,pop, ordraw.exitacceptsnoneorfade.durationMssets the length.duration: Milliseconds to stay up before clearing itself, with no pairedclearstep.
Set "transition": { "enter": "none" } on a blur you’re using to redact. An annotation that fades in leaves the content underneath readable for the length of the animation, and every frame of that is in the recording.
Annotate something that hasn’t loaded yet
An element target waits up to 5000 milliseconds for its element to appear, then fails the step. Set timeout on the target when you’re annotating something slower. Examples include a panel behind a fetch, or a dashboard that renders after a first sync:
This is find’s timeout, on the annotation’s target. Two things follow from that. It needs the object form of the target, since the string shorthand has nowhere to put it. It’s also per-target, so one slow element in a payload doesn’t make the others wait.
update re-resolves its target, so give it a timeout too when you point an annotation at something that isn’t on the page yet.
Outputs: the action exposes $$annotationCount, the number of annotations on screen after the step.
For comprehensive options, see the
annotatereference.
Examples
Narrate a recording
Annotations track the flow, moving from field to field as the walkthrough progresses.
Redact for a whole recording
The blur stays glued to every match while the page scrolls, and never animates in.
Show a note briefly
duration clears the annotation on its own.
How it works
Doc Detective draws annotations into a dd-annotation-layer element with its own shadow root, sitting above the page and ignoring pointer events. The page under test keeps behaving exactly as it would without annotations, and the page’s CSS can’t restyle them.
Doc Detective tracks the annotations itself, so they survive navigation: after a step loads a new page, it re-draws whatever is still up. Annotations last until an annotate step clears them, their duration elapses, or the test context ends.