Skip to main content
Instrumentation wraps Playwright’s locator and page actions with two capabilities:
  • Visualization — before each action, a ghost cursor animates to the target element and the element is highlighted. After the action, the highlight clears.
  • Error enrichment — when a pointer action (click, dblclick, hover) times out, additional context is captured and attached to the error.

instrumentPage()

Applies instrumentation to a Page in place and returns it typed as InstrumentedPage. The original page object is modified directly.
async function instrumentPage(
  page: Page,
  options?: InstrumentationOptions
): Promise<InstrumentedPage>
page
Page
required
The Playwright Page to instrument.
options
InstrumentationOptions

Example

import { instrumentPage } from "libretto";

const instrumented = await instrumentPage(page, {
  visualize: true,
  highlightBeforeActionMs: 500,
  logger,
});

// All subsequent locator actions show ghost cursor + element highlights
await instrumented.locator("#submit").click();
await instrumented.locator("#email").fill("user@example.com");

installInstrumentation()

Same as instrumentPage() but returns void instead of the page. Useful when you don’t need the typed return value, or when you want to instrument a page that was passed in from elsewhere.
async function installInstrumentation(
  page: Page,
  options?: InstrumentationOptions
): Promise<void>
page
Page
required
The Playwright Page to patch in place.
options
InstrumentationOptions
Calling installInstrumentation() (or instrumentPage()) on an already-instrumented page is a no-op. The check is based on the presence of page.__librettoInstrumented.

instrumentContext()

Instruments all current pages in a BrowserContext and automatically instruments any pages that open in the future. Useful when connecting to an existing browser via CDP, or when your workflow opens multiple tabs.
async function instrumentContext(
  context: BrowserContext,
  options?: InstrumentationOptions
): Promise<void>
context
BrowserContext
required
The Playwright BrowserContext to instrument.
options
InstrumentationOptions

Example

import { instrumentContext } from "libretto";

await instrumentContext(browserContext, { visualize: true, logger });

// All existing pages are now instrumented.
// Any new page opened in this context will be instrumented automatically.
const newPage = await browserContext.newPage();

InstrumentationOptions

visualize
boolean
Enable ghost cursor animation and element highlight overlays. Defaults to false.
logger
MinimalLogger
Optional logger. Navigation actions (goto, reload, goBack, goForward) are logged at info level when a logger is provided.
highlightBeforeActionMs
number
How long (in milliseconds) to show the element highlight before performing the action. Defaults to 350.
ghostCursor
GhostCursorOptions
Options for the ghost cursor overlay.
highlight
HighlightOptions
Options for the element highlight overlay.

Standalone visualization functions

You can use the ghost cursor and highlight primitives directly without going through instrumentPage.

Ghost cursor

ensureGhostCursor(page, options?)

Injects the ghost cursor overlay into the page if it is not already present. Also installs a page.addInitScript so the cursor reappears after navigation.
async function ensureGhostCursor(page: Page, options?: GhostCursorOptions): Promise<void>

moveGhostCursor(page, target)

Animates the ghost cursor to a specific coordinate.
async function moveGhostCursor(
  page: Page,
  target: { x: number; y: number; durationMs?: number }
): Promise<void>

ghostClick(page, target)

Animates a press-and-release visual feedback on the ghost cursor at the given coordinates.
async function ghostClick(page: Page, target: { x: number; y: number }): Promise<void>

hideGhostCursor(page)

Fades the ghost cursor out.
async function hideGhostCursor(page: Page): Promise<void>

Highlight layer

ensureHighlightLayer(page, options?)

Injects the highlight layer into the page if it is not already present.
async function ensureHighlightLayer(page: Page, options?: HighlightOptions): Promise<void>

showHighlight(page, params)

Draws a highlight rectangle over a bounding box. The highlight fades out automatically after durationMs.
async function showHighlight(
  page: Page,
  params: {
    box: { x: number; y: number; width: number; height: number };
    label?: string;
    color?: string;
    durationMs?: number;
  }
): Promise<void>

clearHighlights(page)

Removes all highlight rectangles from the layer immediately.
async function clearHighlights(page: Page): Promise<void>

Standalone example

import {
  ensureGhostCursor,
  moveGhostCursor,
  ghostClick,
  ensureHighlightLayer,
  showHighlight,
  clearHighlights,
} from "libretto";

await ensureGhostCursor(page, { style: "dot", color: "rgba(0, 120, 255, 0.9)" });
await ensureHighlightLayer(page);

const box = await page.locator("#submit").boundingBox();
if (box) {
  await showHighlight(page, { box, durationMs: 400 });
  await moveGhostCursor(page, {
    x: box.x + box.width / 2,
    y: box.y + box.height / 2,
  });
  await ghostClick(page, { x: box.x + box.width / 2, y: box.y + box.height / 2 });
}

await clearHighlights(page);

Build docs developers (and LLMs) love