When a target breaks
A CSS selector is a claim about your markup. Rename a class, reorder a list, or move a button into a new wrapper, and the claim stops being true. The tour then points at nothing, waits out its gate, and skips the step the user most needed.
A fingerprint is a second, weaker claim about the same element: what tag it is, what it says, what it is called, and what heading it sits under. Those survive most refactors that break a selector.
{
id: "cancel",
target: ".danger-btn",
title: "Cancel a ride",
fingerprint: {
tag: "button",
text: "Cancel",
label: "Cancel ride",
near: "Your rides",
},
}If .danger-btn still matches, the fingerprint is never consulted. If it misses, the fingerprint
finds the element and the tour continues, with a warning naming the step and the stale selector:
tourkit: step "cancel" could not find ".danger-btn" and matched it by fingerprint instead.
Update the target before it stops matching.Once per step, per tour run.
You do not write these by hand
tourkit record captures a fingerprint for every step whose target fell back to a selector, and
writes it into the generated file. Steps using a data-tour-id get none, because there is nothing
to heal: an id you control does not drift.
To add one to an existing tour, build it in the browser console:
import { buildFingerprint } from "@tourkit/react";
buildFingerprint(document.querySelector(".danger-btn"));What matching actually does
Every element with the right tag is scored:
| Signal | Points |
|---|---|
label matches (data-tour-label or aria-label) |
5 |
text matches |
4 |
role matches |
2 |
near matches, the nearest heading or labelled landmark |
2 |
index matches, position among same-tag siblings |
1 |
A different tag scores zero regardless of everything else.
The best candidate wins only if it scores at least 4 and strictly beats the runner-up. Two buttons that both say "Save" produce a tie, and a tie resolves to nothing. Healing that guesses between two plausible elements is worse than healing that admits defeat, because a tour pointing confidently at the wrong button teaches the user the wrong thing.
Matching also bails when more than 500 elements share the tag. A fingerprint of
{ tag: "div", text: "Save" } is not worth a full-document scan on every step.
There is no model call. This is comparison logic running in your app, and it is why the feature costs nothing at runtime.
It is a safety net, not a fix
A healed step is a step whose target is already wrong. The warning exists so you notice, and the
right response is to open the file and give the element a data-tour-id:
<button data-tour-id="cancel-ride" className="Button_destructive__9fa2b">Cancel</button>{ id: "cancel", target: "cancel-ride", title: "Cancel a ride" }Now nothing to heal, nothing to warn about, and the tour survives any styling change at all. That is the outcome the warning is pushing you toward.