TypeScript teams get compile-time safety on API responses and Playwright page handles. Same rule as Python: launch Multilogin profile → connectOverCDP → stop in finally.
Setup
npm init -y npm install playwright axios p-limit npm install -D typescript @types/node npx tsc --init
Typed worker
import axios from "axios";
import pLimit from "p-limit";
import { chromium, Browser, Page } from "playwright";
const MLX = process.env.MLX_API ?? "https://api.multilogin.com";
const TOKEN = process.env.MLX_TOKEN!;
const headers = { Authorization: `Bearer ${TOKEN}` };
interface LaunchResp {
cdp_url?: string;
wsUrl?: string;
}
async function withProfile(
profileId: string,
fn: (page: Page) => Promise<void>
): Promise<void> {
const { data } = await axios.post<LaunchResp>(
`${MLX}/profile/start`,
{ profile_id: profileId, headless: false },
{ headers, timeout: 90_000 }
);
const cdp = data.cdp_url ?? data.wsUrl;
if (!cdp) throw new Error("Missing CDP URL");
const browser: Browser = await chromium.connectOverCDP(cdp, { timeout: 60_000 });
try {
const ctx = browser.contexts()[0] ?? (await browser.newContext());
const page = ctx.pages()[0] ?? (await ctx.newPage());
await fn(page);
} finally {
await browser.close();
await axios.post(`${MLX}/profile/stop`, { profile_id: profileId }, { headers });
}
}
async function main() {
const ids = (process.env.MLX_PROFILE_IDS ?? "").split(",").filter(Boolean);
const limit = pLimit(Number(process.env.MLX_MAX_PARALLEL ?? 4));
await Promise.all(
ids.map((id) =>
limit(async () => {
await withProfile(id.trim(), async (page) => {
await page.goto("https://example.com", { waitUntil: "domcontentloaded" });
console.log(id, await page.title());
});
})
)
);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
When TypeScript vs Python
| Pick TS | Pick Python |
|---|---|
| Existing Node monorepo, CI in GitHub Actions JS | Data/scraping stack already in pandas/httpx |
| Shared types with frontend dashboard | asyncio semaphore recipe |
Related
Disclosure: MLX-MMO affiliated with Multilogin.