The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
To capture an AJAX request in Selenium Wire, trigger the browser action first, then wait for the matching URL with driver.wait_for_request(). Read the response only after checking that request.response exists. Selenium Wire can also rewrite headers and bodies, alter responses, abort traffic, return mock responses, capture WebSockets and export HAR data. Its upstream repository was archived on January 3, 2024, so treat it as a legacy dependency and evaluate Selenium’s native BiDi network APIs for new automation.
Install Selenium Wire and start a browser
Install the package in the same Python environment as Selenium:
pip install selenium-wire
Import WebDriver from seleniumwire, not from selenium:
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →from seleniumwire import webdriver
driver = webdriver.Chrome()
driver.get("https://example.com")
print(driver.title)
driver.quit()
The project documents Python 3.7+, Selenium 4.0.0+, Chrome, Firefox, Edge and Remote WebDriver. Selenium Wire decrypts HTTPS traffic through its generated certificate handling and requires OpenSSL; Linux installations may need OpenSSL installed separately, while the package documentation says Windows needs no separate installation.
#1 Best Overall
Capture every request and response
Selenium Wire stores captured requests in chronological order in driver.requests. A request can still be in flight, so always test request.response before reading status, headers or body.
from seleniumwire import webdriver
options = {}
driver = webdriver.Chrome(seleniumwire_options=options)
driver.get("https://example.com")
for request in driver.requests:
if request.response:
print(request.method, request.url)
print(request.response.status_code)
print(request.response.headers.get("Content-Type"))
print(request.response.body[:200])
driver.quit()
For the newest captured item, use driver.last_request. When traffic is large, driver.iter_requests() provides an iterator instead of requiring you to work from the complete list.
Wait for the AJAX call caused by a click
The important ordering is action, then wait. wait_for_request() observes a request made by another action; it does not send the request itself. Its pattern is matched within the URL and can be a substring or regular expression. A timeout raises Selenium’s TimeoutException.
from seleniumwire import webdriver
from selenium.common.exceptions import TimeoutException
driver = webdriver.Chrome()
try:
driver.get("https://shop.example")
button = driver.find_element("css selector", "#load-products")
button.click()
request = driver.wait_for_request(r"/api/products/12345/", timeout=10)
print("method:", request.method)
print("url:", request.url)
if request.response:
print("status:", request.response.status_code)
print(request.response.body.decode("utf-8", errors="replace"))
except TimeoutException:
print("The expected request was not observed within 10 seconds")
finally:
driver.quit()
Escape regular-expression metacharacters when the URL text is meant literally. If the page can issue several matching calls, inspect the returned request’s method, query string or body before accepting it.
Modify outgoing requests
Assign a request interceptor before navigation or before the action that creates the traffic. Interceptors receive one request object.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Add or replace a header
from seleniumwire import webdriver
def add_header(request):
request.headers["X-Debug"] = "1"
driver = webdriver.Chrome()
driver.request_interceptor = add_header
driver.get("https://example.com")
Header names can occur more than once. Delete an existing value before replacing it, otherwise you can create a duplicate header:
def replace_referer(request):
del request.headers["Referer"]
request.headers["Referer"] = "https://example.test/"
driver.request_interceptor = replace_referer
Change a JSON POST body
Request bodies are bytes. Decode them, update the parsed object, encode the result and update Content-Length so the server receives a consistent message.
Free tools Windows power users keep installed
One-click scans. No signup required.
import json
def edit_json(request):
if request.url.endswith("/api/search") and request.method == "POST":
payload = json.loads(request.body.decode("utf-8"))
payload["debug"] = True
request.body = json.dumps(payload).encode("utf-8")
del request.headers["Content-Length"]
request.headers["Content-Length"] = str(len(request.body))
driver.request_interceptor = edit_json
Remove an interceptor when it should no longer affect later navigation:
del driver.request_interceptor
Modify, block or mock responses
Change a response header
A response interceptor receives both the originating request and its response. As with request headers, delete a value before replacing it.
def add_response_header(request, response):
if request.url.endswith("/api/products"):
response.headers["X-Inspected"] = "1"
driver.response_interceptor = add_response_header
del driver.response_interceptor
Abort unwanted requests
request.abort() stops the request and returns an immediate error (403 by default). This is useful for blocking images or other noisy resources.
Rank #3
def block_images(request):
if request.path.endswith((".png", ".jpg", ".gif")):
request.abort()
driver.request_interceptor = block_images
Return a local mock response
create_response() responds without contacting the remote server:
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesdef mock_products(request):
if request.url == "https://server.example/api/products":
request.create_response(
status_code=200,
headers={"Content-Type": "application/json"},
body='{"products": []}'
)
driver.request_interceptor = mock_products
Capture less traffic and control storage
Limit captured URLs with scopes
Selenium Wire routes browser traffic through an internal proxy and captures all URLs by default. Set scopes before navigation to retain only matching URL regular expressions:
driver.scopes = [r".*api\.example\.com/.*"]
Out-of-scope requests still pass through the proxy; they are simply not stored as captured requests. To stop interception and storage while traffic continues through the proxy, use disable_capture=True. To bypass Selenium Wire completely for selected hosts, configure exclude_hosts.
HAR files and request storage
HAR capture is disabled by default. Enable it at driver creation and read driver.har:
driver = webdriver.Chrome(
seleniumwire_options={"enable_har": True}
)
# ... perform navigation and actions ...
har_data = driver.har
The default ignored-method list includes OPTIONS. Capture preflight requests by setting ignore_http_methods to an empty list. For short-lived containers, use memory storage and cap retained items:
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
driver = webdriver.Chrome(seleniumwire_options={
"request_storage": "memory",
"request_storage_max_size": 500
})
Remote WebDriver and HTTPS caveats
- HTTPS: decryption depends on OpenSSL and Selenium Wire's generated certificate. Certificate or proxy errors usually indicate that the browser cannot trust the generated certificate or that OpenSSL is unavailable.
- Remote sessions: provide the Selenium Wire backend address with the
addroption. When the browser runs on another machine, manual proxy configuration may also be required. - Request timing: install the interceptor and scopes before the page action; assigning them afterward cannot change traffic that already occurred.
- Memory: unrestricted capture grows with every request. Narrow scopes or use bounded memory storage for long sessions.
Selenium Wire versus Selenium BiDi for new work
| Area | Selenium Wire | Selenium BiDi network API |
|---|---|---|
| Maintenance | Upstream repository archived January 3, 2024; read-only. | Documented as Selenium's native direction for network interception. |
| Integration model | Python binding extension using an internal proxy. | Browser-native Selenium network events and commands. |
| Interception shown by the documentation | Request/response inspection and mutation, aborts, mocks, HAR and storage controls. | Intercepted Request operations including fail_request() and continue_request(...). |
| Feature parity | Established proxy, HAR and storage features. | Complete parity with those Selenium Wire features is not established here. |
| Migration | Existing scripts can continue if their pinned environment is acceptable. | Investigate for new implementations and verify the exact browser and Selenium versions you deploy. |
For an existing test suite that depends on HAR export, proxy exclusions or create_response(), pin the archived package, review its security posture and plan a migration rather than assuming a one-to-one replacement.
Troubleshooting checklist
wait_for_request times out
- Click or submit the UI element before calling the wait.
- Check that the URL pattern matches the actual request, including path, query string and escaping.
- Increase the timeout only after confirming the action really triggers the call.
- If several requests are issued, use a narrower pattern and inspect method or body.
No response fields are available
The request may still be in flight. Test if request.response: before reading status, headers or body. A failed load can leave a request without a response.
Headers appear twice
Delete the old header first. Selenium Wire permits duplicate header names and assignment alone does not replace every existing value.
Preflight requests are missing
OPTIONS is ignored by default. Set ignore_http_methods to [].
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallToo many requests or high memory use
Set driver.scopes, use request_storage="memory" with request_storage_max_size, or bypass selected hosts with exclude_hosts.
Best Value
Remote or HTTPS errors
Check OpenSSL, generated-certificate trust, the Selenium Wire backend addr, and proxy settings on the machine running the browser.
Or skip the browser setup
If your goal is a clean page image or PDF rather than inspecting an AJAX exchange, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP or PDF. Its capture pipeline accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets before the shot; bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
Use the API documentation at https://screenshotneo.com/docs/ for all options. A minimal call is:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo includes full-page and element capture, device presets, custom viewport and retina scale, dark mode, PDF controls, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed links, async webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification. Parameter names used by other screenshot APIs also work. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can Selenium Wire capture WebSocket traffic?
The project lists WebSocket capture among its capabilities, but the same archived maintenance status applies to that functionality.
What does last_request return?
It is a shortcut for the newest captured request; it may not have a response yet, so apply the same response check.
Do out-of-scope requests bypass the proxy?
No. Scopes limit what Selenium Wire captures; out-of-scope traffic still travels through its proxy.
Recommended Free Tools
Is Selenium BiDi a drop-in replacement?
Not necessarily. Its documented intercepted-request operations are a native starting point, but complete parity with Selenium Wire's proxy, HAR and storage features is not established.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

