Building an ACA Playwright connector for Power Platform and Copilot Studio
July 09, 2026
Browser automation from Power Automate has always meant desktop flows, attended RPA sessions, or external services. What if your flow could spin up a headless Chromium browser in an isolated cloud microVM, navigate to a page, fill a form, take a screenshot, and tear it down — all without a desktop or VM license?
This connector puts Playwright inside Azure Container Apps Sandboxes. Each session boots a fresh Linux microVM with Node.js 22, Playwright, and Chromium pre-installed. The browser runs headless, state persists across operations within a session, and the sandbox auto-suspends after 10 minutes idle.
Operations
The connector exposes 11 typed operations plus an MCP endpoint:
| Operation | Purpose |
|---|---|
| Create Browser Session | Boot a sandbox with custom viewport, user agent, locale, and HAR recording |
| Navigate to URL | Navigate with configurable wait conditions (load, DOMContentLoaded, networkidle) |
| Take Screenshot | Full page or element screenshot as PNG/JPEG |
| Click Element | Click by CSS, XPath, or Playwright locator with optional post-click wait |
| Fill Form Fields | Fill multiple inputs by selector/value pairs |
| Extract Content | Extract text, HTML, or attributes from elements |
| Run Playwright Script | Execute arbitrary Playwright JavaScript with full API access |
| Generate PDF | Export page as PDF with paper format, orientation, and background options |
| Get Console Log | Retrieve browser console messages from the session |
| Download Artifact | Download any file from the sandbox workspace |
| Destroy Session | Tear down sandbox and free resources |
The MCP endpoint (/mcp) exposes all 11 as tools for Copilot Studio agents.
How it works under the hood
Each operation generates a self-contained Node.js script that:
- Launches Chromium headless with
ignoreHTTPSErrors: true - Loads saved browser state (cookies, localStorage) from
/workspace/.browser-state.json - Restores the last visited URL from
/workspace/.last-url.txt - Performs the requested action
- Saves browser state and URL back to disk
- Closes the browser
Scripts execute via the ACA Sandbox executeShellCommand API with NODE_PATH set so globally installed Playwright resolves correctly. The browser launches fresh on each operation (~1–2s overhead per call), but state persistence means you don’t lose cookies or localStorage between steps.
Persistent state across operations
This is the key design decision. Within a session, browser state carries forward:
1. Create Browser Session → sessionId: "abc123"
2. Navigate to URL → "https://app.example.com/login"
3. Fill Form Fields → [username: "user@zava.com", password: "***"]
4. Click Element → "#login-button"
5. Navigate to URL → "https://app.example.com/dashboard"
(cookies from login persist — no re-authentication needed)
6. Take Screenshot → full page dashboard capture
7. Extract Content → "#revenue-total" → "$1,234,567"
8. Destroy Session
Each step picks up where the last one left off. The session maintains the authenticated browser context across all operations.
Run Playwright Script
For scenarios that go beyond the typed operations, Run Playwright Script lets you execute arbitrary Playwright JavaScript:
const table = await page.locator('table#results');
const rows = await table.locator('tr').all();
const data = [];
for (const row of rows) {
const cells = await row.locator('td').allTextContents();
data.push(cells);
}
console.log(JSON.stringify(data));
The script runs in a Node.js context with the full Playwright API available. Output goes to stdout, which the connector captures and returns.
Disk image setup
The sandbox runs a custom disk image with Playwright and Chromium pre-installed (~2.4 GB). Build it in ACR using remote build:
az acr build `
--registry <your-acr-name> `
--resource-group <your-rg> `
--image playwright-sandbox:latest `
--file Dockerfile .
Then register it as a disk image via the ACA Sandboxes data plane API. The response includes a GUID — set it as ACA_DISK_IMAGE in script.csx.
Deployment
PAC CLI 2.8.1 has a known bug with OAuth connectionParameters in apiProperties.json. Deploy in two steps:
- Deploy with PAC CLI (swagger + script only):
pac connector create `
-df "apiDefinition.swagger.json" `
-pf "apiProperties.json" `
-sf "script.csx" `
-env <environment-id>
- Configure OAuth in the portal Security tab:
- Identity Provider: Azure Active Directory
- Client ID: your Entra app client ID
- Client Secret: your Entra app secret
- Resource URL:
https://dynamicsessions.io - Scope:
https://dynamicsessions.io/.default offline_access
Resource recommendations
| Scenario | CPU | Memory |
|---|---|---|
| Simple screenshots/extraction | 2000m | 4096Mi |
| Complex SPAs, heavy JavaScript | 4000m | 8192Mi |
Playwright with Chromium needs more resources than a typical code execution sandbox. Start with 2 vCPU / 4 GiB and scale up if pages load slowly.
Use cases
Competitive monitoring — A scheduled flow navigates to competitor pricing pages, extracts content, and stores it in Dataverse for trend analysis. No RPA license needed.
Automated compliance screenshots — Before a deployment goes live, a flow captures screenshots of every critical page and attaches them to the approval record.
Form submission automation — Fill and submit web forms from Power Automate for systems that don’t have APIs. The connector handles login, navigation, form filling, and confirmation capture.
Copilot Studio web research agent — An agent navigates to URLs, extracts relevant content, takes screenshots, and summarizes findings — all conversationally via MCP tools.
PDF report generation — Navigate to a dashboard, wait for data to load, and export as PDF with custom paper format and orientation.
Known limitations
- Browser launches fresh on each operation (~1–2s overhead per call)
- No video recording (would require a persistent process)
- Chromium only (Firefox/WebKit not pre-installed to save image size)
- Sandbox Chromium does not trust system CA certs —
ignoreHTTPSErrors: trueis set on all browser contexts
The full source is available in the SharingIsCaring repository.