Browser

Browser infrastructure for portal automation

The portal has no API.
Your agent still gets in.

Payer portals, EHRs and registries are built to stop bots. Oya is a real browser with the automation inside it: your agents sign in like staff, and a run recorded once replays forever with no model in the loop.

Or sign in by hand, once

Everyone elseheadless Chrome over CDP

Blocked. Verify you are human

Oyaa real browser, signed in

Eligibility: active
Same portal, same task. The difference is where the automation runs.
$ npm i @oya-ai/browser
import { Oya } from "@oya-ai/browser";

const browser = await new Oya().browser.start();     // a real browser, already signed in
await browser.goto(PORTAL_URL);

const result = await browser.play("eligibility-check", { memberId });  // no model in the loop

Your browser. Your choice.

  • Oya Cloud
  • Browserbase
  • Browser Use
  • Steel
  • Anchor
  • Your own Chrome

The portal reality

The work is simple.
Keeping it working is not.

  1. 01

    There is no API.

    Payer portals, EHRs, registries and state boards. The last mile is a person in a browser, and your product stops where they start.

  2. 02

    The portal blocks the bot.

    Headless Chrome driven over the debugging protocol is the shape anti-bot vendors look for. The task is fine. The browser gives you away.

  3. 03

    The session dies.

    SSO, passkeys, a code to a mailbox. Scripted logins break first and break constantly, and a retried password locks the account.

  4. 04

    Every run costs a model call.

    An agent that reasons through the same eight steps every night is paying to rediscover them, and drifting each time it does.

Playbooks

The tenth run
should not cost a model call.

Save the run that worked. Replay it with new inputs and no LLM in the loop. When the portal moves, the agent repairs the step and leaves a draft for a person to promote.

A task becomes a workflow
“Prepare a portal request.”
  1. Navigate
  2. Fill
  3. Review
Save the successful runportal-request-review
browser.toPlaybook("portal-request-review")

The agent does the task once. You keep the steps.

Interactive diagram · fictional task

The hard way

Everyone drives Chrome.
We built the browser.

The automation lives inside it, not attached over the debugging protocol.

See the numbers
YOUR AGENTHowever it connects.
SDKMCPCDPREST
OyaThe browser itself
THE SITESees ordinary Chrome.
Headful ChromeNo Runtime.enable

Not flagged as a bot.

Chrome’s own emulation sets the device. 0% on CreepJS.

Sign in once.

Log in by hand. Every browser after that starts signed in.

Prove what happened.

A hash-chained audit trail. Allow-list the hosts a browser may reach.

See it run

This is the whole loop.
Ask, save, replay.

Do it once. Keep it forever.

Ask in plain language. When the run works, save it: the steps, the selectors and the inputs become a playbook that replays with no model in the loop, and exports as a Playwright module you own.

Recorded in the Oya browser. The boxes are the page as the agent reads it.

One console for every browser.

Start browsers on your own machines or in your own cloud, watch a run as it happens, take the mouse when a portal asks for a code, and read the audit trail afterwards.

The Oya console, self-hosted.

Already running browsers in the cloud?

Same five questions.
Different answers.

 A cloud browser SDKOya
What you connect toHeadless Chrome over the debugging protocolA real headful browser with the automation inside it
The tenth run of the same taskAnother full model passA recorded playbook, replayed with no model
Signing inScript the login, or paste cookiesSign in by hand once; the persona carries cookies and localStorage
Where it runsTheir cloudTheir cloud, your cloud, or your own machines
What you keep if you leaveThe code you wrote against their SDKYour playbooks, as Playwright modules

It stays your code.
Not a vendor's black box.

Every playbook exports as a Playwright module you can read, diff and keep. Self-host the control plane and the run never leaves your cloud.

Get the full example
One sign-in, every run.
portal.ts Node 24+
import { Oya } from "@oya-ai/browser";

const oya = new Oya(); // Set OYA_API_KEY.
const { PORTAL_URL, PORTAL_USERNAME, PORTAL_PASSWORD } = process.env;
if (!PORTAL_URL || !PORTAL_USERNAME || !PORTAL_PASSWORD) {
  throw new Error("Set your test portal URL and credentials.");
}
const secrets = { username: PORTAL_USERNAME, password: PORTAL_PASSWORD };
const playbookName = "portal-request-review";

// First run: let the agent do the task, then store its playbook.
{
  await using browser = await oya.browser.start();
  await browser.goto(PORTAL_URL);
  await browser.ask(
    "If needed, log in with {{username}} and {{password}}. " +
    "Open New Request for {{customerName}}. Stop before submitting.",
    { data: { customerName: "Alex Example" }, secrets },
  );
  await browser.toPlaybook(playbookName);
} // The first browser stops here; the playbook stays saved.

// Later: run the saved playbook on a new browser with new inputs.
await using replay = await oya.browser.start();
await replay.goto(PORTAL_URL);
await replay.play(playbookName, {
  customerName: "Sam Example",
  ...secrets, // Replay remembers which variables are secret.
});

Fictional inputs.

Stop writing integrations
for portals that don't want you.

Start a browser in a minute. Record the run your team already does by hand. Move the whole thing into your own cloud when the data says it has to stay there.