 <p>Try using a content script, injected into the web page, instead of a background script. Use this in your manifest.json:</p> <pre><code>"content_scripts" : [{ "js" : ["myScript.js"] }] "permissions": [ "tabs", "http://*/*", "https://*/*" ] </code></pre> <p>However, chrome extensions are sandboxed from other scripts in the page. However, you do have access to the DOM and you can inject your own tags. So, create a new <code>&lt;script&gt;</code> tag and append it to the DOM, and the new script (script.js) it references can include the event listeners you want.</p> <p>background.js:</p> <pre><code>chrome.runtime.onConnect.addListener(function(port) { port.onMessage.addListener(function(msg) { enableEXT = msg.enableEXT; }); }); chrome.webRequest.onHeadersReceived.addListener(function(details) { for (var i = 0; i &lt; details.responseHeaders.length; ++i) { if (details.responseHeaders[i].name.toLowerCase() == 'content-type' &amp;&amp; !enableEXT) details.responseHeaders[i].value = 'application/xyz'; } return {responseHeaders: details.responseHeaders}; }, {urls: ["&lt;all_urls&gt;"]}, ['blocking', 'responseHeaders']); </code></pre> <p>myScript.js:</p> <pre><code>//to inject into the page var s = document.createElement('script'); s.src = chrome.extension.getURL("script.js"); s.onload = function() { this.parentNode.removeChild(this); }; (document.head||document.documentElement).appendChild(s); //to communicate with our background var port = chrome.runtime.connect(); window.addEventListener("message", function(event) { // We only accept messages from ourselves if (event.source != window) return; if (event.data.type &amp;&amp; (event.data.type == "FROM_PAGE")) { port.postMessage(event.data); } }, false); </code></pre> <p>script.js:</p> <pre><code>window.onkeydown = function() { if (event.keyCode == 70) window.postMessage({ enableEXT: true, "*"); }; window.onkeyup = function() { window.postMessage({ enableEXT: false, "*"); }; </code></pre> <p>To communicate between your injected code, your content script, and your background page is a very awkward situation, but can be dealt with, with all the postMessage APIs...</p>