Overriding languages and user agent strings seen by web pages

I am developing an extension that allows the user to set preferered languages and a user agent string for a container (contextual identity).

In MV2, I used an approach where I define a dynamic content script string which includes custom languages and a user agent string, for each container.

Question 1

With nonpersistent background pages in MV2, however, how can I register and unregister content scripts dynamically? Since variables are not saved in background pages, content script objects needed to unregister associated content scripts later, cannot be retained, I think. They are complex objects, so they do not seem to be storable in storage API.

Question 2

With MV3, dynamic content script strings do not seem to be possible. So we need to get overrides strings (languages and a user agent string) from storage, in a static content script. To get the strings, the content script needs to know the cookieStoreId (the ID of the contextual identity or container the tab resides).

The flow, I think, is the following:

  1. the content script loads at document_start.
  2. the content script asks the background script for the cookieStoreId of the tab. (asynchronously)
  3. the content script gets the overrides strings from storage, using the cookieStoreId as the key. (asynchronously)
  4. the content script sets the preferred languages and the user agent string, for the tab.

Isn’t this too late for a web page to get languages and user agent information? I suppose that a web page determines the preferred languages and the user agent string, when the script on the page starts.

I am very confused. What is the best practice for what I am trying to achieve?


Question 1

I thought, that it may be that only the scripting API is supported in nonpersistent background pages. In that case, the situation is the same as MV3.

If no other good solutions are available, I came upon the idea of having a static pre-generated content script file for each of known languages. In this setting, we cannot support very minor or new languages (think, for example, constructed languages and disappearing languages). If the user has the setting jbo,ia,eo,en-GB,en-US,en, we load jbo.js, ia.js, eo.js, en-GB.js, en-US.js, en.js in this order.

User agent strings overriding is in a bit different situation. If we set User-Agent header in onBeforeRequest handler, Firefox automatically sets navigator.userAgent so if we do not need to react to language settings changes sooner, we can keep this behavior and do not do anything special for navigator.userAgent. Our extension support navigator.uaData emulation (not in Firefox), so that is the only thing to do.

Listed only well-known and common language codes.

Even this list has the size of 865. This will broat our extension!

It turned out, that scripting API does not seem to support registering content scripts by cookieStoreId. I cannot do what I am trying to do. Help!

You could register “tabs.onCreated” listener in the background script, that one should be the first one to fire and it already has the “cookieStoreId”:

Then use the scripting API to manually execute script inside the tab.

Although, this bug may break it for you:

I would probably use MV2 here. That way I could cache the settings the persistent background script and execute script would also work for the newly created tab.

1 Like