Event Pages

A common need for apps and extensions is to have a single long-running script to manage some task or state. Event pages to the rescue. Event pages are loaded only when they are needed. When the event page is not actively doing something, it is unloaded, freeing memory and other system resources.

{{?is_apps}}

Chrome Apps always use event pages instead of background pages. It is not possible for a Chrome App to have a persistent background page.

{{/is_apps}}

Event pages are available in the stable channel as of Chrome 22, and the performance advantages are significant, especially on low-power devices. Please prefer them to persistent background pages whenever possible for new development and begin migrating existing background pages to this new model.

Manifest

Register your event page in the extension manifest:

{{^is_apps}}
{
  "name": "My extension",
  ...
  "background": {
    "scripts": ["eventPage.js"],
    "persistent": false
  },
  ...
}

Notice that without the "persistent" key, you have a regular background page. Persistence is what differentiates an event page from a background page.

{{/is_apps}} {{?is_apps}}
{
  "name": "My app",
  ...
  "app": {
    "background": {
      "scripts": ["eventPage.js"]
    }
  }
  ...
}
{{/is_apps}}

Lifetime

The event page is loaded when it is "needed", and unloaded when it goes idle again. Here are some examples of things that will cause the event page to load:

Once it has been loaded, the event page will stay running as long as it is active (for example, calling an extension API or issuing a network request). Additionally, the event page will not unload until all visible views (for example, popup windows) are closed and all message ports are closed. Note that opening a view does not cause the event page to load, but only prevents it from closing once loaded.

Make sure your event page closes as soon as the event that opened it is processed. You can observe the lifetime of your event page by opening Chrome's task manager. You can see when your event page loads and unloads by observing when an entry for your extension appears in the list of processes.

Once the event page has been idle a short time (a few seconds), the $(ref:runtime.onSuspend) event is dispatched. The event page has a few more seconds to handle this event before it is forcibly unloaded. If during this time an event occurs which would normally cause the event page to be loaded, the suspend is canceled and the $(ref:runtime.onSuspendCanceled) event is dispatched.

Event registration

Chrome keeps track of events that an app or extension has added listeners for. When it dispatches such an event, the event page is loaded. Conversely, if the app or extension removes all of its listeners for an event by calling removeListener, Chrome will no longer load its event page for that event.

Because the listeners themselves only exist in the context of the event page, you must use addListener each time the event page loads; only doing so at $(ref:runtime.onInstalled) by itself is insufficient.

For an example of event registration in action, you can view the Google Mail Checker extension.

{{^is_apps}}

Convert background page to event page

Follow this checklist to convert your extension's (persistent) background page to an event page.

  1. Add "persistent": false to your manifest as shown above.
  2. If your extension uses window.setTimeout() or window.setInterval(), switch to using the alarms API instead. DOM-based timers won't be honored if the event page shuts down.
  3. Similarly, other asynchronous HTML5 APIs like notifications and geolocation will not complete if the event page shuts down. Instead, use equivalent extension APIs, like notifications.
  4. If your extension uses, $(ref:extension.getBackgroundPage), switch to $(ref:runtime.getBackgroundPage) instead. The newer method is asynchronous so that it can start the event page if necessary before returning it.

{{/is_apps}}

Best practices when using event pages

Keep these tips in mind when using event pages to avoid common subtle pitfalls.

  1. Register to receive any events your extension is interested in each time the event page is loaded. The event page will be loaded once for each new version of your extension. After that it will only be loaded to deliver events you have registered for. This generally means that your event listeners should be added at the top level scope of the event page, otherwise they may not be available when the event page reloads.
  2. If you need to do some initialization when your extension is installed or upgraded, listen to the $(ref:runtime.onInstalled) event. This is a good place to register for declarativeWebRequest rules, contextMenu entries, and other such one-time initialization.
  3. If you need to keep runtime state in memory throughout a browser session, use the storage API or IndexedDB. Since the event page does not stay loaded for long, you can no longer rely on global variables for runtime state. {{^is_apps}}
  4. Use event filters to restrict your event notifications to the cases you care about. For example, if you listen to the tabs.onUpdated event, try using the $(ref:webNavigation.onCompleted) event with filters instead (the tabs API does not support filters). That way, your event page will only be loaded for events that interest you. {{/is_apps}}
  5. Listen to the $(ref:runtime.onSuspend) event if you need to do last second cleanup before your event page is shut down. However, we recommend persisting periodically instead. That way if your extension crashes without receiving onSuspend, no data will typically be lost.
  6. If you're using message passing, be sure to close unused message ports. The event page will not shut down until all message ports are closed.
  7. If you're using the context menus API, pass a string id parameter to $(ref:contextMenus.create), and use the $(ref:contextMenus.onClicked) callback instead of an onclick parameter to $(ref:contextMenus.create).
  8. Remember to test that your event page works properly when it is unloaded and then reloaded, which only happens after several seconds of inactivity. Common mistakes include doing unnecessary work at page load time (when it should only be done when the extension is installed); setting an alarm at page load time (which resets any previous alarm); or not adding event listeners at page load time.