Addon for Playwright for intercepting and modifying HTTP requests and responses.
- Request modification before sending to the server
- Server response modification before passing to the browser
- Request filtering by URL, method, and content type
- Support for synchronous and asynchronous modification functions
- Processing requests with multiple handlers
- Obtaining information about intercepted requests
- Type safety with beartype
- Direct access to request and response properties
pip install playwright_interceptorfrom playwright.async_api import async_playwright
from playwright_interceptor import NetworkInterceptor, Handler, Execute, Request, Response
import asyncio
async def main():
async with async_playwright() as pw:
browser = await pw.firefox.launch()
page = await browser.new_page()
interceptor = NetworkInterceptor(page)
# Intercepting and modifying requests and responses
handler = Handler.ALL(execute=Execute.ALL(
request_modify=modify_request,
response_modify=modify_response,
max_modifications=5,
max_responses=2
))
# Starting interception
results, _ = await asyncio.gather(
interceptor.execute([handler]),
page.goto("https://httpbin.org/get")
)
print(f"Results: {results}")
await browser.close()
def modify_request(request: Request) -> Request:
"""Modifies request before sending"""
request.headers["X-Custom-Header"] = "ModifiedByInterceptor"
request.params["intercepted"] = "true"
return request
def modify_response(response: Response) -> Response:
"""Modifies response after receiving"""
response.response_headers["X-Response-Modified"] = "true"
# Parsing and modifying JSON
parsed_content = response.content_parse()
if isinstance(parsed_content, dict):
parsed_content["_intercepted"] = True
# Updating content
import json
response.content = json.dumps(parsed_content).encode('utf-8')
return response
if __name__ == "__main__":
asyncio.run(main())Class for intercepting HTTP traffic:
from playwright_interceptor import NetworkInterceptor
interceptor = NetworkInterceptor(page, logger=custom_logger)
results = await interceptor.execute(handlers, timeout=10.0)Parameters:
page- Playwright pagelogger- Optional logger
Methods:
execute(handlers, timeout=10.0)- Start interception with specified handlers
Rules for capturing and processing requests:
from playwright_interceptor import Handler, Execute, ExpectedContentType, HttpMethod
handler_all = Handler.ALL(
expected_content=ExpectedContentType.JSON,
startswith_url="https://api.example.com",
method=HttpMethod.GET,
execute=Execute.RETURN(max_responses=3)
)
handler_modify = Handler.ALL(
expected_content=ExpectedContentType.ANY,
execute=Execute.MODIFY(
request_modify=my_request_modifier,
response_modify=my_response_modifier,
max_modifications=5
)
)
handler_combined = Handler.ALL(
slug="my_handler",
expected_content=ExpectedContentType.JSON,
startswith_url="https://api.example.com",
method=HttpMethod.POST,
execute=Execute.ALL(
request_modify=my_request_modifier,
response_modify=my_response_modifier,
max_modifications=3,
max_responses=2
)
)Parameters:
expected_content- Expected content typestartswith_url- Filter by URL beginningmethod- HTTP method for filteringexecute- Execution configurationslug- Handler identifier
Factory methods:
Handler.ALL()- Universal handler for all types of requestsHandler.MAIN()- Handler for main page requestsHandler.SIDE()- Handler for side resource requestsHandler.NONE()- Empty handler
Handler behavior configuration:
from playwright_interceptor import Execute
execute_return = Execute.RETURN(max_responses=5)
execute_modify = Execute.MODIFY(
request_modify=modify_request,
max_modifications=3
)
execute_all = Execute.ALL(
request_modify=modify_request,
response_modify=modify_response,
max_modifications=5,
max_responses=3
)Modes:
RETURN- Request interceptionMODIFY- Request/response modificationALL- Combination of interception and modification
Parameters:
request_modify- Request modification functionresponse_modify- Response modification functionmax_modifications- Maximum number of modificationsmax_responses- Maximum number of intercepted responses
HTTP request representation:
from playwright_interceptor import Request, HttpMethod
request = Request(
url="https://api.example.com/users",
headers={"Authorization": "Bearer token"},
params={"page": "1", "limit": "10"},
body={"name": "John"},
method=HttpMethod.POST
)
# Modification (direct field access)
request.headers["X-Custom"] = "value"
request.params["filter"] = "active"
request.method = HttpMethod.PUT
request.body = {"updated": "data"}
# URL with parameters
final_url = request.real_urlProperties:
url- Base URLreal_url- URL with parameters (read-only property)base_url- URL without parameters (read-only property)headers- Headers dictionaryparams- Request parameters dictionarybody- Request bodymethod- HTTP method
HTTP response representation:
from playwright_interceptor import Response
def modify_response(response: Response) -> Response:
response.response_headers["X-Modified"] = "true"
parsed_content = response.content_parse()
if isinstance(parsed_content, dict):
parsed_content["_intercepted"] = True
import json
response.content = json.dumps(parsed_content).encode('utf-8')
return responseProperties:
status- HTTP status codeurl- Request URLrequest_headers- Request headersresponse_headers- Response headerscontent- Response content (bytes)duration- Request execution time
Methods:
content_parse()- Parse content into objects
from playwright_interceptor import ExpectedContentType, HttpMethod
# Content types
ExpectedContentType.JSON # application/json
ExpectedContentType.JS # application/javascript
ExpectedContentType.CSS # text/css
ExpectedContentType.IMAGE # image/*
ExpectedContentType.VIDEO # video/*
ExpectedContentType.AUDIO # audio/*
ExpectedContentType.FONT # font/*
ExpectedContentType.APPLICATION # application/*
ExpectedContentType.ARCHIVE # archive formats
ExpectedContentType.TEXT # text/*
ExpectedContentType.ANY # any type
# HTTP methods
HttpMethod.GET
HttpMethod.POST
HttpMethod.PUT
HttpMethod.DELETE
HttpMethod.PATCH
HttpMethod.HEAD
HttpMethod.OPTIONS
HttpMethod.ANYdef add_auth(request: Request) -> Request:
if "/api/" in request.url:
request.headers["Authorization"] = "Bearer your-token"
return request
handler = Handler.ALL(
startswith_url="https://api.example.com",
execute=Execute.MODIFY(request_modify=add_auth, max_modifications=10)
)from datetime import datetime
async def add_analytics(response: Response) -> Response:
parsed_content = response.content_parse()
if isinstance(parsed_content, dict):
parsed_content["_analytics"] = {
"intercepted_at": datetime.now().isoformat(),
"response_time_ms": response.duration * 1000,
"status_code": response.status
}
import json
response.content = json.dumps(parsed_content).encode('utf-8')
return response
handler = Handler.ALL(
expected_content=ExpectedContentType.JSON,
execute=Execute.ALL(
response_modify=add_analytics,
max_modifications=5,
max_responses=3
)
)async def run_multiple_handlers():
request_handler = Handler.ALL(
slug="request_modifier",
execute=Execute.MODIFY(
request_modify=add_tracking,
max_modifications=10
)
)
response_handler = Handler.ALL(
slug="response_modifier",
expected_content=ExpectedContentType.JSON,
execute=Execute.MODIFY(
response_modify=add_metadata,
max_modifications=10
)
)
collector_handler = Handler.ALL(
slug="data_collector",
startswith_url="https://api.example.com",
execute=Execute.ALL(
response_modify=collect_data,
max_modifications=5,
max_responses=5
)
)
results = await interceptor.execute([
request_handler,
response_handler,
collector_handler
])async def async_request_modifier(request: Request) -> Request:
await asyncio.sleep(0.01)
request.headers["X-Async-Modified"] = "true"
return request
async def async_response_modifier(response: Response) -> Response:
parsed_content = response.content_parse()
if isinstance(parsed_content, dict):
parsed_content["_processed_async"] = True
import json
response.content = json.dumps(parsed_content).encode('utf-8')
return responsedef safe_modifier(response: Response) -> Response:
try:
parsed_content = response.content_parse()
if isinstance(parsed_content, dict):
parsed_content["_modified"] = True
import json
response.content = json.dumps(parsed_content).encode('utf-8')
return response
except Exception as e:
print(f"Modification error: {e}")
return response- When using multiple handlers, modifications are applied sequentially
- For
MODIFYandALLmodes, at least one of the modifiers is required - With multiple handlers, unique
slugvalues are required - Avoid heavy operations in modifiers
MIT License