11

So i'd like to run a script when the tab reloads in a specified URL. It almost works, but actually id doesn't :) This is my manifest file:

{
"manifest_version": 2,

"name": "Sample Extension",
"description": "Sample Chrome Extension",
"version": "1.0",

"content_scripts":
[
    {
      "matches": ["http://translate.google.hu/*"],
      "js": ["run.js"]
    }
],

"permissions":
[
    "activeTab",
    "tabs"
],

"browser_action":
{
    "default_title": "Sample",
    "default_icon": "icon.png"
}
}

and this is run.js:

chrome.tabs.onUpdated.addListener(
function ( tabId, changeInfo, tab )
{
    if ( changeInfo.status === "complete" )
    {
        chrome.tabs.executeScript( null, {file: "program.js"} );
    }
}
);

The programs.js just alerts some text (yet). When I put an alert to the first line of the run.js, it alerts, but when I put it in the if, it doesn't. I can't find the problem. Did I type something wrong?

András Geiszl
  • 966
  • 2
  • 16
  • 36
  • Did you check for errors in the dev console? I think you need to run this from a background page rather than the content script. I believe content scripts can only utilise chrome.extension and all other methods in the api need to be invoked on a background.js page. – QFDev Jun 05 '13 at 21:45
  • Hooking https://stackoverflow.com/q/23333771/632951 – Pacerier Aug 10 '17 at 06:13

3 Answers3

17

Assuming that http://translate.google.hu/* pages are the ones you wish to inject code into on reload, you would have to go about it in a slightly different way. Currently you are always injecting code into those pages (without the permission to do so, no less) and then trying to use the chrome.tabs api inside that content script, which you can't do. Instead, we will put the listener in a background page and inject the code only on a page refresh, like you want. First the manifest:

{
  "manifest_version": 2,
  "name": "Sample Extension",
  "description": "Sample Chrome Extension",
  "version": "1.0",
  "background": {
    "scripts": ["background.js"]
  },
  "permissions":[
    "http://translate.google.hu/*", "tabs"
  ]
}

background.js

chrome.tabs.onUpdated.addListener(function(tabId,changeInfo,tab){
  if (tab.url.indexOf("http://translate.google.hu/") > -1 && 
      changeInfo.url === undefined){
    chrome.tabs.executeScript(tabId, {file: "program.js"} );
  }
});

This will listen for the onUpdated event, checks if it is one of the url's that we want to inject into, and then it checks if the page was reloaded. That last step is accomplished by checking if changeInfo.url exists. If it does, then that means that the url was changed and thus not a refresh. Conversely, if it doesn't exist, then the page must have only been refreshed.

BeardFist
  • 8,031
  • 3
  • 35
  • 40
  • 1
    Thanks, that works, but how can I run this script if there is another tab on top? – András Geiszl Jun 07 '13 at 19:59
  • @Geiszla What do you mean by another tab on top? – BeardFist Jun 07 '13 at 20:43
  • 1
    So when I reload the tab, but change tab. Then the script don't run, because that is not that (e.g. translate.google.hu) website. – András Geiszl Jun 07 '13 at 21:25
  • Great! I wrote the same function for other things for my extension, but I did not know onUpdate callback arguments. Thanks, this helped me a lot +1 – Mohammad Kermani Apr 25 '17 at 19:16
  • 2
    @BeardFist, Are you sure this works as expected? Wouldn't this fire even for [`changeInfo.status` and etc etc](https://developer.chrome.com/extensions/tabs#event-onUpdated)? – Pacerier Aug 10 '17 at 06:04
  • I agree with @Pacerier. I'm not sure that "changeInfo.url === undefined" works as expected. It will be trigger with any change on the actual tab and not only when the tab is refreshed. – Lowtrux Aug 11 '20 at 09:00
10

2021

If you want to detect reload from background.js in manifest 3 (maybe also 2), chrome.tabs.onUpdated approach didn't work for me :/ It was invoked too many times.

That what worked for me in the end!

// --- On Reloading or Entering example.com --- 
chrome.webNavigation.onCommitted.addListener((details) => {
    if (["reload", "link", "typed", "generated"].includes(details.transitionType) &&
        details.url === "http://example.com/") {

        codeAfterReload();

        // If you want to run only when the reload finished (at least the DOM was loaded)
        chrome.webNavigation.onCompleted.addListener(function onComplete() {

            codeAfterReloadAndFinishSomeLoading();

            chrome.webNavigation.onCompleted.removeListener(onComplete);
        });
    }
});

For more transition types: https://developer.chrome.com/docs/extensions/reference/history/#transition_types

good luck :)

Yam Shargil
  • 445
  • 5
  • 9
  • 2
    Keep in mind that these APIs require the `webNavigation` permission with shows the "This extension can see all your browsing" message – fregante Jul 19 '21 at 12:42
  • There's additional info in the second parameter of the callback: `changeInfo`. When loading the `changeInfo.status == "loading` and when loaded it is `"complete"`. By checking `changeInfo.status` you can make sure it runs once. – kuzdogan Apr 07 '22 at 11:44
4

content_scripts are run at every page (re)load, so it's best to just use those to detect it.

This way you also don't risk running any code in the background before your content_script is ready to receive any message.

fregante
  • 29,050
  • 14
  • 119
  • 159
  • There seems to be a Chrome bug whereby sometimes manifest contentscript doesn't run on page load. See https://stackoverflow.com/questions/19191679/chrome-extension-inject-js-before-page-load/19192010#comment78166411_19192010 – Pacerier Aug 10 '17 at 06:06