Arash Taher

Content Scripts Not Loading for JSON Pages in Firefox

Ran into a weird issue where my content script wasn’t loading for a page in Firefox (Manifest V2). Worked fine in Chrome (Manifest V3). Turns out, Firefox only injects content scripts into HTML pages, not JSON responses (Content-Type: application/json). Makes sense—content scripts need a DOM, and JSON doesn’t have one.

I didn’t find this problem to be mentioned anywhere else, so here’s a quick blog post to explain it.

I was trying to grab a JSON token from http://localhost:8000/extension/auth and send it back to my extension. Chrome handled it, but Firefox just wouldn’t run the script.

Fix: Swap JSON for HTML

Instead of a raw JSON response, I made the server return an HTML page with the response now in a hidden form field.

Here’s the initial version of the content.js file:

const response = document.body.textContent;
try {
  const data = JSON.parse(response);
  if (data.token) {
    // Send the token back to the options page
    chrome.runtime.sendMessage({
      type: "TOKEN",
      token: data.token,
    });
  } else if (data.errorCode) {
    console.error("Error from auth response:", data);
  }
} catch (e) {
  console.error("Failed to parse response:", e);
}

And now, instead I serve HTML and get the token from the hidden field in form:

(function() {
  // Try to find the token immediately
  let tokenField = document.getElementById('token');
  
  // If not found, set up a small delay to try again
  // (in case our script runs before the element is available)
  if (!tokenField) {
    setTimeout(function() {
      tokenField = document.getElementById('token');
      if (tokenField && tokenField.value) {
        chrome.runtime.sendMessage({
          type: "TOKEN",
          token: tokenField.value,
        });
        console.log("Token found and sent (delayed)");
      }
    }, 500);
  } else if (tokenField && tokenField.value) {
    chrome.runtime.sendMessage({
      type: "TOKEN",
      token: tokenField.value,
    });
    console.log("Token found and sent (immediate)");
  }
})();

Why It Works

The HTML response lets Firefox run the content script, and the hidden field holds the JSON. Works in Chrome too. If you can’t change the server, you could use webRequest in the background script, but this felt cleaner.

Takeaway

Firefox won’t run content scripts on JSON pages. Serve HTML instead. It’s a better solution anyway. It’s strange to serve JSON to the user!

#Browser #Javascript #Programming