This is a detailed customized chrome extension configuration cheatsheet.

Manifest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
{
// required
"manifest_version": 2, // integer indicates the version of the manifest file format.
"name": "Name of Extension",
"version": "Version of Extension", // One to four dot-separated integers indicating the version of the extension, "1.2.3.1234", and there's a field named "version_name" for displaying purpose, "version_name": "1.0 beta"

// Recommended
"default_locale": "en", // this field is required in extensions that have a '_locales' directory and must be absent in extensions that have no '_locales' directory.
"description": "Description of Extension",
"icons": {
// One or more icons that represent the extension, app, or theme.
"16": "icon16.png", // is used as the favicon for an extension's pages
"48": "icon48.png", // 48 x 48 icon is for extension management page
"128": "icon128.png" // You should always provides a 128 x 128 icon, it's used during installation and by the Chrome Extension Store.
},

// Pick one or none
"browser_action": {
// use browser actions to put icons in the main chrome toolbar, to the right of the address bar. It can have a tooltip, a badge and a popup
"default_icon": {
// optional, you can use browserAction.setBadgeText, browserAction.setBadgeBackgroundColor to set the badge
"16": "images/icon16.png",
"24": "images/icon24.png",
"32": "images/icon32.png"
},
"default_title": "Tooltip of Extension",
"default_popup": "popup.html"
},
"page_action": {
// use the chrome.pageAction API to put icons in the main chrome toolbar, to the right of the address bar. Page actions represent actions that can be taken on the current page, but that aren't applicable to all pages. Page actions appear grayed out when inactive.
"default_icons": {
// optional
"16": "images/icon16.png",
"24": "images/icon24.png",
"32": "images/icon32.png"
},
"default_title": "Tooltip of Extension", // optional
"default_popup": "popup.html"
},

// Optional
"action": "//TODO",
"author": "//TODO",
"automation": "//TODO",
"background": {
"scripts": [],
"persistent": false, // Recommended to be false
"service_worker": "path to the sw" // Optional
},
"chrome_settings_override": {
"homepage": "url of homepage",
"search_provider": {},
"startup_pages": []
},
"chrome_ui_overrides": {
"bookmarks_ui": {
"remove_bookmark_shortcut": true,
"remove_button": true
}
},
"chrome_url_overrides": {}, // used to override pages provided by chrome. In addition to HTML, an override page usually has CSS and JavaScript Code.
"commands": {},
"content_capabilities": {},
"content_scripts": [{}],
"content_security_poligy": "policyString"a,
"converted_from_user-script": "",
"devtools_page": "//TODO",
"event_rules": [],
"externally_connectable": {},
"file_browser_handlers": [],
"file_system_provider_capabilities": {
"configurable": true,
"multiple_mounts": true,
"source": "network"
},
"homepage_url": "http://path/to/homepage",
"import": [], // shared modules
"export": [], // shared modules
"incognito": "//TODO",
"input_components": "",
"key": "publicKey",
"minimum_chrome_version": "versionString",
"nacl_modules": [],
"oauth2": "",
"offline_enabled": true,
"omnibox": {
"keyboard": "aString" // The omnibox allows you to register a keyword with chrome's address bar.
},
"optional_permissions": ["tabs"],
"options_page": "options.html",
"options_ui": {
"chrome_style": true,
"page": "options.html"
},
"permissions": ["tabs"],
"platforms": "",
"replacement_web_app": "",
"requirements": {},
"sandbox": [],
"short_name": "short name",
"signature": "",
"spellcheck": "",
"storage": {
"managed_schema": "schema.json"
},
"system_indicator": "",
"tts_engine": {},
"update_url": "http://path/to/updateInfo.xml",,
"version_name": "0.1 beta",
"web_accessible_resource": []
}

BrowerAction Methods

1
chrome.browserAction.method(params)
  • setTitle({ title: string, tabId?: number }, callback)
  • getTitle({ tabId?: number }, callback)
  • setIcon({ imageData?: ImageDataType | object, path?: string | object, tabId?: number }, callback)
  • setPopup({ tabId?: number, popup: string }, callback)
  • getPopup({ tabId?: number }, callback)
  • setBadgeText({ text: string, tabId?: number }, callback)
  • getBadgeText({ tabId?: number }, callback)
  • setBadgeBackgroundColor({ color: string or ColorArray, tabId?: number }, callback)
  • getBadgeBackgroundColor({ tabId?: number }, callback)
  • enable({ tabId?: number }, callback)
  • disable({ tabId?: number }, callback)

BrowserAction Events

1
chrome.browserAction.onClicked.addEventListener((tab: tabs.Tab) => {})

PageAction Methods

1
chrome.pageAction.method(params)
  • show({ tabId: number }, callback), the page action is shown whenever the tab is selected
  • hide({ tabId: number }, callback), hide the page action, means set the page action gray
  • setTitle({ tabId: number, title: string }, callback)
  • getTitle({ tabId: number }, callback)
  • setIcon({ imageData: object | ImageDataType, path?: string | object, }), the path to the icons could be a dictionary {size => relative image path}, the actual image to be used is chosen depending on screen’s pixel density. Note that path = ‘foo’ equals to path = { ‘16’: foo }, implicitly converted into a dictionary.
  • setPopup({ tabId: number, popup: string }, callback)
  • getPopup({ tabId }, callback)

PageAction Events

1
chrome.pageAction.onClicked.addEventListener((tab: tabs.Tab) => {})

Background

Extensions are event-driven programs used to modify or enhance the chrome browsing experience. Events are browser triggers and extensions monitor them in background scripts, then react to specified instructions.

A background page is loaded when it is needed, and unloaded when it goes idle.

- The extension is first installed or updated to a new version.
- The background page was listening for an event, and the event is dispatched.
- A content script or other extension sends a message.
- Another view in the extension, such as a popup, calls `runtime.getBackgroundPage`.

Register background scripts

Background scripts are registered in the manifest under the “background” field. They are listed in an array of “background.scripts”.

Remember to set “persistent” to false unless the extension uses chrome.webRequest API to block or modify network requests.

Initialize the extension

Listen to runtime.onInstalled event to initialize an extension on installation. Use this event to set a state or for one-time initialization, such as a context menu.

1
2
3
4
5
6
7
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenu.create({
id: 'sampleContextMneu',
title: 'Sample Context Menu',
contexts: ['selection'],
})
})

Set up listeners

Structure background scripts around events the extension depends on. Defining functionally relevant events allows background scripts to lie dormant until those events are fired and prevents the extension from missing important triggers.

Listeners must be registered synchronously from the start of the page.

1
2
3
4
// This will run when a bookmark is created
chrome.bookmark.onCreated.addListener(() => {
// do something
})

Do not register listeners asynchronously, as they will not be properly triggered.

1
2
3
4
5
6
// DO NOT DO THIS
chrome.runtime.onInstalled.addListener(() => {
chrome.bookmarks.onCreated.addListener(() => {
// do something
})
})

Filter events

Use APIs that supports event filters to restrict listeners to the cases the extension cares about. If an extension is listening for the tabs.onUpdated event, try using the webNavigation.onCompleted event with filters instead, as the tabs API does not support filters.

1
2
3
4
5
6
7
8
9
10
11
12
chrome.webNavigation.onCompleted.addListener(
() => {
alert('This is my favorite website')
},
{
url: [
{
urlMatches: 'http://www.google.com',
},
],
},
)

React to listeners

1
2
3
4
5
6
7
8
9
10
11
chrome.runtime.onMessage.addListener((message, callback) => {
if (message.data === 'setAlarm') {
chrome.alarms.create({ delayInMinutes: 5 })
} else if (message.data === 'runLogic') {
chrome.tabs.executeScript({ file: 'logic.js' })
} else if (message.data === 'changeColor') {
chrome.tabs.executeScript({
code: 'document.body.style.backgroundColor="orange"',
})
}
})

Unload background scripts

Data should be persisted periodically so that important information is not lost if an extension crashes without receiving onSuspend. Use the storage API to assist with this.

1
chrome.storage.local.set({ variable: 'info' })

If an extension uses message passing, ensure all ports are closed. The background script will not unload until all message ports have shut.

Listen to runtime.Port.onDisconnect event will give insight to when open ports are closing. Manually close them with runtime.Port.disconnect.

Background scripts unload themself after a few seconds of inactivity. If any last minute cleanup is required, listen to runtime.onSuspend event.

1
2
3
4
chrome.runtime.onSuspend.addListener(() => {
console.log('unloading')
chrome.browserAction.setBadgeText({ text: '' })
})

Content scripts

Content scripts are files that run in the context of web pages. By using the standard DOM, they are able to read details of the web pages the browser visits, make changes to them and pass information to their parent extension.

Content scripts can access chrome APIs used by their parent extension by exchanging messages with the extension. They can also access the URL of an extension’s file with chrome.runtime.getURL() and use the result the same as other URLs.

Content scripts can access the following chrome APIs directly:

  • i18n
  • storage
  • runtime
    • connect
    • getManifest
    • getURL
    • id
    • onConnect
    • onMessage
    • sendMessage

Content scripts are unable to access other APIs directly.

Work in isolated worlds

Content scripts live in an isolated world, allowing a content script to makes chagnes to its JavaScript environment without conflicting with the page or additional content scripts.

Inject scripts

Content scripts can be programmatically or declaratively injected.

Inject Programmatically

Use programmatic injection for content scripts that need to run on specific occasions.

To inject a programmatic content script, provide the activeTab permission in the manifest. This grants secure access to the active site’s host and temporary access to the tabs permission, enabling the content script to run on the current active tab without specifying cross-origin premissions.

1
2
3
{
"permissions": ["activeTab"]
}

Then content scripts can be injected as code

1
2
3
4
5
6
7
8
9
10
11
chrome.runtime.onMessage.addListener((message, callback) => {
if (message === 'changeColor') {
chrome.tabs.executeScript({
code: 'document.body.style.backgroundColor="orange"',
})
} else if (message === 'runContentScript') {
chrome.tabs.executeScript({
file: 'contentScript.js',
})
}
})

Inject declaratively

Use declarative injection for content scripts that should be automatically run on specified pages.

Declaratively injected scripts are registered in the manifest.content_scripts field.

1
2
3
4
5
6
7
8
9
10
11
12
{
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"], // required, specifies which pages this content script will be injected into.
"css": ["myStyles.css"], // optional, the list of css files to be injected into the pages. They are injected orderly.
"js": ["contentScript.js"], // optional, the list of js files to be injected into orderly.
"match_about_blank": false, // optional, whether or not to inject into the blank pages
"run_at": "document_idel", // controls when the files are injected, the preferred and default config is document_idle.
"all_frames": false,
}
]
}

Chrome Permissions

Use the chrome.permission API to request declared optional permissions at run time rather than install time, so users understand why the permissions are needed and grant only those that are necessary.

Decide which permissions are required and which are optional

An extension can declare both required and optional permissions. In general, you should:

  • Use required permissions when they are needed for your extension’s basic functionality.
  • Use optional permissions when they are needed for optional features in your extension.

Advantages of required permissions:

  • Fewer prompts: An extension can prompt the user once to accept all permissions.
  • Simpler development: Required permissions are guaranteed to be present.

Advantages of optional permissions:

  • Better security
  • Better information for users: An extension can explain why it needs a particular permission when the user enables the relevant feature.
  • Easier upgrades: When you upgrades your extension, chrome will not disable it for your users if the upgrade adds optional rather than required permissions.

Declare optional permissions in your extension manifest with the optional_permissions key, using the same format as the permission field.

Request optional permissions

Request the permission from within a user gesture using permissions.request().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
document.querySelector('#my-button').addEventListener('click', (e) => {
chrome.permissions.request(
{
permissions: ['tabs'],
origins: ['http://www.google.com'],
},
(granted) => {
if (granted) {
// do something
} else {
// do something
}
},
)
})

Check the extension’s current permissions

1
2
3
4
5
6
7
8
9
10
11
12
13
chrome.permissions.contains(
{
permissions: ['tabs'],
origins: ['http://www.google.com'],
},
(result) => {
if (result) {
// the extension has the permissions
} else {
// the extension doesn't have the permissions
}
},
)

Remove the permissions

1
2
3
4
5
6
7
8
9
chrome.permissions.remove(
{
permissions: ['tabs'],
origins: ['http://www.google.com'],
},
(removed) => {
// do something
},
)

Requirements

Technologies required by the app or extension. Hosting sites such as chrome web store may use this list to dissuade users from installing apps or extensions that will not work on their computer.

Supported requirements currently include “3D” and “plugins”.

Messages

Since content scripts run in the context of a web page and not the extension, they often need some way of communicating with the rest of the extension. For example, an RSS reader extension might use content script to detect the presence of an RSS feed on a page, then notify the background page in order to display a page action icon for that page.

Communication between extensions and their content script scripts works by using message passing. Either side can listen for message sent from the other end, and respond on the same channel. A message can contain any valid JSON object.

Simple one-time requests

If you only need to send a single message to another part of your extension, you should use the simplified runtime.sendMessage and tabs.sendMessage. This lets you send a one-time JSON-serializable message from a content script to extension, or vice versa, respectively.

1
2
3
4
// send a request from content script
chrome.runtime.sendMessage({ greeting: 'hello' }, (res) => {
console.log(res)
})
1
2
3
4
5
6
// send a request from the extension to a content script works similar, except that you need to specify which tab to send it to.
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, { greeting: 'hello' }, (res) => {
console.log(res)
})
})

On the receiving end, you need to set up an runtime.onMessage event listener to handle the message.

1
2
3
4
5
6
chrome.runtime.onMessage.addListener((req, sender, sendRespond) => {
console.log(sender.tab ? `from a content script: ${sender.tab.url}` : `from the extension`)
if (req.greeting === 'hello') {
sendResponse({ farewell: 'goodbye' })
}
})

In the above example, the sendResponse is called synchronously. If you want to call the sendResponse asynchronously, simple return true at the end.

Note: If multiple pages are listening on the onMessage events, only the first to call sendResponse for a particular event will succeed in sending response. Other response will be ignored.

Note: call sendResponse synchronously or return true. Without return true, sendResponse(undefined) will be called automatically and implicitly.

Long-lived connections

Sometimes it’s useful to have a conversation lasting longer than one-time request.

You can open a long-lived channel from content script to an extension page, or vice versa, by using runtime.connect or tab.connect.

When establishing a connection, each end is given a runtime.Port object which is used for sending and receiving messages through that connection.

1
2
3
4
5
6
7
8
9
const port = chrome.runtime.connect({ name: 'knockknock' })
port.postMessage({ joke: 'Knock knock' })
port.onMessage.addListener((msg) => {
if (msg.question === "Who's there?") {
port.postMessage({ answer: 'Madame' })
} else if (msg.question === 'Madame who?') {
port.postMessage({ answer: 'Madame... Bovary' })
}
})