Skip to content

Login Flow

Portals behind a login are where scrapers break most — and where the kind of break matters. A renamed submit button is fixable by code; an expired password is not. Autowright classifies the two differently so each gets the right response.

The script

portal-login.ts
import { chromium } from '@autowright/browser';
const browser = await chromium.launch({
headless: true,
autowright: {
scriptId: 'portal-login',
serviceUrl: 'http://localhost:4400',
repoUrl: 'https://github.com/your-org/scrapers',
scriptPath: 'src/portal-login.ts',
},
});
const page = await browser.newPage();
await page.goto('https://portal.example.com/login');
// Credentials come from the environment — never hard-code them
await page.fill('#username', process.env.PORTAL_USER!);
await page.fill('#password', process.env.PORTAL_PASS!);
await page.click('button[type="submit"]');
// Wait for a post-login element before scraping
await page.waitForSelector('.account-summary');
const balance = await page.locator('.account-balance').textContent();
console.log(`Balance: ${balance}`);
await browser.close();
Terminal window
PORTAL_USER=svc-account PORTAL_PASS= npx tsx portal-login.ts

Two very different failures

The form changed. If the portal renames button[type="submit"] or moves the username field, the failure classifies as SELECTOR_NOT_FOUND — the fixer hunts through the captured DOM for the replacement and proposes a PR.

The credentials stopped working. If the login submits but the portal rejects it — you land on an error page instead of .account-summary — the observer sees the auth rejection and classifies CREDENTIALS_INVALID. No code change can fix a dead password, so instead of a speculative PR you get a needs-attention notification telling you exactly that. See Error Classification.

Credentials and captured evidence

Failure evidence includes the DOM and the action log — which would be a problem if your password appeared in them. It doesn’t: credential values are redacted from captured artifacts before anything is written or uploaded. Keep secrets in environment variables (as above) rather than string literals, so they also never appear in the source the fixer reads.

Next