Playwright is a modern web automation framework that provides reliable end-to-end testing and automation capabilities. With Orchestrator, you can run Playwright scripts against real browser instances in the cloud without managing infrastructure.

Installation

Install Playwright in your project:
npm install playwright
You don’t need to install browser binaries since you’ll be connecting to Orchestrator’s cloud browsers.

Basic Setup

Here’s a complete example of connecting Playwright to an Orchestrator session:
const { chromium } = require('playwright');

async function connectToOrchestrator() {
  // Create a new browser session
  const sessionResponse = await fetch('https://api.orchestratorhq.com/api/sessions', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer orch_your_api_key_here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      session_name: 'Playwright Automation',
      duration: '1h'
    })
  });

  const session = await sessionResponse.json();
  console.log('Session created:', session.id);

  // Connect to the browser using CDP (session is active when API responds)
  const browser = await chromium.connectOverCDP(session.cdp_url);
  const context = browser.contexts()[0];
  const page = context.pages()[0];

  return { browser, context, page, sessionId: session.id };
}

// Usage
async function main() {
  const { browser, page, sessionId } = await connectToOrchestrator();

  try {
    // Your automation code here
    await page.goto('https://example.com');
    console.log('Page title:', await page.title());

    // Take a screenshot
    await page.screenshot({ path: 'example.png' });

  } finally {
    // Clean up
    await browser.close();

    // Stop the session
    await fetch(`https://api.orchestratorhq.com/api/sessions/${sessionId}`, {
      method: 'DELETE',
      headers: {
        'Authorization': 'Bearer orch_your_api_key_here'
      }
    });
  }
}

main().catch(console.error);

Web Scraping Example

Here’s a practical example of using Playwright with Orchestrator for web scraping:
const { chromium } = require('playwright');

async function scrapeWithPlaywright() {
  // Create and connect to session
  const sessionResponse = await fetch('https://api.orchestratorhq.com/api/sessions', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer orch_your_api_key_here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      session_name: 'Web Scraping Session',
      duration: '30m'
    })
  });

  const session = await sessionResponse.json();

  // Connect to browser (session is active when API responds)
  const browser = await chromium.connectOverCDP(session.cdp_url);
  const context = browser.contexts()[0];
  const page = context.pages()[0];

  try {
    // Navigate to the target website
    await page.goto('https://quotes.toscrape.com/', { waitUntil: 'networkidle' });

    // Extract quotes
    const quotes = await page.evaluate(() => {
      const quoteElements = document.querySelectorAll('.quote');
      return Array.from(quoteElements).map(quote => ({
        text: quote.querySelector('.text')?.textContent,
        author: quote.querySelector('.author')?.textContent,
        tags: Array.from(quote.querySelectorAll('.tag')).map(tag => tag.textContent)
      }));
    });

    console.log('Scraped quotes:', quotes);

    // Navigate to next page if available
    const nextButton = await page.$('.next > a');
    if (nextButton) {
      await nextButton.click();
      await page.waitForLoadState('networkidle');
      
      // Scrape more quotes from the next page
      const moreQuotes = await page.evaluate(() => {
        const quoteElements = document.querySelectorAll('.quote');
        return Array.from(quoteElements).map(quote => ({
          text: quote.querySelector('.text')?.textContent,
          author: quote.querySelector('.author')?.textContent,
          tags: Array.from(quote.querySelectorAll('.tag')).map(tag => tag.textContent)
        }));
      });

      console.log('More quotes:', moreQuotes);
    }

    return [...quotes, ...moreQuotes];

  } finally {
    await browser.close();
    
    // Clean up session
    await fetch(`https://api.orchestratorhq.com/api/sessions/${session.id}`, {
      method: 'DELETE',
      headers: { 'Authorization': 'Bearer orch_your_api_key_here' }
    });
  }
}

scrapeWithPlaywright().catch(console.error);

Testing Example

Use Playwright with Orchestrator for end-to-end testing:
const { chromium } = require('playwright');
const { test, expect } = require('@playwright/test');

// Custom fixture for Orchestrator connection
test.extend({
  orchestratorPage: async ({}, use) => {
    // Create session
    const sessionResponse = await fetch('https://api.orchestratorhq.com/api/sessions', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer orch_your_api_key_here',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        session_name: 'E2E Test Session',
        duration: '15m'
      })
    });

    const session = await sessionResponse.json();

    // Connect to browser (session is active when API responds)
    const browser = await chromium.connectOverCDP(session.cdp_url);
    const context = browser.contexts()[0];
    const page = context.pages()[0];

    // Use the page in tests
    await use(page);

    // Cleanup
    await browser.close();
    await fetch(`https://api.orchestratorhq.com/api/sessions/${session.id}`, {
      method: 'DELETE',
      headers: { 'Authorization': 'Bearer orch_your_api_key_here' }
    });
  }
});

test('homepage loads correctly', async ({ orchestratorPage }) => {
  await orchestratorPage.goto('https://example.com');
  
  await expect(orchestratorPage).toHaveTitle(/Example Domain/);
  
  const heading = orchestratorPage.locator('h1');
  await expect(heading).toContainText('Example Domain');
});

test('navigation works', async ({ orchestratorPage }) => {
  await orchestratorPage.goto('https://example.com');
  
  // Test navigation
  const moreInfoLink = orchestratorPage.locator('a[href*="iana.org"]');
  await expect(moreInfoLink).toBeVisible();
  
  // Take screenshot for visual verification
  await orchestratorPage.screenshot({ path: 'navigation-test.png' });
});

Advanced Configuration

Request Interception

Intercept and modify network requests:
async function interceptRequests() {
  const { browser, context, page, sessionId } = await connectToOrchestrator();

  try {
    // Enable request interception
    await page.route('**/*', (route) => {
      const request = route.request();
      
      // Block images to speed up loading
      if (request.resourceType() === 'image') {
        route.abort();
        return;
      }

      // Modify headers
      const headers = {
        ...request.headers(),
        'X-Custom-Header': 'Orchestrator-Playwright'
      };

      route.continue({ headers });
    });

    await page.goto('https://httpbin.org/headers');
    
    // The response should show our custom header
    const content = await page.textContent('pre');
    console.log('Headers:', content);

  } finally {
    await browser.close();
    // Stop session...
  }
}

Error Handling and Best Practices

Debugging with VNC

When your automation isn’t working as expected, use VNC to visually debug:
1

Get VNC Access

Retrieve the VNC URL from your session details (available in the session creation response or by fetching session details).
2

Connect via Dashboard

Use the Orchestrator dashboard to view the live browser session.
3

Add Debugging Pauses

Add await page.pause() in your Playwright script to pause execution and inspect the browser state.
4

Take Screenshots

Use await page.screenshot({ path: 'debug.png' }) at key points to capture the browser state.

Performance Tips

Next Steps