Selenium & Playwright Guide
Integrate har-capture-proxy into your browser automation tests for HAR capture, network throttling, and response mutation.
Overview
har-capture-proxy provides a REST API that you control from your test code. The workflow is always the same regardless of language or framework:
- Start the
har-capture-proxybinary (or ensure it is running) - Create a proxy session via
POST /proxy - Configure your browser to use the proxy
- Optionally enable HAR capture or add mutation rules
- Run your tests
- Retrieve HAR data or tear down the session
Prerequisites
- Download the
har-capture-proxybinary from GitHub Releases - Trust the CA certificate at
~/.har-capture-proxy/har-capture-proxy-ca.pem(auto-generated on first run) - The CA certificate Common Name is "har-capture-proxy CA"
For CI environments, you can pre-generate the CA cert on one machine and distribute it, or add it to the trust store in your Docker image or CI setup script.
Step-by-Step Integration
1. Start the binary
Launch har-capture-proxy with the REST API on a known port:
./har-capture-proxy --port 8080
2. Create a proxy session
Use the REST API to spin up a new proxy listener:
curl -X POST http://localhost:8080/proxy
# Response: {"port": 8081}
3. Enable HAR capture
curl -X PUT "http://localhost:8080/proxy/8081/har?captureHeaders=true&captureContent=true"
4. Configure the browser
Point your browser's HTTP/HTTPS proxy to localhost:8081 (the port returned in step 2).
5. Add mutation rules (optional)
curl -X POST http://localhost:8080/proxy/8081/rules \
-H "Content-Type: application/json" \
-d '[{"url_pattern": ".*api\\.example\\.com.*", "json_mutations": [{"selector": "$.user.name", "action": "set", "value": "Test User"}]}]'
6. Run your tests, then retrieve HAR
curl http://localhost:8080/proxy/8081/har -o capture.har
7. Tear down
curl -X DELETE http://localhost:8080/proxy/8081
Ruby (Selenium WebDriver)
This example uses Ruby's built-in Net::HTTP to manage the proxy and Selenium WebDriver for Chrome.
require 'selenium-webdriver'
require 'net/http'
require 'json'
require 'uri'
PROXY_API = "http://localhost:8080"
# 1. Create a proxy session
uri = URI("#{PROXY_API}/proxy")
response = Net::HTTP.post(uri, "")
proxy_port = JSON.parse(response.body)["port"]
puts "Proxy started on port #{proxy_port}"
# 2. Enable HAR capture
uri = URI("#{PROXY_API}/proxy/#{proxy_port}/har?captureHeaders=true&captureContent=true")
Net::HTTP.start(uri.host, uri.port) do |http|
http.put(uri, "")
end
# 3. Add mutation rules (optional)
rules_uri = URI("#{PROXY_API}/proxy/#{proxy_port}/rules")
rules = [
{
url_pattern: ".*api\\.example\\.com.*",
json_mutations: [
{ selector: "$.user.email", action: "set", value: "test@example.com" }
]
}
]
req = Net::HTTP::Post.new(rules_uri)
req["Content-Type"] = "application/json"
req.body = rules.to_json
Net::HTTP.start(rules_uri.host, rules_uri.port) { |http| http.request(req) }
# 4. Configure Chrome to use the proxy
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument("--proxy-server=http://localhost:#{proxy_port}")
options.add_argument("--ignore-certificate-errors")
driver = Selenium::WebDriver.for(:chrome, options: options)
begin
# 5. Run your test
driver.get("https://example.com")
puts "Page title: #{driver.title}"
# 6. Retrieve HAR
har_uri = URI("#{PROXY_API}/proxy/#{proxy_port}/har")
har_response = Net::HTTP.get(har_uri)
File.write("capture.har", har_response)
puts "HAR saved to capture.har"
ensure
# 7. Cleanup
driver.quit
uri = URI("#{PROXY_API}/proxy/#{proxy_port}")
Net::HTTP.start(uri.host, uri.port) do |http|
http.delete(uri)
end
end
The #{variable} syntax in the code above is Ruby string interpolation, not template placeholders. These expressions are evaluated at runtime by Ruby.
JavaScript (Playwright)
Playwright has built-in proxy support. Use fetch (Node 18+) or any HTTP client to control the proxy API.
const { chromium } = require('playwright');
const PROXY_API = 'http://localhost:8080';
(async () => {
// 1. Create a proxy session
const createRes = await fetch(`${PROXY_API}/proxy`, { method: 'POST' });
const { port: proxyPort } = await createRes.json();
console.log(`Proxy started on port ${proxyPort}`);
// 2. Enable HAR capture
await fetch(
`${PROXY_API}/proxy/${proxyPort}/har?captureHeaders=true&captureContent=true`,
{ method: 'PUT' }
);
// 3. Add mutation rules (optional)
await fetch(`${PROXY_API}/proxy/${proxyPort}/rules`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify([{
url_pattern: '.*api\\.example\\.com.*',
json_mutations: [
{ selector: '$.user.name', action: 'set', value: 'Test User' }
]
}])
});
// 4. Launch browser with proxy
const browser = await chromium.launch({
proxy: {
server: `http://localhost:${proxyPort}`
}
});
const context = await browser.newContext({
ignoreHTTPSErrors: true
});
const page = await context.newPage();
// 5. Run your test
await page.goto('https://example.com');
console.log(`Page title: ${await page.title()}`);
// 6. Retrieve HAR
const harRes = await fetch(`${PROXY_API}/proxy/${proxyPort}/har`);
const har = await harRes.text();
const fs = require('fs');
fs.writeFileSync('capture.har', har);
console.log('HAR saved to capture.har');
// 7. Cleanup
await browser.close();
await fetch(`${PROXY_API}/proxy/${proxyPort}`, { method: 'DELETE' });
})();
Python (Selenium WebDriver)
Uses the requests library for proxy management and Selenium for Chrome.
import requests
import json
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
PROXY_API = "http://localhost:8080"
# 1. Create a proxy session
response = requests.post(f"{PROXY_API}/proxy")
proxy_port = response.json()["port"]
print(f"Proxy started on port {proxy_port}")
# 2. Enable HAR capture
requests.put(
f"{PROXY_API}/proxy/{proxy_port}/har",
params={"captureHeaders": "true", "captureContent": "true"}
)
# 3. Add mutation rules (optional)
rules = [{
"url_pattern": ".*api\\.example\\.com.*",
"json_mutations": [
{"selector": "$.user.name", "action": "set", "value": "Test User"}
]
}]
requests.post(
f"{PROXY_API}/proxy/{proxy_port}/rules",
json=rules
)
# 4. Configure Chrome to use the proxy
chrome_options = Options()
chrome_options.add_argument(f"--proxy-server=http://localhost:{proxy_port}")
chrome_options.add_argument("--ignore-certificate-errors")
driver = webdriver.Chrome(options=chrome_options)
try:
# 5. Run your test
driver.get("https://example.com")
print(f"Page title: {driver.title}")
# 6. Retrieve HAR
har = requests.get(f"{PROXY_API}/proxy/{proxy_port}/har")
with open("capture.har", "w") as f:
f.write(har.text)
print("HAR saved to capture.har")
finally:
# 7. Cleanup
driver.quit()
requests.delete(f"{PROXY_API}/proxy/{proxy_port}")
BrowserMob Proxy Migration Checklist
If you are migrating from BrowserMob Proxy, follow this checklist to ensure a smooth transition.
-
✓Replace the BMP JAR and JVM dependency with the single
har-capture-proxybinary. Use the same--portflag for the REST API port. -
✓Update the CA certificate. Remove the old BMP CA cert and install
~/.har-capture-proxy/har-capture-proxy-ca.pemin your browser or test trust store. -
✓Verify your REST API base URL. The endpoints are identical:
/proxy,/proxy/{port}/har, etc. -
✓If you used BMP's embedded Java API, switch to REST API calls. har-capture-proxy is REST-only by design.
-
✓Remove JVM tuning flags (
-Xmx,-Xms, GC options). har-capture-proxy uses ~3 MB of memory at idle. -
✓Update any process management (systemd, Docker, CI scripts) to launch the new binary.
-
✓Run your existing test suite. All BMP-compatible endpoints work identically.
-
✓(Optional) Add response mutation rules using the new
/proxy/{port}/rulesendpoint for capabilities that were not available in BMP.
CI Pipeline Tips
Start as a background service
In CI, start har-capture-proxy before your test suite runs:
# Start in background
./har-capture-proxy --port 8080 &
PROXY_PID=$!
# Wait for it to be ready
sleep 1
# Run your tests
bundle exec rspec
# Stop the proxy
kill $PROXY_PID
Docker
Run har-capture-proxy as a sidecar container or within the same container as your tests:
# Dockerfile snippet
COPY har-capture-proxy /usr/local/bin/har-capture-proxy
RUN chmod +x /usr/local/bin/har-capture-proxy
GitHub Actions
steps:
- name: Download har-capture-proxy
run: |
curl -L https://github.com/jaygen/har-capture-proxy/releases/latest/download/har-capture-proxy-x86_64-unknown-linux-gnu \
-o har-capture-proxy
chmod +x har-capture-proxy
- name: Start proxy
run: |
./har-capture-proxy --port 8080 &
sleep 1
- name: Run tests
run: npm test
Parallel test suites
Each test worker can create its own proxy session via POST /proxy. Sessions are isolated from each other. No need to run multiple proxy processes.
Use POST /proxy?port=0 to let the OS assign an available port. This avoids port conflicts in parallel test environments.
Always delete proxy sessions after tests complete (DELETE /proxy/{port}) to free up resources. Leaked sessions accumulate memory and file descriptors.