Connect to an external browser

Launch a server, get a wsEndpoint, and connect to it.

This example shows two different external-browser connection styles:

  • launchServer() plus connect() for Playwright protocol;
  • connectOverCDP() for a running Chromium browser with remote debugging enabled.

The two mechanisms are not interchangeable. Use the first when another Playwright process owns the browser server. Use CDP only when you intentionally attach to Chromium through Chrome DevTools Protocol.

Run it

bash
php content/examples/connect-external-browser.php

Expected output for the Playwright server part:

text
=== Example 1: Launch Browser Server ===
Browser server started at: ws://127.0.0.1:...

=== Example 2: Connect to Browser Server ===
Page title: Example Domain

The CDP part is optional. If Chrome is not running with remote debugging enabled, the script prints a connection failure and continues.

Try the CDP branch

Start Chrome manually with remote debugging:

bash
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-pw

Then run:

bash
CDP_ENDPOINT='http://127.0.0.1:9222' php content/examples/connect-external-browser.php

CDP is Chromium-only and does not provide the same contract as a Playwright wsEndpoint.

What it demonstrates

  • launchServer() creates a Playwright browser server.
  • connect() attaches through Playwright protocol.
  • connectOverCDP() attaches to Chromium through DevTools Protocol.
  • Playwright protocol endpoints and CDP endpoints have different shapes and semantics.

For a cleaner two-process walkthrough, use the dedicated server and client examples.

Go next

Source

connect-external-browser.php
php
<?php

declare(strict_types=1);

/*
 * This file is part of the community-maintained Playwright PHP project.
 * It is not affiliated with or endorsed by Microsoft.
 *
 * (c) 2025-Present - Playwright PHP - https://github.com/playwright-php
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

require __DIR__.'/../../vendor/autoload.php';

use Playwright\Exception\PlaywrightException;
use Playwright\PlaywrightFactory;

$playwright = PlaywrightFactory::create();

// Example 1: launchServer() exposes a Playwright WebSocket endpoint that can be reused
// by other processes. This endpoint is ephemeral and valid while the server is running.
echo "=== Example 1: Launch Browser Server ===\n";
$server = $playwright->launchServer('chromium', ['headless' => true]);
$wsEndpoint = $server->wsEndpoint();
echo "Browser server started at: {$wsEndpoint}\n";

// Example 2: connect() uses Playwright protocol, so it must target a launchServer() endpoint.
echo "\n=== Example 2: Connect to Browser Server ===\n";
$browser = $playwright->chromium()->connect($wsEndpoint);
$context = $browser->newContext();
$page = $context->newPage();
$page->goto('https://example.com');
echo "Page title: {$page->title()}\n";

$browser->close();
// Closing the client connection does not stop the server process.
$server->close();

// Example 3: connectOverCDP() is Chromium-only and attaches to a running Chrome instance.
// First, start Chrome with remote debugging enabled.
echo "\n=== Example 3: Connect Over CDP (Chromium only) ===\n";
echo "To use this example:\n";
echo "1. Start Chrome with remote debugging on port 9222\n";
echo "   macOS example:\n";
echo "   \"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\" --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-pw\n";
echo "2. Optionally set CDP_ENDPOINT (default: http://127.0.0.1:9222)\n";

$cdpEndpoint = getenv('CDP_ENDPOINT') ?: 'http://127.0.0.1:9222';

try {
    $cdpBrowser = $playwright->chromium()->connectOverCDP($cdpEndpoint);
    $cdpContext = $cdpBrowser->newContext();
    $cdpPage = $cdpContext->newPage();
    $cdpPage->goto('https://playwright.dev');
    echo "Connected via CDP! Title: {$cdpPage->title()}\n";
    $cdpBrowser->close();
} catch (PlaywrightException $e) {
    echo "CDP connection failed at {$cdpEndpoint}: {$e->getMessage()}\n";
}

$playwright->close();

echo "\nDone!\n";