Table of Contents Previous entry (api:window.focus) Next entry (api:CDATA)
Userscripts can exchange messages with each other over a dedicated channel. This works both inside a single tab - between the top frame and its iframes - and between different tabs, as long as the scripts belong to the same Tampermonkey profile.
The channel is only available to sandboxed scripts.
A script with @grant none or @unwrap runs in the page's own scope and uses the native window.postMessage / window.addEventListener, so message passing is not active for it.
No @grant directive is required for this feature itself - every sandboxed script can use it.
There is a special target, 'tampermonkey:self', that delivers the message back to your own listeners.
Unlike every other target it is synchronous: the message is dispatched to your tampermonkey:message listeners in the same call, before window.postMessage returns.
That makes it a reliable, timeout-free way to find out whether message passing is active for the current script:
const supportsMessagePassing = (() => {
const token = 'tm-probe-' + Math.random().toString(36).slice(2);
let supported = false;
const listener = (event) => { if (event.data === token) supported = true; };
window.addEventListener('tampermonkey:message', listener);
try {
window.postMessage(token, 'tampermonkey:self');
} catch (e) {}
window.removeEventListener('tampermonkey:message', listener);
return supported;
})();
To receive messages, register a listener for the tampermonkey:message event:
window.addEventListener('tampermonkey:message', (event) => {
// event.source - a unique id of the sending instance, e.g. "tampermonkey:3f2a9c…e1"
// event.data - the payload the sender posted
if (event.data && event.data.hello === 'world') {
console.log('got a greeting from', event.source);
}
});
event.source is a stable identifier of the sending instance in the form tampermonkey: followed by a string.
Every frame (the top frame and each of its iframes) and every tab has its own id, so it can be used to tell senders apart and to reply to a specific one.
To send a message, call window.postMessage with a tampermonkey: target as the second argument:
// reply to the specific instance you received the message from
window.postMessage({ hello: 'back' }, event.source);
// broadcast to every other registered instance in the same profile
window.postMessage({ type: 'status', active: true }, 'tampermonkey:*');
The target is one of:
event.source id you received earlier, to send (or reply) to that single instance, or'tampermonkey:*' to broadcast the message to every other registered instance. The sending instance is never delivered to itself, so a broadcast never echoes back to its sender, or'tampermonkey:self' to deliver the message to your own listeners - the target used for feature detection (synchronous).Use a broadcast to reach instances you have not heard from yet; once you know an instance's event.source, send to it directly.
The payload - the first argument of postMessage, delivered to the receiver as event.data - is copied, so it must be a JSON-cloneable value: an object, array, string, number, boolean or null.
Functions, DOM nodes and other non-cloneable values are not supported.
Delivery is best-effort. A message only reaches instances that are currently registered - their script is running and has an open channel. There is no queueing: if the target is not registered at the moment the message is sent, the message is dropped. Because of this, a sender might re-sends a discovery message on a short interval until the receiving side is ready to pick it up.