Skip to content

Locators and actions

A locator describes how to find one or more elements inside an attached frame. Locators are chainable and lazy: nothing touches the page until you call an action. If you have used Playwright, you already know this model.

Locators run wherever attachFrame() attached the frame: in the FKN extension’s content script or in the cloud render proxy. Consent applies only to the extension backend. A cloud frame uses either an isolated or persistent cloud cookie jar, depending on syncCookies, and does not show extension prompts.

Locators and actions by execution backend

All APIs below are called from browser code. The columns show which backend performs the work.

API / featureExtensionCloudDesktop
Selectors (locator, getByRole, ...)SupportedSupportedNot available
Read actions (textContent, ...)SupportedSupportedNot available
Write actions (click, fill, hover)SupportedSupportedNot available
videoElement()SupportedNot availableNot available
await
const frame: Frame
frame
.
locator: (selector: string) => Locator
locator
('.video-card')
.
first: () => Locator
first
()
.
getByText: (text: string) => Locator
getByText
('Play')
.
click: (options?: (OperationTimeoutOptions & {
position?: {
x?: number;
y?: number;
};
}) | undefined) => Promise<void>
click
()

Each selector returns a new locator, scoped to the previous step’s matches.

The frame root starts narrow: it offers locator(css), frameLocator(css) and owner(). The rest of the set below becomes available on element locators, from the first locator() onward; owner() stays a frame-locator selector.

SelectorFinds
locator(css)elements matching a CSS selector
getByRole(role)elements by ARIA role
getByText(text)elements containing the given text
getByTestId(id)elements by data-testid
first()the first match of the current set
nth(index)the n-th match of the current set
frameLocator(css)descends into a child iframe matched by the selector
owner()steps back up to the locator’s owning frame (frame locators only)

Actions are terminal: they resolve the chain against the live page and perform the operation. On the extension backend, each action is checked against a permission keyed to its capability and target. Severity-0 actions continue automatically; other actions prompt when no existing grant covers them. Cloud actions do not use extension consent.

ActionDoesReturns
click()clicks the elementPromise<void>
fill(value)sets an input’s valuePromise<void>
hover()moves a faithful pointer over the elementPromise<void>
textContent()reads the element’s textPromise<string | null>
getAttribute(name)reads an attributePromise<string | null>
isVisible()whether the element is rendered and visiblePromise<boolean>
exists()whether the element is presentPromise<boolean>
count()how many elements matchPromise<number>
videoElement()a remote handle to a <video> element (play, pause, seek, events); extension backend onlyPromise<RemoteVideoElement>
addStyleTag(options)injects safety-filtered CSS into the framePromise<void>

All actions accept an options object with:

  • timeout: how long to retry resolving the locator before failing. Waiting for the user’s consent never counts against the timeout.
  • reason: an app-supplied explanation shown on the consent prompt next to the request.
const
const title: string
title
= await
const frame: Frame
frame
.
locator: (selector: string) => Locator
locator
('h1')
.
textContent: (_options?: OperationTimeoutOptions | undefined) => Promise<string>
textContent
({
timeout?: number | undefined
timeout
: 5_000,
reason?: string | undefined
reason
: 'Show the video title in your library' })

Reading page content (textContent, getAttribute) and acting on it (click, fill, hover) use distinct extension capabilities. Visibility, existence, and count checks are severity 0 and do not prompt. A user can grant content reading without granting page actions, and vice versa.

Drive an embedded page through the extension below: single actions (one consent each), an area grant that covers a region, and the on-device activity log. Needs the FKN extension installed; the demo picks it up automatically. For a demo that also runs without the extension, see attachFrame().

Locators, consent and the audit logOpen in new tab