Skip to content

SDK ​

@openpicker/sdk is a tiny, dependency-free client. It does not draw any UI — it starts a pick and awaits the result; the extension owns the picker overlay and the cross-tab routing.

bash
npm install @openpicker/sdk

Quick start ​

ts
import { createOpenpicker, OpenpickerError } from "@openpicker/sdk"

const op = createOpenpicker({ appName: "My App" })

if (!(await op.isAvailable())) {
  // prompt the user to install the OpenPicker extension
}

try {
  const { selector, matchCount, element, screenshot } = await op.pick({
    url: "https://app.example.com",
    screenshot: "element",
  })
  console.log(selector, `(matches ${matchCount})`, element)
} catch (err) {
  if (err instanceof OpenpickerError && err.code === "cancelled") {
    // the user closed the picker
  } else {
    throw err
  }
}

How it works ​

Your app calls op.pick({ url }); the extension opens the URL, the user points at any element on the real page, and the selector is routed back — no DevTools, on any web app.

Add visual picking to your product — a tiny SDK lets your users choose page elements without DevTools

Open any website and pick there

Anyone can point and click

Get the selector back in your app

createOpenpicker(options?) ​

Returns an Openpicker handle.

OptionTypeDefaultDescription
appNamestring—Display name shown to the user (informational, never trusted).
pingTimeoutnumber1500ms before ping assumes the extension isn't installed.
defaultTimeoutnumber3000ms for quick ops (cancel / highlight / clearHighlight).
targetWindowWindowwindowWindow to communicate over.

Methods ​

MethodReturnsDescription
ping()PingResultProbe the extension; negotiate version & capabilities.
isAvailable()booleantrue if the extension responds to a ping.
pick(params)PickResultOpen params.url, let the user pick there, resolve with the result.
cancel()voidCancel an in-flight pick (it rejects with cancelled).
highlight(selector)HighlightResultHighlight matches of a selector without entering pick mode.
clearHighlight()voidRemove any active highlight.
activateSelf()voidBring the calling tab to the foreground (a tab can only focus itself).
isTargetOpen()booleanWhether the cross-tab target tab this tab opened is still open.
destroy()voidStop listening and reject any in-flight requests.

pick(params) ​

FieldTypeDescription
urlstring (required)Page to open and pick in. Omitting it rejects with invalid_params.
screenshot"none" | "element" | "viewport"Screenshot to include. Defaults to "none".
keystringOpaque task id; decides whether a later pick reuses the target tab.
appNamestringOverrides the instance appName for this call.
selectorSelectorConfigSelector-generation rules for this pick (composed with the user's).
lockSelectorSettingsbooleanShow the gear rules read-only. Default false.
lockSelectorEditbooleanMake the selector field read-only. Default false.
requireUniqueMatchbooleanAllow confirm only when the selector matches exactly one element. Default false.
mustMatchstringA CSS selector the picked element must match. Non-matching elements aren't selectable (hovering snaps to the nearest matching ancestor); an invalid value rejects with invalid_params.

Two axes. mustMatch constrains which element can be picked; selector constrains how its selector is built. They're independent and compose — e.g. "only inputs, identified by id":

ts
op.pick({
  url,
  mustMatch: "input, textarea, select, [contenteditable]",
  selector: { class: { enabled: false }, attr: { enabled: false }, tag: { enabled: false } },
})

SelectorConfig — per anchor type (id / class / attr / tag), all optional:

ts
{ id?: SelectorAnchorConfig; class?: …; attr?: …; tag?: … }
// SelectorAnchorConfig: { enabled?: boolean; allow?: string /* regex */; ignore?: string /* regex */ }

selector composes with the user's saved rules — each layer can only narrow. See Configuring selectors.

PickResult

ts
{
  selector: string
  matchCount: number
  element: { tag: string; id?: string; classes: string[]; text?: string; attributes: Record<string, string> }
  screenshot?: string // data: URL, present only when requested
}

pick is cross-tab only — see Cross-tab picking. Error codes are listed in Errors.

matchesSelectorConfig(selector, config) ​

Returns whether a selector only uses anchors permitted by a SelectorConfig. The user can hand-edit the returned selector (unless you set lockSelectorEdit), so validate it against your rules:

ts
import { matchesSelectorConfig } from "@openpicker/sdk"

const cfg = { attr: { allow: "^data-step$" }, tag: { enabled: false } }
const { selector } = await op.pick({ url, selector: cfg })
if (!matchesSelectorConfig(selector, cfg)) {
  // doesn't meet the requirement — ask the user to pick again
}

Released under the MIT License.