---
name: confirm-an-action-in-a-browser-you-drive
description: Establish whether an action in somebody else's web interface actually happened, when a stale success looks like a fresh one and an open form looks like a failure.
runbook:
  schema_version: v1
  semver: 1.0.0
  profile: P1
  min_runtime_profile: R1
  domain: ci-cd
  targets:
    - linux
  trigger: manual
  execution: human-with-agent
  risk: reversible-write
  blast_radius: global
  duration: 5-30m
  capabilities: []
  publisher: std
  lang: en
  license: CC-BY-4.0
  relations:
    - kind: requires
      ref: std/publish-through-a-browser-already-signed-in@1.0.0
      why: How the browser comes to be signed in, and how to check the result as a stranger, are there and are not repeated here.
  inputs:
    confirmation:
      type: string
      required: true
      description: what the interface shows when the action succeeded
  steps:
    - id: s1
      kind: action
      title: Put the content in without the clipboard
      risk: reversible-write
      expect: the text is in the field, inserted directly rather than pasted
      on_fail: escalate:s9
      next: s2
    - id: s2
      kind: action
      title: Find the control, then click that element
      risk: reversible-write
      requires_approval: true
      expect: the click lands on the element the page returned, not on a coordinate
      rollback_ref: s8
      on_fail: escalate:s9
      next: s3
    - id: s3
      kind: wait
      title: Give the confirmation time to appear
      duration: 10s
      next: s4
    - id: s4
      kind: decision
      title: Is a confirmation on screen?
      question: Does the interface show the sign it shows on success?
      branches:
        none: s5
        default: s6
    - id: s5
      kind: wait
      title: Wait again before believing it failed
      duration: 10s
      retry:
        max: 2
        target: s4
      next: s7
    - id: s6
      kind: decision
      title: Is the confirmation this one?
      question: Does it say it happened just now, rather than minutes ago?
      branches:
        stale: s7
        default: s10
    - id: s7
      kind: check
      title: Look for the result itself, not the sign
      expect: the thing you did is visible where it would be if it worked
      on_fail: escalate:s9
      next: s10
    - id: s10
      kind: decision
      title: Is the interface offering something else now?
      question: Has a prompt appeared that would start a different action if you continued?
      branches:
        upsell: s11
        default: s12
    - id: s11
      kind: action
      title: Decline it explicitly
      risk: read-only
      expect: the prompt is closed by its decline, not by its continue
      next: end:success
    - id: s12
      kind: action
      title: Write down that it went out, and when
      risk: read-only
      expect: the run is recorded, so the next one does not have to guess whether this one happened
      next: end:success
    - id: s8
      kind: action
      title: Undo it, before doing it again
      risk: reversible-write
      requires_approval: true
      expect: the first attempt is removed, so a retry cannot become a duplicate
      next: end:aborted
    - id: s9
      kind: escalate
      title: Stop rather than repeat the action
      to: team:platform
  source:
    url: https://runbooks.directory/r/std/confirm-an-action-in-a-browser-you-drive/source.md
    fetched_at: 2026-09-04
    upstream_state: current
---

## When to reach for this

Something is being done through a web interface somebody else built, by a tool rather than
by hand — posting, submitting, approving — and the question afterwards is whether it
actually happened. That question is harder than it sounds, and getting it wrong in either
direction is expensive: a false failure leads to doing it twice, and a false success leads
to nobody doing it at all.

How the browser comes to be signed in, and why the result is checked from an account signed
into nothing, are in `std/publish-through-a-browser-already-signed-in`.

## The confirmation is late, and impatience costs a duplicate

The success indicator does not appear at the moment the action completes. Measured on one
interface: checking after three seconds showed nothing, and the action had in fact
succeeded. One release nearly went out twice on that.

Wait longer than feels necessary — ten seconds where three would seem generous — before
concluding anything. The cost of waiting is ten seconds. The cost of not waiting is a
duplicate that a reader has already seen.

## A stale confirmation is not your confirmation

The opposite mistake, and subtler. A success indicator can stay on the page for minutes
after the action that produced it, which means finding one proves nothing on its own.

Check two things: that it is there **and** that it says it happened *just now* rather than
some minutes ago. An indicator from the previous run confirms the previous run.

## An open form is not evidence of failure

Interfaces differ: some close the composer on success, some leave it exactly as it was. If
the tool concludes "the form is still open, so it failed" it will retry an action that
worked.

When the sign is absent or stale, look for the **result** rather than for the sign: is the
thing you did visible where it would be if it had worked? That is the only answer that does
not depend on the interface's habits.

## Click the element, not the coordinates

This one produces failures that look like something else entirely.

A tool that clicks by coordinates is usually working in the coordinate space of a
*screenshot*, and the page has its own. On one setup the two differed by a factor of about
1.07 — a control at (1062, 651) in the image is at (991, 607) on the page. The click lands on
nothing. The form stays open with the content ready, and the natural conclusion is that the
action failed.

Reading `getBoundingClientRect()` and clicking those numbers looks like the fix and is not:
that returns page coordinates, and the clicking layer still works in screenshot ones. Find
the control and click *the element you found*.

## Do not read the system clipboard from the page

`navigator.clipboard.readText()` does not fail cleanly when it is not allowed. It hangs the
tab on a permission prompt that is never shown, and whatever is driving the page times out
—  measured at forty-five seconds — with no error that says what happened.

Put text in directly. There is always a way to set a field's value; there is not always a way
to read a clipboard.

## What the interface offers next may not be what you wanted

After an action completes, the page may offer a related one — promoting the thing, upgrading
it, turning it into something paid. The buttons are laid out to make continuing the easy
path.

Close it with its decline, deliberately, as a step of the procedure rather than as an
afterthought. A tool that dismisses dialogs by clicking the affirmative button will
eventually buy something.
