API

Programmatic access for developers

Overview

Agentation exposes callbacks that let you integrate annotations into your own workflows — send to a backend, pipe to terminal, trigger automations, or build custom AI integrations.

  • Sync annotations to a database or backend service
  • Build analytics dashboards tracking feedback patterns
  • Create custom AI integrations (MCP servers, agent tools)

Props

onAnnotationAdd(annotation: Annotation) => void
Called when an annotation is created
onAnnotationDelete(annotation: Annotation) => void
Called when an annotation is deleted
onAnnotationUpdate(annotation: Annotation) => void
Called when an annotation comment is edited
onAnnotationsClear(annotations: Annotation[]) => void
Called when all annotations are cleared
onCopy(output: string) => void
Receives the formatted output after a Copy attempt, even if clipboard access fails.
onSubmit(output: string, annotations: Annotation[]) => void
Receives structured markdown and annotations when Send is clicked. Async callbacks are awaited; failures preserve feedback.
copyToClipboardbooleanDefault: true
Set to false to prevent writing to clipboard (if handling via onCopy)
endpointstring
MCP server URL for syncing annotations
sessionIdstring
Pre-existing session ID to use
onSessionCreated(sessionId: string) => void
Called when a new session is created
webhookUrlstring
Webhook URL to receive annotation events
classNamestring
Apply custom positioning and z-index to the toolbar host.
useHashLocationbooleanDefault: false
Keep separate feedback, layout state and sessions for hash-based routes.
appNamestring
Identify the app in copied and submitted feedback.
enableKeyboardShortcutsbooleanDefault: true
Enable global shortcuts. Popup Enter/Escape and keyboard activation of buttons remain available.
identifyingAttributesreadonly string[]
Replace the default list of identifying attributes captured from selected elements.
copyFormat"markdown" | "source" | "classes" | { attribute: string }Default: "markdown"
Choose full feedback, source paths, classes or an attribute value. Changes Copy only.
onOpenSource(sourceFile: string) => void
Show Open in editor when a source location is available. Your callback chooses the editor integration.
portalContainerHTMLElement | ShadowRoot | nullDefault: document.body
Keep the toolbar and popup inside a host overlay’s focus boundary.

Basic usage

Receive annotation data directly in your code:

import { Agentation, Annotation } from "agentation";


function App() {
  const handleAnnotation = (annotation: Annotation) => {
    console.log(annotation.element, annotation.comment);
  };


  return (
    <>
      <YourApp />
      <Agentation onAnnotationAdd={handleAnnotation} />
    </>
  );
}

Identify your app and choose what to copy

Use appName to distinguish feedback from different apps. By default, Copy produces markdown with the selected elements and your notes.

<Agentation appName="Checkout preview" />

For a smaller output, copy source paths, CSS classes, or one identifying attribute. Each format returns unique values on separate lines.

<Agentation copyFormat="source" />
<Agentation copyFormat="classes" />
<Agentation copyFormat={{ attribute: "data-qa" }} />

Attribute mode captures the requested attribute automatically. When the selected element has a value, you can save it without writing a comment. Missing metadata leaves the clipboard and saved feedback intact.

copyFormat also changes the text passed to onCopy. It does not change Send: onSubmit still receives structured markdown and the annotation array. With copyToClipboard={false}, your onCopy callback handles delivery.

Stable element identifiers

Agentation captures data-testid, data-test, data-qa, data-cy and data-component by default. Supply identifyingAttributes to replace that list.

<Agentation identifyingAttributes={["data-testid", "data-qa"]} />

Values are available in annotation.attributes. Up to two short data attributes also appear in the element selector. Capture is limited to 16 names and 500 characters per value. Choose identifiers intended to be shared with your agent.

Open the source in your editor

Provide onOpenSource to add an Open in editor action to the feedback popup. It receives the detected file reference, such as src/Checkout.tsx:24:5.

<Agentation onOpenSource={(sourceFile) => openInEditor(sourceFile)} />

openInEditor is your app’s editor integration. The action stays hidden if a trustworthy source location is unavailable. React development metadata is best effort; a production build needs source metadata supplied at build time.

Annotate a modal or popover

Pass the active overlay’s content element as portalContainer. A callback ref lets Agentation move its existing portal as the overlay opens and closes, preserving feedback state.

import { useState } from "react";
import { Dialog } from "@base-ui/react/dialog";
import { Agentation } from "agentation";


export function App() {
  const [container, setContainer] = useState<HTMLElement | null>(null);


  return (
    <>
      <Dialog.Root>
        <Dialog.Trigger>Open settings</Dialog.Trigger>
        <Dialog.Portal>
          <Dialog.Popup ref={setContainer}>
            <Dialog.Title>Settings</Dialog.Title>
            {/* Your settings form */}
            <Dialog.Close>Close</Dialog.Close>
          </Dialog.Popup>
        </Dialog.Portal>
      </Dialog.Root>
      <Agentation portalContainer={container} />
    </>
  );
}

The container must belong to the same document. Browsers with the Popover API keep Agentation in the top layer while its DOM remains inside the overlay’s focus boundary. Older browsers use an ordinary portal, so host overflow and transforms can still affect placement. Other modal libraries may need additional focus integration.

Same-origin embedded pages

Select elements inside same-origin iframes, including nested frames and open shadow roots. Single-element markers follow child scrolling and axis-aligned frame scaling. They hide when their target leaves the frame viewport or the frame navigates, and return with the original number when visible again.

Cross-origin contents cannot be inspected. You can still select the iframe element itself. Rotated or skewed frames and live multi-element groups across frame boundaries are outside this support.

Routing and keyboard control

For a hash router, enable useHashLocation so /app#/inbox and /app#/settings retain separate notes, layout state and default MCP sessions.

<Agentation useHashLocation />

Hash changes and browser Back/Forward are tracked. If your router changes history without a navigation event, render Agentation from a component subscribed to that router’s location. Unsaved popup text is cancelled on navigation; saved feedback stays with its route. Query strings do not create separate feedback buckets. Existing pathname-only data stays in its original bucket.

For an app with its own keyboard shortcuts, turn off Agentation’s global shortcuts. The toolbar buttons and Enter/Escape within feedback popups remain usable.

<Agentation enableKeyboardShortcuts={false} />

Annotation type

The Annotation object passed to callbacks. See Agentation Format for the full schema.

type Annotation = {
  // Required
  id: string;              // Unique identifier
  comment: string;         // User's annotation text
  elementPath: string;     // CSS selector path
  timestamp: number;       // Unix timestamp (ms)
  x: number;               // % of viewport width (0-100)
  y: number;               // px from document top
  element: string;         // Tag name ("button", "div")


  // Recommended
  url?: string;            // Page URL
  boundingBox?: {          // Element dimensions
    x: number;
    y: number;
    width: number;
    height: number;
  };


  // Context (varies by output format)
  reactComponents?: string;   // Component tree
  cssClasses?: string;
  sourceFile?: string;        // path:line:column when available
  attributes?: Record<string, string>; // Captured identifying attributes
  computedStyles?: string;
  accessibility?: string;
  nearbyText?: string;
  selectedText?: string;      // If text was selected


  // Browser component fields
  isFixed?: boolean;       // Fixed-position element
  isMultiSelect?: boolean; // Created via drag selection


  // Annotation kind (defaults to "feedback")
  kind?: "feedback" | "placement" | "rearrange";


  // Layout mode data
  placement?: {
    componentType: string;
    width: number;
    height: number;
    scrollY: number;
    text?: string;
  };
  rearrange?: {
    selector: string;
    label: string;
    tagName: string;
    originalRect: { x: number; y: number; width: number; height: number };
    currentRect: { x: number; y: number; width: number; height: number };
  };
};

HTTP API

The agentation-mcp server provides a REST API for programmatic access:

Sessions

Sessions
MethodEndpointDescription
POST/sessionsCreate a new session
GET/sessionsList all sessions
GET/sessions/:idGet session with annotations

Annotations

Annotations
MethodEndpointDescription
POST/sessions/:id/annotationsAdd annotation
GET/annotations/:idGet annotation
PATCH/annotations/:idUpdate annotation
DELETE/annotations/:idDelete annotation
POST/annotations/:id/threadAdd thread message
GET/sessions/:id/pendingGet pending annotations
GET/pendingGet all pending annotations

Events (SSE)

Events (SSE)
MethodEndpointDescription
GET/sessions/:id/eventsSession event stream
GET/eventsGlobal event stream (optionally filter with ?domain=...)

Health

Health
MethodEndpointDescription
GET/healthHealth check
GET/statusServer status

Real-Time Events

Subscribe to real-time events via Server-Sent Events:

# Session-level: events for a single page
curl -N http://localhost:4747/sessions/:id/events


# Global: events across ALL sessions
curl -N http://localhost:4747/events


# Filtered by domain: events for pages on a specific domain
curl -N "http://localhost:4747/events?domain=localhost:3001"


# Reconnect after disconnect (replay missed events)
curl -N -H "Last-Event-ID: 42" http://localhost:4747/sessions/:id/events

Event types

  • annotation.created: New annotation added (includes kind field for design annotations)
  • annotation.updated: Annotation modified (comment, status, design data, etc.)
  • annotation.deleted: Annotation removed
  • session.created: New session started
  • session.updated: Session updated
  • session.closed: Session closed
  • action.requested: Agent action requested
  • thread.message: New message in annotation thread

Environment Variables

Environment Variables
VariableDescriptionDefault
AGENTATION_STOREStorage backend (memory or sqlite)sqlite
AGENTATION_EVENT_RETENTION_DAYSDays to keep events7

Storage

By default, data is persisted to SQLite at ~/.agentation/store.db. To use in-memory storage:

AGENTATION_STORE=memory npx agentation-mcp server

Programmatic Usage

import { startHttpServer, startMcpServer } from 'agentation-mcp';


// Start HTTP server on port 4747
startHttpServer(4747);


// Start MCP server (connects via stdio)
await startMcpServer('http://localhost:4747');

See MCP Server for AI agent integration and available tools.

In-memory event history

When AGENTATION_STORE=memory, these settings bound event replay history. They do not delete current sessions or annotations and do not change SQLite retention.

AGENTATION_MAX_EVENTS=10000
AGENTATION_EVENT_TTL_MS=3600000
AGENTATION_CLEANUP_INTERVAL_MS=300000

The defaults retain up to 10,000 events for one hour, with background cleanup every five minutes. Reads also remove expired events. Invalid values fall back to these defaults.