I achieved capturing all HTTP requests and responses made by a website, by injecting a script to DOM. There are several methods of doing it depending on your needs and environment e.g. ManifestV3/V2. Here's the one I've used:
inject.js:
var s = document.createElement('script');
// must be listed in web_accessible_resources in manifest.json
s.src = chrome.runtime.getURL('injected.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
This would inject injected.js in website(s) that match "content_scripts" "matches" in manifest.json. Mention contentscript.js and inject.js in "js".
See manifest.json at the end of answer.
Now, the code in injected.js which does the actual capturing of requests and responses is inspired from How we captured AJAX requests from a website tab with a Chrome Extension. Also see the comment section in that article.
injected.js:
(function(xhr) {
var XHR = XMLHttpRequest.prototype;
var open = XHR.open;
var send = XHR.send;
var setRequestHeader = XHR.setRequestHeader;
XHR.open = function(method, url) {
this._method = method;
this._url = url;
this._requestHeaders = {};
this._startTime = (new Date()).toISOString();
return open.apply(this, arguments);
};
XHR.setRequestHeader = function(header, value) {
this._requestHeaders[header] = value;
return setRequestHeader.apply(this, arguments);
};
XHR.send = function(postData) {
this.addEventListener('load', function() {
var endTime = (new Date()).toISOString();
var myUrl = this._url ? this._url.toLowerCase() : this._url;
if(myUrl) {
if (postData) {
if (typeof postData === 'string') {
try {
// here you get the REQUEST HEADERS, in JSON format, so you can also use JSON.parse
this._requestHeaders = postData;
} catch(err) {
console.log('Request Header JSON decode failed, transfer_encoding field could be base64');
console.log(err);
}
} else if (typeof postData === 'object' || typeof postData === 'array' || typeof postData === 'number' || typeof postData === 'boolean') {
// do something if you need
}
}
// here you get the RESPONSE HEADERS
var responseHeaders = this.getAllResponseHeaders();
if ( this.responseType != 'blob' && this.responseText) {
// responseText is string or null
try {
// here you get RESPONSE TEXT (BODY), in JSON format, so you can use JSON.parse
var arr = this.responseText;
// printing url, request headers, response headers, response body, to console
console.log(this._url);
console.log(JSON.parse(this._requestHeaders));
console.log(responseHeaders);
console.log(JSON.parse(arr));
} catch(err) {
console.log("Error in responseType try catch");
console.log(err);
}
}
}
});
return send.apply(this, arguments);
};
})(XMLHttpRequest);
manifest.json:
{
"manifest_version": 3,
"name": "Extension Name",
"description": "Some Desc.",
"version": "1.1",
"content_scripts": [{
"matches": ["*://website.com/*"],
"run_at": "document_start",
"js": ["contentscript.js", "inject.js"]
}],
"web_accessible_resources": [{
"resources": ["injected.js"],
"matches": ["*://website.com/*"]
}]
}
For MV2 the last block is simply "web_accessible_resources": ["injected.js"]