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
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 themawait 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 scrapingawait page.waitForSelector('.account-summary');
const balance = await page.locator('.account-balance').textContent();console.log(`Balance: ${balance}`);
await browser.close();PORTAL_USER=svc-account PORTAL_PASS=… npx tsx portal-login.tsTwo 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
- Scheduled Scraper — run this on a cron
- Artifacts — exactly what gets captured