Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Revision 1083558 of Modify a web page

  • Revision slug: Mozilla/Add-ons/WebExtensions/Modify_a_web_page
  • Revision title: Modify a web page
  • Revision id: 1083558
  • Created:
  • Creator: wbamberg
  • Is current revision? No
  • Comment

Revision Content

{{AddonSidebar}}

One of the most common use cases for a browser add-on is to modify a web page. For example, an add-on might want to change the style applied to a page, hide particular DOM nodes, or inject extra DOM nodes into the page.

There are two ways to do this with WebExtensions:

  • declaratively: define a pattern than matches a set of URLs, and ask the browser to load a set of scripts into pages whose URL matches that pattern
  • programmatically: using a JavaScript API, load a script into the page hosted by a particular tab.

Either way, these scripts are called content scripts, and are different from the other scripts that make up a WebExtension:

  • they only get access to a small subset of the WebExtension APIs
  • they get direct access to the web page in which they are loaded
  • they communicate with the rest of the WebExtension using a messaging API.

In this article we'll look at both methods of loading a script.

Modifying pages that match a URL pattern

Create a new directory called "modify-page". In that directory, create a file called "manifest.json" which has the following contents:

{

  "manifest_version": 2,
  "name": "modify-page",
  "version": "1.0",

  "content_scripts": [
    {
      "matches": ["https://addons.mozilla.org/*"],
      "js": ["page-eater.js"]
    }
  ]

}

The content_scripts key is how you load scripts into pages that match URL patterns. In this case, content_scripts instructs the browser to load a script called "page-eater.js" into all pages under https://addons.mozilla.org/.

Next, create a file called "page-eater.js" with the following contents:

document.body.textContent = "";

var header = document.createElement('h1');
header.textContent = "This page has been eaten";
document.body.appendChild(header);

Now install the WebExtension, and visit https://addons.mozilla.org/:

{{EmbedYouTube("lxf2Tkg6U1M")}}

Modifying pages programmatically

What if you still want to eat pages, but only when the user asks you to? Let's update this example so we inject the content script when the user clicks a context menu item.

First, update "manifest.json" so it has the following contents:

{

  "manifest_version": 2,
  "name": "modify-page",
  "version": "1.0",

  "permissions": [
    "activeTab",
    "contextMenus"
  ],

  "background": {
    "scripts": ["background.js"]
  }

}

Here, we've removed the content_scripts key, and added two new keys:

  • permissions: to inject scripts into pages we need permissions for the page we're modifying. The activeTab permission is a way to get this temporarily for the currently active tab. We also need the contextMenus permission to add context menu items.
  • background: we're using this to load a persistent "background script" called "background.js", in which we'll set up the context menu and inject the content script.

Next, create "background.js", and give it the following contents:

chrome.contextMenus.create({
  id: "eat-page",
  title: "Eat this page"
});

chrome.contextMenus.onClicked.addListener(function(info, tab) {
  if (info.menuItemId == "eat-page") {
    chrome.tabs.executeScript({
      file: "page-eater.js"
    });
  }
});

In this script we're creating a context menu item. When the user clicks it, we're injecting "page-eater.js" using the tabs.executeScript() API. This API optionally takes a tab ID as an argument: we've omitted the tab ID, which means that the script is injected into the currently active tab.

At this point the add-on should look like this:

modify-page/
    background.js
    manifest.json
    page-eater.js

Now reload the WebExtension, open a page (any page, this time) activate the context menu, and select "Eat this page":

{{EmbedYouTube("zX4Bcv8VctA")}}

Messaging

Content scripts and background scripts can't directly access each other's state. However, they can communicate by sending messages. One end sets up a message listener, and the other end can then send it a message. The following table summarises the APIs involved on each side:

  In content script In background script
Send a message chrome.runtime.sendMessage() chrome.tabs.sendMessage()
Receive a message chrome.runtime.onMessage chrome.runtime.onMessage

Let's update our example to show how to send a message from the background script.

First, edit "background.js" so it has these contents:

chrome.contextMenus.create({
  id: "eat-page",
  title: "Eat this page"
});

chrome.contextMenus.onClicked.addListener(function(info, tab) {
  if (info.menuItemId == "eat-page") {
    chrome.tabs.executeScript({
      file: "page-eater.js"
    });
    
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
      chrome.tabs.sendMessage(tabs[0].id, {
        replacement: "Message from the add-on!"
      });
    });
  }
});

All we've done here is: after injecting "page-eater.js", use tabs.query() to get the currently active tab, and then use tabs.sendMessage() to send a message to the content scripts loaded into that tab. The message has the payload {replacement: "Message from the add-on!"}.

Next, update "page-eater.js" like this:

function eatPage(request, sender, sendResponse) {
  document.body.textContent = "";

  var header = document.createElement('h1');
  header.textContent = request.replacement;
  document.body.appendChild(header);
}

chrome.runtime.onMessage.addListener(eatPage);

Now instead of just eating the page right away, the content script listens for a message using runtime.onMessage. When a message arrives, the content script runs essentially the same code as before, except that the replacement text is taken from request.replacement.

If we wanted to send messages back from the content script to the background page, the setup would be the same, except we would use runtime.sendMessage() in the content script.

Modifying styles

These examples all insert JavaScript, but you can load CSS as well. You can specify CSS in the content_scripts key, and can inject CSS programmatically using the tabs.insertCSS() function.

Learn more

 

Revision Source

<div>{{AddonSidebar}}
<p>One of the most common use cases for a browser add-on is to modify a web page. For example, an add-on might want to change the style applied to a page, hide particular DOM nodes, or inject extra DOM nodes into the page.</p>

<p>There are two ways to do this with WebExtensions:</p>

<ul>
 <li>declaratively: define a pattern than matches a set of URLs, and ask the browser to load a set of scripts into pages whose URL matches that pattern</li>
 <li>programmatically: using a JavaScript API, load a script into the page hosted by a particular tab.</li>
</ul>

<p>Either way, these scripts are called <em>content scripts</em>, and are different from the other scripts that make up a WebExtension:</p>

<ul>
 <li>they only get access to a small subset of the WebExtension APIs</li>
 <li>they get direct access to the web page in which they are loaded</li>
 <li>they communicate with the rest of the WebExtension using a messaging API.</li>
</ul>

<p>In this article we'll look at both methods of loading a script.</p>

<h2 id="Modifying_pages_that_match_a_URL_pattern">Modifying pages that match a URL pattern</h2>

<p>Create a new directory called "modify-page". In that directory, create a file called "manifest.json" which has the following contents:</p>

<pre class="brush: json">
{

  "manifest_version": 2,
  "name": "modify-page",
  "version": "1.0",

  "content_scripts": [
    {
      "matches": ["https://addons.mozilla.org/*"],
      "js": ["page-eater.js"]
    }
  ]

}</pre>

<p>The <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts">content_scripts</a></code> key is how you load scripts into pages that match URL patterns. In this case, <code>content_scripts</code> instructs the browser to load a script called "page-eater.js" into all pages under <a href="https://addons.mozilla.org/">https://addons.mozilla.org/</a>.</p>

<p>Next, create a file called "page-eater.js" with the following contents:</p>

<pre class="brush: js">
document.body.textContent = "";

var header = document.createElement('h1');
header.textContent = "This page has been eaten";
document.body.appendChild(header);</pre>

<p>Now <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox">install the WebExtension</a>, and visit <a href="https://addons.mozilla.org/">https://addons.mozilla.org/</a>:</p>

<p>{{EmbedYouTube("lxf2Tkg6U1M")}}</p>

<h2 id="Modifying_pages_programmatically">Modifying pages programmatically</h2>

<p>What if you still want to eat pages, but only when the user asks you to? Let's update this example so we inject the content script when the user clicks a context menu item.</p>

<p>First, update "manifest.json" so it has the following contents:</p>

<pre class="brush: json">
{

  "manifest_version": 2,
  "name": "modify-page",
  "version": "1.0",

  "permissions": [
    "activeTab",
    "contextMenus"
  ],

  "background": {
    "scripts": ["background.js"]
  }

}</pre>

<p>Here, we've removed the <code>content_scripts</code> key, and added two new keys:</p>

<ul>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions">permissions</a></code>: to inject scripts into pages we need permissions for the page we're modifying. The <a href="/en-US/Add-ons/WebExtensions/manifest.json/permissions#activeTab_permission"><code>activeTab</code> permission</a> is a way to get this temporarily for the currently active tab. We also need the <code>contextMenus</code> permission to add context menu items.</li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/background">background</a></code>: we're using this to load a persistent <a href="/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Background_scripts">"background script"</a> called "background.js", in which we'll set up the context menu and inject the content script.</li>
</ul>

<p>Next, create "background.js", and give it the following contents:</p>

<pre class="brush: js">
chrome.contextMenus.create({
  id: "eat-page",
  title: "Eat this page"
});

chrome.contextMenus.onClicked.addListener(function(info, tab) {
  if (info.menuItemId == "eat-page") {
    chrome.tabs.executeScript({
      file: "page-eater.js"
    });
  }
});
</pre>

<p>In this script we're creating a <a href="/en-US/Add-ons/WebExtensions/API/ContextMenus/create">context menu item</a>. When the user clicks it, we're injecting "page-eater.js" using the <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript">tabs.executeScript()</a></code> API. This API optionally takes a tab ID as an argument: we've omitted the tab ID, which means that the script is injected into the currently active tab.</p>

<p>At this point the add-on should look like this:</p>

<pre class="line-numbers  language-html">
<code class="language-html">modify-page/
    background.js
    manifest.json
    page-eater.js</code></pre>

<p>Now <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox#Reloading_a_temporary_add-on">reload the WebExtension</a>, open a page (any page, this time) activate the context menu, and select "Eat this page":</p>

<p>{{EmbedYouTube("zX4Bcv8VctA")}}</p>

<h2>Messaging</h2>

<p>Content scripts and background scripts can't directly access each other's state. However, they can communicate by sending messages. One end sets up a message listener, and the other end can then send it a message. The following table summarises the APIs involved on each side:</p>

<table class=" fullwidth-table standard-table">
 <thead>
  <tr>
   <th scope="row">&nbsp;</th>
   <th scope="col">In content script</th>
   <th scope="col">In background script</th>
  </tr>
  <tr>
   <th scope="row">Send a message</th>
   <td><code><a href="/en-US/Add-ons/WebExtensions/API/runtime#sendMessage()">chrome.runtime.sendMessage()</a></code></td>
   <td><code><a href="/en-US/Add-ons/WebExtensions/API/Tabs/sendMessage">chrome.tabs.sendMessage()</a></code></td>
  </tr>
  <tr>
   <th scope="row">Receive a message</th>
   <td><code><a href="/en-US/Add-ons/WebExtensions/API/runtime/onMessage">chrome.runtime.onMessage</a></code></td>
   <td><code><a href="/en-US/Add-ons/WebExtensions/API/runtime#onMessage">chrome.runtime.onMessage</a></code></td>
  </tr>
 </thead>
</table>

<p>Let's update our example to show how to send a message from the background script.</p>

<p>First, edit "background.js" so it has these contents:</p>

<pre class="brush: js">
chrome.contextMenus.create({
  id: "eat-page",
  title: "Eat this page"
});

chrome.contextMenus.onClicked.addListener(function(info, tab) {
  if (info.menuItemId == "eat-page") {
    chrome.tabs.executeScript({
      file: "page-eater.js"
    });
    
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
      chrome.tabs.sendMessage(tabs[0].id, {
        replacement: "Message from the add-on!"
      });
    });
  }
});</pre>

<p>All we've done here is: after injecting "page-eater.js", use <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/query">tabs.query()</a></code> to get the currently active tab, and then use <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/sendMessage">tabs.sendMessage()</a></code> to send a message to the content scripts loaded into that tab. The message has the payload <code>{replacement: "Message from the add-on!"}</code>.</p>

<p>Next, update "page-eater.js" like this:</p>

<pre class="brush: js">
function eatPage(request, sender, sendResponse) {
  document.body.textContent = "";

  var header = document.createElement('h1');
  header.textContent = request.replacement;
  document.body.appendChild(header);
}

chrome.runtime.onMessage.addListener(eatPage);</pre>

<p>Now instead of just eating the page right away, the content script listens for a message using <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage">runtime.onMessage</a></code>. When a message arrives, the content script runs essentially the same code as before, except that the replacement text is taken from <code>request.replacement</code>.</p>

<p>If we wanted to send messages back from the content script to the background page, the setup would be the same, except we would use <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage">runtime.sendMessage()</a></code> in the content script.</p>

<h2>Modifying styles</h2>

<p>These examples all insert JavaScript, but you can load CSS as well. You can specify CSS in the <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts">content_scripts</a></code> key, and can inject CSS programmatically using the <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/insertCSS">tabs.insertCSS()</a></code> function.</p>

<h2>Learn more</h2>

<ul>
 <li><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts">Content scripts</a> guide</li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts">content_scripts</a></code> manifest key</li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions">permissions</a></code> manifest key</li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript">tabs.executeScript()</a></code></li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/insertCSS">tabs.insertCSS()</a></code></li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/sendMessage">tabs.sendMessage()</a></code></li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage">runtime.sendMessage()</a></code></li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage">runtime.onMessage</a></code></li>
 <li>Examples using <code>content_scripts</code>:
  <ul>
   <li><a href="https://github.com/mdn/webextensions-examples/tree/master/borderify">borderify</a></li>
   <li><a href="https://github.com/mdn/webextensions-examples/tree/master/inpage-toolbar-ui">inpage-toolbar-ui</a></li>
   <li><a href="https://github.com/mdn/webextensions-examples/tree/master/notify-link-clicks-i18n">notify-link-clicks-i18n</a></li>
   <li><a href="https://github.com/mdn/webextensions-examples/tree/master/page-to-extension-messaging">page-to-extension-messaging</a></li>
  </ul>
 </li>
 <li>Examples using <code>tabs.executeScript()</code>:
  <ul>
   <li><a class="external external-icon" href="https://github.com/mdn/webextensions-examples/tree/master/beastify">beastify</a></li>
   <li><a class="external external-icon" href="https://github.com/mdn/webextensions-examples/tree/master/context-menu-demo">context-menu-demo</a></li>
  </ul>
 </li>
</ul>

<p>&nbsp;</p>
</div>
Revert to this revision