# How to Use Selenium Wire in 2026

> Learn how to use Selenium Wire to upgrade your Selenium web scraping and avoid getting blocked again.

Source: https://www.zenrows.com/blog/selenium-wire

Selenium is great for automating browsers, but it doesn’t give you access to network traffic. That’s where Selenium Wire comes in—it adds the ability to inspect and modify requests and responses. 
Let's see how to use it!

## What Is Selenium Wire
Selenium Wire is a Python library that enhances Selenium's Python bindings so that you can access the actual requests made by the browser. It provides an easy-to-use interface for intercepting and modifying network traffic.

Furthermore, web scrapers can use Selenium Wire to analyze a website's network traffic, such as requests, responses, and WebSocket messages.

## Install Selenium Wire in Python and Get Started
Let’s get Selenium Wire set up. First, make sure you’re running [**Python**](https://www.python.org/downloads/) **v3.7** or later—you can check with:

```nginx
python --version
```

Then, install Selenium Wire using `pip`:

```nginx
pip install selenium-wire
```

Installing Selenium Wire will also pull in Selenium, since it builds on top of it. While Selenium works with all major browsers, we’ll use Chrome for this guide.

**Note:** Installing WebDriver was once required, but not anymore. Selenium version 4 or higher includes it by default. To ensure you have the latest features, update Selenium if you're using an older version. You can check your current version with `pip show selenium` and upgrade with `pip install --upgrade selenium` if needed.

Here's a script showing the primary usage of Selenium. It initializes an instance of the [ChromeDriver](https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.chrome.webdriver) and opens [ScrapingCourse.com](https://www.scrapingcourse.com/ecommerce/) (our target site) in a new browser tab. It then kills the instance and prints the text content of the site.

<!-- script.py -->
```python
from selenium import webdriver 
from selenium.webdriver.common.by import By

# creates an instance of the chrome driver (browser)
driver = webdriver.Chrome()
# hit target site
driver.get("https://www.scrapingcourse.com/ecommerce/")
# get body element of target site
body = driver.find_element(By.TAG_NAME, 'body')
# print body text content
print(body.text)

# kill browser instance
driver.quit()
```

> **Note**
>
> Check out our [Selenium web scraping](/blog/selenium-python-web-scraping) tutorial if you want to review concepts.

Now, to use `selenium-wire`, update the import of `webdriver` from `selenium` to `seleniumwire`:

<!-- script.py -->
```python
from seleniumwire import webdriver
from selenium.webdriver.common.by import By
```

Run the script powered by Selenium Wire, and you'll see the target site in a new browser instance:

![scrapingcourse ecommerce controlled by automated software](https://static.zenrows.com/content/scraping_course_ecommerce_controlled_by_automated_software_b9fa616b55.jpg)

After it closes, you'll see the page text in your terminal:

<!-- Terminal -->
```bash
Skip to navigation
Skip to content
Ecommerce Test Site to Learn Web Scraping
ScrapingCourse.com
Search for:
Search
Shop
$0.00 0 items
Shop
     Default sorting
     Sort by popularity
     Sort by latest
     Sort by price: low to high
     Sort by price: high to low
    Showing 1–16 of 188 results
1 2 3 4 … 10 11 12 →
Abominable Hoodie
$69.00
```

### Parse Response to JSON
ScrapingCourse.com contains a list of products with their respective price, and we'll scrape them into a JSON object.

Use the `woocommerce-loop-product__title` class to get the name of each creature and the `woocommerce-Price-amount` one to get their individual price.

![scrapingcourse ecommerce homepage selected product h2 class](https://static.zenrows.com/content/scrapingcourse_ecommerce_homepage_selected_product_h2_class_78e47ab4f1.png)

Do those steps by looping through all the products and storing the name and price as key-value pairs in the `data` dictionary.

<!-- script.py -->
```python
import json

# ...

driver.get('https://www.scrapingcourse.com/ecommerce/')

products = driver.find_elements(By.CSS_SELECTOR, '.products > li')
data = {}
for product in products:
    product_name = product.find_element(By.CLASS_NAME, 'woocommerce-loop-product__title').text
    product_price = product.find_element(By.CLASS_NAME, 'woocommerce-Price-amount').text
    data[product_name] = product_price

print(json.dumps(data, ensure_ascii=False))

# kill browser instance
driver.quit()
```

Here's the complete code:

<!-- scraper.py -->
```python
from seleniumwire import webdriver
from selenium.webdriver.common.by import By
import json

driver = webdriver.Chrome()

driver.get('https://www.scrapingcourse.com/ecommerce/')

products = driver.find_elements(By.CSS_SELECTOR, '.products > li')
data = {}
for product in products:
    product_name = product.find_element(By.CLASS_NAME, 'woocommerce-loop-product__title').text
    product_price = product.find_element(By.CLASS_NAME, 'woocommerce-Price-amount').text
    data[product_name] = product_price

print(json.dumps(data, ensure_ascii=False))

# kill browser instance
driver.quit()
```

Run the script, and you should see an output on your terminal like this:

<!-- Terminal -->
```bash
{
    "Abominable Hoodie": "$69.00",  
    
    #... other products omitted for brevity

    "Artemis Running Short": "$45.00"
}
```

### Chrome Options of Selenium Wire
Selenium Wire allows you to specify additional Chrome options when creating a WebDriver to customize it further. You can pass them as an argument to the `seleniumwire_options` parameter.

<!-- script.py -->
```python
driver = webdriver.Chrome(
    options=webdriver.ChromeOptions(...),
    # seleniumwire options
    seleniumwire_options={}
)
```

This is a list of all options made available by Selenium Wire:

| **Option**                         | **Description**                                                                        | **Example**                                                                                                   | **Default Value**      |
| ------------------------------ | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------ |
| `addr`                       | The current machine's IP or hostname                                               | `{ 'addr': '159.89.173.104' }`                                                                          | `127.0.0.1`      |
| `auto_config`                | Auto-configure the browser for request capture                                     | `{ 'auto_config': False }`                                                                              | `True`           |
| `ca_cert`                    | The path to a root (CA) certificate                                                | `{ 'ca_cert': '/path/to/ca.crt' }`                                                                      | Default path       |
| `ca_key`                     | The path to the private key                                                        | `{ 'ca_key': '/path/to/ca.key' }`                                                                       | Default key        |
| `disable_capture`            | Disable request capture                                                            | `{ 'disable_capture': True }`                                                                           | `False`          |
| `disable_encoding`           | Request uncompressed server data                                                   | `{ 'disable_encoding': True }`                                                                          | `False`          |
| `enable_har`                 | Store a HAR archive of HTTP transactions that can be retrieved with `driver.har` | `{ 'enable_har': True }`                                                                                | `False`          |
| `exclude_hosts`              | The addresses Selenium Wire should ignore                                          | `{ 'exclude_hosts': ['zenrows.com'] }`                                                                  | `[]`             |
| `ignore_http_methods`        | Selenium Wire will ignore these uppercase HTTP methods                             | `{ 'ignore_http_methods': ['TRACE'] }`                                                                  | `['OPTIONS']`    |
| `port`                       | Selenium Wire's backend port                                                       | `{ 'port': 8080 }`                                                                                      | Random port        |
| `proxy`                      | The proxy server's upstream configuration                                          | `{ 'proxy': { 'http': 'http://190.43.92.130:999', 'https': 'http://5.78.76.237:8080', } }` | `{}`             |
| `request_storage`            | Storage type                                                                       | `{ 'request_storage': 'memory }`                                                                        | `disk`               |
| `request_storage_base_dir`   | Selenium Wire's default disk-based storage location for requests and responses     | `{ 'request_storage_base_dir': '/path/to/storage_folder' }`                                             | System temp folder |
| `request_storage_max_size`   | The maximum number of requests to store in-memory                                  | `{ 'request_storage_max_size': 100 }`                                                                   | Unlimited          |
| `suppress_connection_errors` | Suppress connection-related tracebacks                                             | `{ 'suppress_connection_errors': False }`                                                               | `True`              |
| `verify_ssl`                 | Verify SSL certificates                                                            | `{ 'verify_ssl': False }`                                                                               | `False`             |

> **Skip the blocks.** [Try Zenrows free](/) and get clean web data without the anti-bot fight.

## Understand the Request and Response Objects
Selenium provides access to two objects that represent HTTP requests and responses: the `request` and `response` objects.

You can see the **attributes of the `request` object** below:

| **Attribute**       | **Description**                                                                        |
| --------------- | ---------------------------------------------------------------------------------- |
| `body`        | Returns the request body as a byte string                                          |
| `cert`        | Dictionary-format SSL certificate information                                      |
| `date`        | Time when the request was made                                                     |
| `headers`     | Dictionary of request headers                                                      |
| `host`        | Request host                                                                       |
| `method`      | HTTP method                                                                        |
| `params`      | Dictionary of parameters                                                           |
| `path`        | Request path                                                                       |
| `querystring` | Query string                                                                       |
| `response`    | Response object associated with the request                                        |
| `url`         | Request URL                                                                        |
| `ws_messages` | For WebSocket handshake requests, this is a list of any messages sent and received |

The **properties of the `response` object** are as follows:

| **Attribute**       | **Description**                                |
| --------------- | ------------------------------------------ |
| `body`        | Returns the response body as a byte string |
| `date`        | Time the response was received             |
| `headers`     | Dictionary of request headers              |
| `reason`      | Reason phrase                              |
| `status_code` | Status code of the response                |

## Avoid Being Blocked While Using Selenium Wire Proxy in Python
Unfortunately, using Selenium Wire in Python to scrape websites can also get your scraper blocked. However, there are ways to avoid that, so let's explore them! 

### Use a Proxy with Selenium Wire
A proxy acts as a middleman between your machine and the website you're trying to scrape. You can hide your IP address and avoid detection by routing traffic through it.

Use a [proxy with Selenium](/blog/selenium-proxy) Wire by grabbing a free proxy for web scraping and specifying the `proxy` option in the `seleniumwire_options` dictionary. Update your script like this:

<!-- script.py -->
```python
# ...

PROXY = 'http://61.28.233.217:3128'

seleniumwire_options = {
    'proxy': {
        'http': PROXY,
        'https': PROXY,
    },
}

# creates an instance of the chrome driver (browser)
driver = webdriver.Chrome(
    # seleniumwire options
    seleniumwire_options=seleniumwire_options,
)

# hit target site
driver.get('https://httpbin.org/anything')

body = driver.find_element(By.TAG_NAME, 'body')

print(body.text)

# ...
```

We've replaced the target site with [HTTPBin](https://httpbin.org/anything), which returns some information about the clients that make requests to it, including their IP.

> **Note**
>
> The proxy specified in `PROXY` is free and may not work for you. If so, get a fresh one from a provider like [Free Proxy List](https://free-proxy-list.net/) using this format:
> ```
> <PROXY_PROTOCOL>://<PROXY_IP_ADDRESS>:<PROXY_PORT>
> ```

Run the script, and you'll get an IP address different from your machine's.

![Selenium Wire Proxy](https://static.zenrows.com/content/selenium_wire_proxy_d4d9c93c5e.png)

#### Proxy Authentication in Selenium Wire

Some proxies require credentials before granting access, but you can perform Selenium Wire proxy authentication by adding the username and password using the below format:

```python
<PROXY_PROTOCOL>://<YOUR_USERNAME>:<YOUR_PASSWORD>@<PROXY_IP_ADDRESS>:<PROXY_PORT>
```

The updated script with the credentials will look like this:

```python
# ...

PROXY = 'http://<YOUR_USERNAME>:<YOUR_PASSWORD>@61.28.233.217:3128'

# ...
```

#### Error: Selenium Wire with Proxy Is Not Working

In certain scenarios, your proxy may not work with Selenium Wire, and you'll see the common error `ERR_TUNNEL_CONNECTION_FAILED`. In that case, either your proxy isn't running or accessible from your network, or your proxy configuration isn't correct. 

Here's what you can do to fix it:

1.  Start by pinging the proxy through a browser to ensure it's active. If not, check if your proxy's IP and ports are correct and that no firewalls are blocking your connection to the proxy server.
2.  If you're still experiencing errors, you'll need to use a different proxy server or network.

**Related:** [How to Rotate Proxies in Selenium Python: 2026 Tutorial](/blog/rotating-proxy-selenium-python)

#### Why You Need Premium Proxies

Using free proxies has some important downsides: they're unreliable, insecure, and sometimes malicious. They're also often overloaded, resulting in poor performance. That's where premium [proxies for web scraping](/blog/web-scraping-proxy) come in.

Popular solutions like Zenrows provide residential rotating proxies at an amazing rate. Your overall experience will be notably better, and you won't get blocked easily. Also, it comes with a complete toolkit to bypass anti-scraping measures.

[Sign up](/) for free on Zenrows to open the Request Builder. Once in the Builder, go to the Proxy Generator dashboard. Then, copy and paste your proxy credentials into your Python script.

![generate residential proxies with zenrows](/blog/_img/zenrows-proxy.png)

Update the `PROXY` variable with the credentials you copied to get a different IP whenever you run the script:

```python
# ...

PROXY = 'http://<ZENROWS_PROXY_USERNAME>:<ZENROWS_PROXY_PASSWORD>@superproxy.zenrows.com:1337'
# ...
```

Zenrows is more effective than free proxies, it scales easily, is cheaper than traditional proxy providers, and you'll have a higher success rate when scraping.

### Customize Headers in Selenium Wire
Using default[ headers while web scraping](/blog/web-scraping-headers) is likely to get you blocked, mostly because of the User-Agent string. But as Selenium Wire enables us to intercept requests, we can set a new custom UA for each request.

To do that, update your script with the below code:

<!-- script.py -->
```python
# ...

# Creates an instance of the chrome driver (browser)
driver = webdriver.Chrome(
    # seleniumwire options
    seleniumwire_options={},
)

CUSTOM_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
SEC_CH_UA = '"Google Chrome";v="112", " Not;A Brand";v="99", "Chromium";v="112"'
REFERER = 'https://google.com'

def request_interceptor(request):
    # delete previous UA
    del request.headers["user-agent"]
    # set new custom UA
    request.headers["user-agent"] = CUSTOM_UA
    # delete previous Sec-CH-UA
    del request.headers["sec-ch-ua"]
    # set Sec-CH-UA
    request.headers["sec-ch-ua"] = SEC_CH_UA
    # set referer
    request.headers["referer"] = REFERER

driver.request_interceptor = request_interceptor

# hit target site
driver.get('https://httpbin.org/anything')

# ...
```

> **Note**
>
> We also set the `sec-ch-ua` and `referer` headers to provide additional information about the UA. You can learn more about [User-Agents for web scraping](/blog/user-agent-web-scraping) in our in-depth tutorial.

Run the script, and you'll see that your UA will change to what you set it to.

![Customize User Agent](https://static.zenrows.com/content/customize_user_agent_de9ca051a9.png)

### Add Undetected ChromeDriver to Selenium Wire
[Undetected Chromedriver](/blog/undetected-chromedriver) for Selenium Wire is a patched ChromeDriver that avoids popular bot detection mechanisms that websites use to identify and block automated traffic. And luckily, Selenium Wire integrates Undetected ChromeDriver if found in the same environment it's installed in.

Let's install the patched driver:

```nginx
pip install undetected-chromedriver
```

Now, update your current driver with the patched one:

<!-- script.py -->
```python
# ...
import undetected_chromedriver as uc

# creates an instance of the chrome driver (browser)
driver = uc.Chrome(
    # seleniumwire options
    seleniumwire_options={},
)

# hit target site
driver.get('https://www.scrapingcourse.com/ecommerce/')

body = driver.find_element(By.TAG_NAME, 'body')

print(body.text)

driver.quit()
```

Your script will work as before but with a set of bot detection bypass features.

However, it'll fail on websites with advanced bot detection, like [G2](https://www.g2.com/products/asana/reviews).

Let's see what happens when we scrape G2:

<!-- script.py -->
```python
from selenium.webdriver.common.by import By
import undetected_chromedriver as uc
from selenium.webdriver.support.wait import WebDriverWait

# creates an instance of the chrome driver (browser)
driver = uc.Chrome(
    # seleniumwire options
    seleniumwire_options={},
)

# hit target site
driver.get('https://www.g2.com/products/asana/reviews')

# wait for element with a class of "off-canvas-wrapper"
WebDriverWait(driver, timeout=30).until(lambda d: d.find_element(By.CLASS_NAME,"off-canvas-wrapper"))

body = driver.find_element(By.TAG_NAME, 'body')

print(body.text)

driver.quit()
```

G2 detected us as a bot, which made the script not get past the human verification page.

![G2 human verification page](https://static.zenrows.com/content/g2_human_verification_85a5e7d957.jpg)

And our scraper fails when the timeout is reached.

![Timeout Reached](https://static.zenrows.com/content/timeout_reached_a9aca94e54.png)

So, a better way to get around this is to use Zenrows.

Here's what you need to do.

Start by installing `requests`:

```nginx
pip install requests
```

Then, implement the following script (the code is auto-generated by Zenrows on its app home when activating the premium proxy, anti-bot and JS rendering features):

<!-- scraper.py -->
```python
import requests

apikey = '<YOUR_ZENROWS_API_KEY>'
zenrows_base_url = 'https://api.zenrows.com/v1/'
target_url = 'https://www.g2.com/products/asana/reviews'

params = {
    'url': url,
    'apikey': apikey,
	'js_render': 'true',
	'premium_proxy': 'true',
}

response = requests.get(zenrows_base_url, params=params)

print(response.text) # G2 home page HTML
```

Update `<YOUR_ZENROWS_API_KEY>` with your Zenrows API key and run the script. 

Congrats! You're able to scrape the page now:

<!-- Terminal -->
```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <link href="https://www.g2.com/images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    <title>Asana Reviews, Pros + Cons, and Top Rated Features</title>
</head>
<body>
    <!-- other content omitted for brevity -->
</body>
```

## Optimize Selenium Wire
Intercepting traffic enables you to inspect the requests and responses that your browser sends and receives. That's useful to optimize Selenium Wire, which requires balancing [traffic interception](/blog/web-scraping-intercepting-xhr-requests) and browser profile configuration.

Earlier, we intercepted requests to customize headers, but we can also do it for assets (images, for example) since we're only scraping text.

Update your script like shown below to increase scraping speed to avoid making requests for images:

<!-- script.py -->
```python
# ...
# creates an instance of the chrome driver (browser)
driver = webdriver.Chrome(
    # seleniumwire options
    seleniumwire_options={},
)

def request_interceptor(request):
    # block image assets
    if request.path.endswith(('.png', '.jpg', '.gif')):
        request.abort()

driver.request_interceptor = request_interceptor

# hit target site
driver.get('https://www.scrapingcourse.com/ecommerce/')

body = driver.find_element(By.TAG_NAME, 'body')

print(body.text)

# ...
```

## Conclusion
In this tutorial, we covered the fundamentals of working with Selenium Wire. Now, you know:

-   How to perform requests with Selenium Wire.
-   How to use premium proxy and its benefits.
-   How to customize headers in Selenium Wire.
-   How to integrate Undetected ChromeDriver and a better alternative.
-   How to optimize Selenium Wire.

You can visit the [official documentation](https://github.com/wkeeling/selenium-wire#selenium-wire) to learn more about it.

Although the library helps intercept and modify network requests and responses, as well as simulate different scenarios, it doesn't work well on sites with advanced bot detection and [WAFs](/blog/waf-bypass) like [DataDome](/blog/datadome-bypass) and [PerimeterX](/blog/perimeterx-bypass). A more trustworthy Selenium Wire alternative is Zenrows. [Sign up](/){:data-popup=true} for a free trial today!

## FAQ

### What Is The Difference between Selenium and Selenium Wire?

The difference between Selenium and Selenium Wire is that base Selenium is a tool for automating web browsers, while Selenium Wire is a Python library that extends the headless browser functionality. It allows the interception and manipulation of network traffic.
