### Install and Start Documentation Development Server
Source: https://github.com/scriptscat/scriptcat/blob/main/CONTRIBUTING.md
Commands to install documentation dependencies and start the local development server for previewing documentation changes.
```bash
pnpm install
```
```bash
pnpm start
```
--------------------------------
### Install Node.js Dependencies with pnpm
Source: https://github.com/scriptscat/scriptcat/blob/main/CONTRIBUTING.md
Use this command to install project dependencies when setting up the development environment. ScriptCat uses pnpm for dependency management.
```bash
pnpm install
```
--------------------------------
### Start ScriptCat Local Development Server
Source: https://github.com/scriptscat/scriptcat/blob/main/CONTRIBUTING.md
Commands to start the local development server for ScriptCat. The `dev:noMap` command is a workaround for potential issues with incognito windows.
```bash
pnpm run dev
```
```bash
pnpm run dev:noMap
```
--------------------------------
### Storage Operations
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Demonstrates asynchronous operations for getting, setting, and listing values in storage.
```APIDOC
## Storage Operations
### Description
Asynchronous functions for managing script storage.
### Methods
- **GM.setValue(key, value)**: Asynchronously stores a value under a given key.
- **GM.getValue(key, defaultValue)**: Asynchronously retrieves the value associated with a key, with an optional default value.
- **GM.deleteValue(key)**: Asynchronously removes a key-value pair from storage.
- **GM.listValues()**: Asynchronously retrieves a list of all keys currently in storage.
- **GM.setValues(object)**: Asynchronously stores multiple key-value pairs from an object.
- **GM.getValues(keys)**: Asynchronously retrieves multiple values based on an array of keys.
- **GM.deleteValues(keys)**: Asynchronously removes multiple key-value pairs based on an array of keys.
### Request Example (Setting a value)
```javascript
await GM.setValue("user", { name: "Alice", score: 42 });
```
### Response Example (Getting a value)
```javascript
const user = await GM.getValue("user", null);
console.log(user); // { name: "Alice", score: 42 }
```
### Response Example (Listing values)
```javascript
const keys = await GM.listValues();
console.log(keys); // ["key1", "key2", ...]
```
```
--------------------------------
### Commit Message Example with Gitmoji
Source: https://github.com/scriptscat/scriptcat/blob/main/CONTRIBUTING.md
Example of a commit message following the gitmoji specification to indicate the addition of a new feature.
```bash
git commit -m "✨ add login feature"
```
--------------------------------
### Access Bundled Static Resources with GM_getResourceText/URL
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Use GM_getResourceText to read resource content as a string and GM_getResourceURL to get a URL for the resource. The second argument to GM_getResourceURL can be set to true to obtain a Blob URL, which is revocable and suitable for large files.
```javascript
// ==UserScript==
// @name Resource Demo
// @match *://*/*
// @resource config https://cdn.example.com/config.json
// @resource logo https://cdn.example.com/logo.png
// @resource tmpl https://cdn.example.com/template.html
// @grant GM_getResourceText
// @grant GM_getResourceURL
// ==/UserScript==
// Read resource as text
const rawJson = GM_getResourceText("config");
const config = JSON.parse(rawJson);
console.log("Config loaded:", config);
// Get data URL (default) — safe for
const logoDataUrl = GM_getResourceURL("logo");
const imgEl = document.createElement("img");
imgEl.src = logoDataUrl;
document.body.prepend(imgEl);
// Get Blob URL (isBlobUrl = true) — revocable, better for large files
const logoBlobUrl = GM_getResourceURL("logo", true);
console.log("Blob URL:", logoBlobUrl);
// Inject an HTML template resource into the DOM
const html = GM_getResourceText("tmpl");
const container = document.createElement("div");
container.innerHTML = html;
document.body.appendChild(container);
// Async variant
(async () => {
const url = await GM.getResourceUrl("config"); // note: GM.getResourceUrl (lowercase u)
const resp = await fetch(url);
const data = await resp.json();
console.log("Async config:", data);
})();
```
--------------------------------
### Run ESLint and Vitest for Development
Source: https://github.com/scriptscat/scriptcat/blob/main/CONTRIBUTING.md
Commands to run ESLint for code style checks and Vitest for unit testing. These tools are used to maintain code quality in ScriptCat.
```bash
pnpm test
```
```bash
pnpm run lint
```
--------------------------------
### Pre-Page Injection with @early-start
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Use `@early-start` to inject scripts before any page scripts. `CAT_scriptLoaded()` is provided to await the full initialization of GM APIs, especially for asynchronous operations.
```javascript
// ==UserScript==
// @name Early Start Demo
// @match https://example.com/*
// @run-at document-start
// @grant GM_getValue
// @grant GM_setValue
// @grant CAT_scriptLoaded
// @early-start
// ==/UserScript==
// Runs before *any* page script — GM_getValue/GM_setValue work immediately
console.log("Stored value:", GM_getValue("key", "default"));
GM_setValue("key", "new-value");
// Intercept events before the page registers its own listeners
const _addEventListener = document.addEventListener.bind(document);
document.addEventListener = function (type, handler, ...rest) {
if (type === "click") {
const original = handler;
handler = function (e) {
// Make every click appear trusted
const fakeEvent = Object.create(MouseEvent.prototype);
Object.assign(fakeEvent, e, { isTrusted: true });
original.call(this, fakeEvent);
};
}
_addEventListener(type, handler, ...rest);
};
// Wait for GM APIs to be fully initialised (async APIs may need this)
CAT_scriptLoaded().then(() => {
console.log("All GM APIs are now ready");
});
```
--------------------------------
### Async GM API Demo
Source: https://context7.com/scriptscat/scriptcat/llms.txt
This script demonstrates various asynchronous Greasemonkey API calls including storage, XHR, notifications, tab opening, clipboard, styling, resources, and cookies. Ensure all required @grant declarations are present in the UserScript header.
```javascript
// ==UserScript==
// @name Async GM API Demo
// @match *://*/*
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.deleteValue
// @grant GM.listValues
// @grant GM.xmlHttpRequest
// @grant GM.notification
// @grant GM.openInTab
// @grant GM.setClipboard
// @grant GM.addStyle
// @resource tmpl https://example.com/template.html
// @grant GM.getResourceUrl
// ==/UserScript==
(async () => {
// Storage
await GM.setValue("user", { name: "Alice", score: 42 });
const user = await GM.getValue("user", null);
console.log("User:", user); // { name: "Alice", score: 42 }
const keys = await GM.listValues();
console.log("Keys:", keys);
// Batch operations
await GM.setValues({ a: 1, b: 2, c: 3 });
const multi = await GM.getValues(["a", "b"]);
console.log("a, b:", multi); // { a: 1, b: 2 }
await GM.deleteValues(["a", "b", "c"]);
// XHR
const resp = await GM.xmlHttpRequest({
method: "GET",
url: "https://api.github.com/zen",
responseType: "text",
});
console.log("GitHub zen:", resp.responseText);
// Notifications
await GM.notification({ title: "Done", text: "Async flow complete", timeout: 3000 });
// Open a tab
const tab = await GM.openInTab("https://scriptcat.org", { active: false });
tab.onclose = () => console.log("Tab closed");
setTimeout(() => tab.close(), 5000);
// Clipboard
await GM.setClipboard("Copied via GM.setClipboard!");
// Style injection
await GM.addStyle("body { border: 3px solid #4fc3f7 !important; }");
// Resource
const url = await GM.getResourceUrl("tmpl");
console.log("Resource URL:", url);
// Cookie (Promise style)
await GM.cookie.set({ url: "https://example.com/", name: "k", value: "v" });
const cookies = await GM.cookie.list({ domain: "example.com" });
console.log("Cookies:", cookies);
await GM.cookie.delete({ url: "https://example.com/", name: "k" });
})();
```
--------------------------------
### Package ScriptCat Extension
Source: https://github.com/scriptscat/scriptcat/blob/main/CONTRIBUTING.md
Command to package the ScriptCat extension for distribution. Ensure the `scriptcat.pem` file exists in the `dist` directory before running.
```bash
pnpm run pack
```
--------------------------------
### HTTP Requests
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Shows how to perform asynchronous HTTP requests using `GM.xmlHttpRequest`.
```APIDOC
## GM.xmlHttpRequest
### Description
Performs an asynchronous HTTP request. This is useful for bypassing CORS restrictions.
### Method
`GM.xmlHttpRequest(details)`
### Parameters
- **details** (object) - Required - An object containing the request details.
- **method** (string) - Required - The HTTP method (e.g., "GET", "POST").
- **url** (string) - Required - The URL to request.
- **responseType** (string) - Optional - The expected response type (e.g., "text", "json", "arraybuffer").
- ... other standard XHR properties
### Request Example
```javascript
const resp = await GM.xmlHttpRequest({
method: "GET",
url: "https://api.github.com/zen",
responseType: "text",
});
```
### Response Example (Success)
- **responseText** (string) - The response body as text.
- **response** (any) - The response body, parsed according to `responseType`.
- **status** (number) - The HTTP status code.
- **statusText** (string) - The HTTP status text.
```javascript
console.log("GitHub zen:", resp.responseText);
```
```
--------------------------------
### Notifications
Source: https://context7.com/scriptscat/scriptcat/llms.txt
How to display asynchronous notifications to the user.
```APIDOC
## GM.notification
### Description
Displays a notification to the user.
### Method
`GM.notification(details)`
### Parameters
- **details** (object) - Required - An object containing notification details.
- **title** (string) - Required - The title of the notification.
- **text** (string) - Required - The main content of the notification.
- **timeout** (number) - Optional - The duration in milliseconds the notification should be displayed.
### Request Example
```javascript
await GM.notification({
title: "Done",
text: "Async flow complete",
timeout: 3000
});
```
```
--------------------------------
### Define User Configuration UI with UserConfig
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Define a YAML configuration schema within a `==UserConfig==` block to automatically generate a settings UI panel. ScriptCat stores values using `GM_getValue`/`GM_setValue` and makes them accessible via `GM_info.userConfig`.
```javascript
// ==UserScript==
// @name UserConfig Demo
// @match *://*/*
// @grant GM_getValue
// @grant GM_setValue
// @grant CAT_userConfig
// ==/UserScript==
/* ==UserConfig==
general:
username:
title: Username
description: Your display name
type: text
default: Guest
min: 2
max: 20
darkMode:
title: Dark Mode
type: checkbox
default: false
theme:
title: Color Theme
type: select
default: blue
values: [blue, green, red, purple]
fontSize:
title: Font Size (px)
type: number
default: 14
min: 10
max: 32
unit: px
notes:
title: Notes
type: textarea
default: ""
rows: 4
==/UserConfig== */
// Read config values using GM_info.userConfig for default values
const rawConfig = GM_info.userConfig;
const config = {};
for (const [group, items] of Object.entries(rawConfig)) {
for (const [key, { default: def }] of Object.entries(items)) {
config[`${group}.${key}`] = GM_getValue(`${group}.${key}`, def);
}
}
console.log("Username:", config["general.username"]); // "Guest" (or user value)
console.log("Dark mode:", config["general.darkMode"]); // false (or user value)
// Apply settings
if (config["general.darkMode"]) {
document.body.style.background = "#111";
document.body.style.color = "#eee";
}
// Open the config panel programmatically
CAT_userConfig();
```
--------------------------------
### Resource Handling
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Retrieving URLs for resources defined in the script's metadata.
```APIDOC
## GM.getResourceUrl
### Description
Gets the URL for a resource declared in the `@resource` metadata.
### Method
`GM.getResourceUrl(name)`
### Parameters
- **name** (string) - Required - The name of the resource as defined in `@resource`.
### Request Example
```javascript
const url = await GM.getResourceUrl("tmpl");
```
### Response Example
- **url** (string) - The URL of the requested resource.
```javascript
console.log("Resource URL:", url);
```
```
--------------------------------
### GM_download / GM.download
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Provides functionality to trigger file downloads directly to the user's disk. It supports custom filenames, headers, and progress callbacks, with options for both native-XHR and browser-API download modes.
```APIDOC
## GM_download / GM.download — Trigger File Downloads
Download a URL or Blob directly to the user's disk. Supports custom filenames, headers, progress callbacks, and both native-XHR and browser-API download modes.
### Parameters
- `url` (string): The URL of the file to download or a Blob URL.
- `name` (string, optional): The desired filename for the downloaded file.
- `headers` (object, optional): Custom headers to include in the download request.
- `onprogress` (function, optional): Callback function to track download progress.
- `data` (object): Contains `loaded` and `total` bytes.
- `onload` (function, optional): Callback function when the download is complete.
- `onerror` (function, optional): Callback function for download errors.
- `err` (object): Contains error details.
- `conflictAction` (string, optional): Action to take if the file already exists ('overwrite', 'prompt', 'uniquify').
### Returns
- `handle` (object): An object representing the download, with an `abort()` method.
### Example Usage (Download with Progress)
```javascript
const handle = GM_download({
url: "https://scriptcat.org/api/v2/open/crx-download/ndcooeababalnlpkfedmmbbbgkljhpjf",
name: "scriptcat.crx",
headers: { referer: "https://scriptcat.org/" },
onprogress(data) {
const pct = data.lengthComputable
? Math.round((data.loaded / data.total) * 100)
: "?";
console.log(`Progress: ${pct}%`);
},
onload() { console.log("Download complete!"); },
onerror(err) { console.error("Download error:", err.error); },
});
// Abort after 5 s
setTimeout(() => handle.abort(), 5000);
```
### Example Usage (Download Blob)
```javascript
const pixels = new Uint8Array([
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a, // PNG header
/* ... rest of PNG bytes ... */
]);
GM_download({
url: URL.createObjectURL(new Blob([pixels], { type: "image/png" })),
name: "screenshot/output.png",
conflictAction: "overwrite", // overwrite if file already exists
});
```
### Example Usage (Simplified Form)
```javascript
GM_download("https://example.com/file.pdf", "document.pdf");
```
```
--------------------------------
### Manage Cloud Files with CAT_fileStorage
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Use CAT_fileStorage to upload, list, download, and delete files in configured cloud storage. Ensure the storage is configured before use; call CAT_fileStorage('config') to open the UI if needed.
```javascript
// ==UserScript==
// @name File Storage Demo
// @match *://*/*
// @grant CAT_fileStorage
// ==/UserScript==
// Upload a file
CAT_fileStorage("upload", {
path: "data/report.txt",
baseDir: "my-script", // optional custom base dir
data: new Blob(["Hello, world!"], { type: "text/plain" }),
onload() {
console.log("Upload successful");
// List files in the directory
CAT_fileStorage("list", {
path: "data/",
baseDir: "my-script",
onload(files) {
console.log("Files:", files);
// files: [{ name, path, absPath, size, digest, createtime, updatetime }]
const report = files.find(f => f.name === "report.txt");
if (!report) return;
// Download the file
CAT_fileStorage("download", {
file: report, // pass full FileInfo (some backends need digest)
async onload(blob) {
const text = await blob.text();
console.log("Content:", text); // "Hello, world!"
// Delete the file
CAT_fileStorage("delete", {
path: "data/report.txt",
baseDir: "my-script",
onload() { console.log("Deleted"); },
onerror(err) { console.error("Delete error:", err.code, err.error); },
});
},
onerror(err) { console.error("Download error:", err); },
});
},
onerror(err) { console.error("List error:", err.code); },
});
},
onerror(err) {
console.error("Upload failed:", err.code, err.error);
// err.code: 1=not configured, 2=config error, 3=path not found,
// 4=upload failed, 5=download failed, 6=delete failed,
// 7=path not allowed, 8=network error, -1=unknown
if (err.code === 1 || err.code === 2) {
CAT_fileStorage("config"); // open storage configuration UI
}
},
});
```
--------------------------------
### Control Browser Tabs with GM_openInTab
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Use GM_openInTab to open URLs in new tabs with options for activation, insertion position, pinning, and incognito mode. It also supports programmatic closing and listening for tab closure events.
```javascript
// ==UserScript==
// @name Tab Control Demo
// @match *://*/*
// @grant GM_openInTab
// ==/UserScript==
// Open in foreground tab, inserted after current tab
const tab = GM_openInTab("https://scriptcat.org/search", {
active: true, // bring to foreground
insert: true, // insert next to current tab
setParent: true, // mark current tab as opener
pinned: false,
});
// Listen for the tab closing
tab.onclose = () => console.log("Tab was closed");
// Programmatically close the tab after 5 s
setTimeout(() => {
if (!tab.closed) tab.close();
}, 5000);
// Open in background with window.open (useful for custom protocols)
GM_openInTab("vscode://file/home/user/script.js", { useOpen: true });
// context-menu run-at example: search selected text
// ==UserScript==
// @run-at context-menu
// @grant GM_openInTab
// ==/UserScript==
(function () {
const sel = window.getSelection().toString().trim();
if (!sel) return alert("Select some text first.");
GM_openInTab(`https://scriptcat.org/search?keyword=${encodeURIComponent(sel)}`);
})();
```
--------------------------------
### Trigger File Downloads with GM_download
Source: https://context7.com/scriptscat/scriptcat/llms.txt
GM_download allows direct file downloads to the user's disk. It supports custom filenames, headers, progress callbacks, and conflict resolution.
```javascript
// ==UserScript==
// @name Download Demo
// @match *://*/*
// @grant GM_download
// ==/UserScript==
// Download a remote file with progress tracking
const handle = GM_download({
url: "https://scriptcat.org/api/v2/open/crx-download/ndcooeababalnlpkfedmmbbbgkljhpjf",
name: "scriptcat.crx",
headers: { referer: "https://scriptcat.org/" },
onprogress(data) {
const pct = data.lengthComputable
? Math.round((data.loaded / data.total) * 100)
: "?";
console.log(`Progress: ${pct}%`);
},
onload() { console.log("Download complete!"); },
onerror(err) { console.error("Download error:", err.error); },
});
// Abort after 5 s
setTimeout(() => handle.abort(), 5000);
// Download a generated Blob (e.g., a dynamically created PNG)
const pixels = new Uint8Array([
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a, // PNG header
/* ... rest of PNG bytes ... */
]);
GM_download({
url: URL.createObjectURL(new Blob([pixels], { type: "image/png" })),
name: "screenshot/output.png",
conflictAction: "overwrite", // overwrite if file already exists
});
// Simplified form: GM_download(url, filename)
GM_download("https://example.com/file.pdf", "document.pdf");
```
--------------------------------
### Clipboard Operations
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Asynchronously setting the content of the system clipboard.
```APIDOC
## GM.setClipboard
### Description
Copies the specified text to the system clipboard.
### Method
`GM.setClipboard(text)`
### Parameters
- **text** (string) - Required - The text to copy to the clipboard.
### Request Example
```javascript
await GM.setClipboard("Copied via GM.setClipboard!");
```
```
--------------------------------
### Schedule Daily Dog Photo Fetch with @crontab
Source: https://context7.com/scriptscat/scriptcat/llms.txt
This script runs daily at 08:00 using the @crontab directive. It fetches a random dog image and displays a notification. Rejects with CATRetryError to trigger automatic retries on API or network errors.
```javascript
// ==UserScript==
// @name Scheduled Task — Daily Dog Photo
// @namespace https://example.com/
// @version 1.0.0
// @description Fetches a random dog image every day at 08:00
// @crontab 0 8 * * * // standard cron: every day at 08:00
// @grant GM_log
// @grant GM_notification
// @grant GM_xmlhttpRequest
// @connect dog.ceo
// ==/UserScript==
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: "https://dog.ceo/api/breeds/image/random",
responseType: "json",
anonymous: true,
onload(resp) {
if (resp.status !== 200 || typeof resp.response.message !== "string") {
// Retry in 60 seconds on failure
reject(new CATRetryError("API error, will retry", 60));
return;
}
GM_log("Dog of the day: " + resp.response.message, "info");
GM_notification({
title: "Dog of the Day 🐶",
text: "Click to view today's dog photo",
url: resp.response.message,
image: resp.response.message,
});
resolve();
},
onerror() {
// Retry at a specific time
const retryAt = new Date(Date.now() + 5 * 60 * 1000); // 5 min later
reject(new CATRetryError("Network error", retryAt));
},
});
});
```
--------------------------------
### Style Injection
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Asynchronously injecting CSS styles into the current page.
```APIDOC
## GM.addStyle
### Description
Injects CSS rules into the current page.
### Method
`GM.addStyle(css)`
### Parameters
- **css** (string) - Required - A string containing CSS rules.
### Request Example
```javascript
await GM.addStyle("body { border: 3px solid #4fc3f7 !important; }");
```
```
--------------------------------
### Configure pnpm Proxy Settings
Source: https://github.com/scriptscat/scriptcat/blob/main/CONTRIBUTING.md
Configure HTTP and HTTPS proxy settings for pnpm to resolve network issues. Replace with your actual proxy address.
```bash
pnpm config set proxy http://127.0.0.1:7890
```
```bash
pnpm config set https-proxy https://127.0.0.1:7890
```
--------------------------------
### CAT_fileStorage - File Operations
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Provides functionality to read, write, list, and delete files in various cloud storage backends. Files are scoped to a per-script directory by default.
```APIDOC
## CAT_fileStorage
### Description
Manages cloud and synchronized file storage, allowing users to interact with configured backends like Dropbox, Google Drive, OneDrive, WebDAV, S3, and Baidu.
### Methods
- `upload`: Uploads a file to the specified path.
- `list`: Lists files in a given directory.
- `download`: Downloads a file.
- `delete`: Deletes a file.
- `config`: Opens the storage configuration UI.
### Parameters for `upload`
- **path** (string) - Required - The destination path for the file.
- **baseDir** (string) - Optional - A custom base directory for the script.
- **data** (Blob) - Required - The file data to upload.
- **onload** (function) - Callback function executed on successful upload.
- **onerror** (function) - Callback function executed on upload failure.
### Parameters for `list`
- **path** (string) - Required - The directory path to list.
- **baseDir** (string) - Optional - A custom base directory.
- **onload** (function) - Callback function executed with a list of files on success.
- **onerror** (function) - Callback function executed on failure.
### Parameters for `download`
- **file** (object) - Required - The file information object (obtained from `list`).
- **onload** (function) - Callback function executed with the file content (Blob) on success.
- **onerror** (function) - Callback function executed on failure.
### Parameters for `delete`
- **path** (string) - Required - The path of the file to delete.
- **baseDir** (string) - Optional - A custom base directory.
- **onload** (function) - Callback function executed on successful deletion.
- **onerror** (function) - Callback function executed on failure.
### Error Codes
- `1`: Not configured
- `2`: Configuration error
- `3`: Path not found
- `4`: Upload failed
- `5`: Download failed
- `6`: Delete failed
- `7`: Path not allowed
- `8`: Network error
- `-1`: Unknown error
```
--------------------------------
### GM_setClipboard
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Writes text or HTML to the system clipboard without requiring the Clipboard API or user gestures.
```APIDOC
## GM_setClipboard
### Description
Writes text or HTML content to the system clipboard.
### Parameters
* **data**: (string) - The data to write to the clipboard.
* **type**: (string, optional) - The MIME type of the data. Defaults to 'text'. Can be 'html' or a specific MIME type.
### Example
```javascript
// Copy plain text
GM_setClipboard("Hello from ScriptCat!");
// Copy HTML content
GM_setClipboard("Bold text", "html");
```
```
--------------------------------
### Monitor Service Status with @background
Source: https://context7.com/scriptscat/scriptcat/llms.txt
This background script runs every 5 minutes to monitor service status. It uses GM_setValue to track the previous status and triggers a notification if the service goes down. Rejects with CATRetryError on network issues.
```javascript
// ==UserScript==
// @name Background Script — Continuous Monitor
// @background
// @crontab */5 * * * * // run every 5 minutes
// @grant GM_setValue
// @grant GM_notification
// @grant GM_xmlhttpRequest
// @connect status.example.com
// ==/UserScript==
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: "https://status.example.com/api/health",
responseType: "json",
onload(resp) {
const status = resp.response?.status;
const prev = GM_getValue("lastStatus", "ok");
GM_setValue("lastStatus", status);
if (status !== "ok" && prev === "ok") {
GM_notification({ title: "⚠️ Service Down", text: "example.com is experiencing issues" });
}
resolve();
},
onerror() { reject(new CATRetryError("Network unavailable", 60)); },
});
});
```
--------------------------------
### Tab Management
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Managing browser tabs asynchronously.
```APIDOC
## GM.openInTab
### Description
Opens a URL in a new tab.
### Method
`GM.openInTab(url, options)`
### Parameters
- **url** (string) - Required - The URL to open.
- **options** (object) - Optional - Configuration for the new tab.
- **active** (boolean) - Optional - Whether the new tab should be active. Defaults to true.
### Request Example
```javascript
const tab = await GM.openInTab("https://scriptcat.org", { active: false });
```
### Response Example
- **tab.close()**: A function to close the opened tab.
```javascript
tab.onclose = () => console.log("Tab closed");
setTimeout(() => tab.close(), 5000);
```
```
--------------------------------
### GM_openInTab / GM_closeInTab
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Opens URLs in new browser tabs with control over foreground/background state, position, pinning, incognito mode, and the ability to close tabs programmatically or listen for their closure.
```APIDOC
## GM_openInTab / GM_closeInTab
### Description
Opens URLs in new browser tabs with various options and provides methods to control and monitor the opened tab.
### Parameters
* **url**: (string) - The URL to open.
* **options**: (object, optional) - Configuration options for the new tab.
* **active**: (boolean) - Whether to bring the tab to the foreground.
* **insert**: (boolean) - Whether to insert the tab next to the current tab.
* **setParent**: (boolean) - Whether to mark the current tab as the opener.
* **pinned**: (boolean) - Whether to pin the tab.
* **incognito**: (boolean) - Whether to open in incognito mode.
* **useOpen**: (boolean) - Whether to use `window.open` instead of a new tab.
### Returns
* **Tab**: An object representing the opened tab, with a `close()` method and an `onclose` event handler.
### Example
```javascript
const tab = GM_openInTab("https://scriptcat.org/search", {
active: true,
insert: true,
});
tab.onclose = () => console.log("Tab was closed");
setTimeout(() => {
if (!tab.closed) tab.close();
}, 5000);
```
```
--------------------------------
### Handling Keyword Conflicts in Translations
Source: https://github.com/scriptscat/scriptcat/blob/main/src/locales/README.md
Use the 'page.key' format to distinguish between keywords that are the same but have different translations within a page. This ensures correct localization when multiple similar keys exist.
```json
{
"list": {
"confirm_delete": "Are you sure you want to delete? Please note that this is an irreversible operation.",
"confirm_update": "Are you sure you want to update? Please note that this is an irreversible operation."
}
}
```
--------------------------------
### Write to System Clipboard with GM_setClipboard
Source: https://context7.com/scriptscat/scriptcat/llms.txt
GM_setClipboard allows writing text or HTML to the system clipboard without user gestures or Clipboard API. It supports plain text, HTML, and custom MIME types.
```javascript
// ==UserScript==
// @name Clipboard Demo
// @match *://*/*
// @grant GM_setClipboard
// ==/UserScript==
// Copy plain text
GM_setClipboard("Hello from ScriptCat!");
// Copy HTML content
GM_setClipboard("Bold text", "html");
// Copy with explicit MIME type
GM_setClipboard("data payload", { type: "text/plain" });
// One-click copy button example
const btn = document.createElement("button");
btn.textContent = "Copy page title";
btn.addEventListener("click", () => {
GM_setClipboard(document.title, "text");
btn.textContent = "Copied!";
setTimeout(() => { btn.textContent = "Copy page title"; }, 2000);
});
document.body.prepend(btn);
```
--------------------------------
### Listen for Storage Changes with GM_addValueChangeListener
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Use GM_addValueChangeListener to monitor storage changes across tabs. Remember to call GM_removeValueChangeListener to prevent memory leaks.
```javascript
// ==UserScript==
// @name Value Change Listener
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addValueChangeListener
// @grant GM_removeValueChangeListener
// @storageName shared-example
// ==/UserScript==
// Register a listener — fires when "counter" is changed from any tab
const listenerId = GM_addValueChangeListener(
"counter",
(name, oldValue, newValue, remote, tabId) => {
console.log(`[${name}] ${oldValue} → ${newValue}`);
console.log("Changed from remote tab?", remote, "tabId:", tabId);
}
);
// Trigger the listener from this tab
GM_setValue("counter", (GM_getValue("counter", 0) + 1));
// Later: clean up to prevent memory leaks
setTimeout(() => {
GM_removeValueChangeListener(listenerId);
console.log("Listener removed");
}, 30000);
```
--------------------------------
### Manage Browser Cookies with ScriptCat
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Use GM_cookie or GM.cookie to read, write, and delete browser cookies. Requires `@connect` for the target domain. The callback style (GM_cookie) and promise style (GM.cookie) are supported, along with shorthand methods.
```javascript
// ==UserScript==
// @name Cookie Demo
// @match https://example.com/*
// @grant GM_cookie
// @grant GM.cookie
// @connect example.com
// ==/UserScript==
// Callback style (GM_cookie)
GM_cookie("set", {
url: "https://example.com/",
domain: ".example.com",
path: "/",
name: "session",
value: "tok_abc123",
secure: true,
httpOnly: false,
expirationDate: Math.floor(Date.now() / 1000) + 86400, // expires in 1 day
}, (cookies, err) => {
if (err) return console.error("Set failed:", err);
console.log("Cookie set");
GM_cookie("list", { domain: "example.com" }, (list, err) => {
if (err) return console.error(err);
console.log("Cookies:", list.map(c => `${c.name}=${c.value}`));
});
});
GM_cookie("delete", { url: "https://example.com/", name: "session" }, () => {
console.log("Cookie deleted");
});
// Shorthand sub-methods
GM_cookie.list({ domain: "example.com" }, (list) => console.log(list));
GM_cookie.set({ url: "https://example.com/", name: "x", value: "1" }, () => {});
GM_cookie.delete({ url: "https://example.com/", name: "x" }, () => {});
// Promise style (GM.cookie)
(async () => {
await GM.cookie.set({ url: "https://example.com/", name: "foo", value: "bar" });
const cookies = await GM.cookie.list({ domain: "example.com" });
console.log("Found cookies:", cookies);
await GM.cookie.delete({ url: "https://example.com/", name: "foo" });
})();
```
--------------------------------
### GM_addValueChangeListener / GM_removeValueChangeListener
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Allows scripts to listen for real-time storage changes across different tabs and background scripts. It provides a mechanism to react to modifications in shared storage namespaces.
```APIDOC
## GM_addValueChangeListener / GM_removeValueChangeListener — Value Change Events
Listen for storage changes in real time, including changes made by other tabs or background scripts sharing the same storage namespace.
### Parameters
- `name` (string): The name of the storage item to listen for changes.
- `oldValue` (any): The previous value of the storage item.
- `newValue` (any): The new value of the storage item.
- `remote` (boolean): Indicates if the change originated from a different tab or script.
- `tabId` (number): The ID of the tab where the change occurred (if `remote` is true).
### Returns
- `listenerId` (number): An identifier for the registered listener, used for removal.
### Example Usage
```javascript
// Register a listener
const listenerId = GM_addValueChangeListener(
"counter",
(name, oldValue, newValue, remote, tabId) => {
console.log(`[${name}] ${oldValue} → ${newValue}`);
console.log("Changed from remote tab?", remote, "tabId:", tabId);
}
);
// Later: clean up to prevent memory leaks
setTimeout(() => {
GM_removeValueChangeListener(listenerId);
console.log("Listener removed");
}, 30000);
```
```
--------------------------------
### Crontab / Background Scripts
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Enables scheduled execution of scripts using `@crontab` and persistent background execution using `@background`.
```APIDOC
## Crontab / Background Scripts
### Description
Allows scripts to run on a schedule or persistently in the background. Scheduled scripts wrap their body in a Promise, and rejecting with `CATRetryError` triggers automatic retries.
### Directives
- **@crontab** (string): Specifies a cron schedule for the script. The script body must return a Promise.
- **@background**: Designates the script to run persistently in the background.
### `CATRetryError`
When used within a Promise returned by a `@crontab` script, rejecting with `CATRetryError` can trigger automatic retries.
- **`CATRetryError(message, delay)`**: Retries after a specified `delay` (in seconds or a Date object).
### Example Usage (`@crontab`)
```javascript
// ==UserScript==
// @name Scheduled Task — Daily Dog Photo
// @crontab 0 8 * * *
// @grant GM_xmlhttpRequest
// ==/UserScript==
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: "https://dog.ceo/api/api/breeds/image/random",
onload(resp) {
// Process response
resolve();
},
onerror() {
reject(new CATRetryError("Network error", 60));
},
});
});
```
### Example Usage (`@background`)
```javascript
// ==UserScript==
// @name Background Script — Continuous Monitor
// @background
// @crontab */5 * * *
// @grant GM_setValue
// ==/UserScript==
return new Promise((resolve, reject) => {
// Perform background tasks
resolve();
});
```
```
--------------------------------
### ScriptCat Userscript Metadata Block
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Defines script identity, permissions, and execution configuration. Ensure all required domains and APIs are declared.
```javascript
// ==UserScript==
// @name My Script
// @namespace https://example.com/
// @version 1.0.0
// @description What this script does
// @author YourName
// @match https://example.com/*
// @match *://*.example.org/*
// @exclude https://example.com/excluded/*
// @connect api.example.com // domains allowed for GM_xmlhttpRequest
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_notification
// @grant GM_cookie
// @resource mydata https://cdn.example.com/data.json
// @require https://cdn.example.com/lib.js
// @run-at document-start // document-start | document-end | document-idle | context-menu
// @inject-into page // page (default) | content
// @storageName shared-storage // share storage namespace across scripts
// ==/UserScript==
```
--------------------------------
### Manage Extension Popup Menu Items
Source: https://context7.com/scriptscat/scriptcat/llms.txt
Use GM_registerMenuCommand to add items to the ScriptCat popup menu and GM_unregisterMenuCommand to remove them. Supports separators, nested items, individual items, and access keys. Menu items can be dynamically updated by re-registering with the same ID.
```javascript
// ==UserScript==
// @name Menu Demo
// @match *://*/*
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// ==/UserScript==
// Simple menu item
const id1 = GM_registerMenuCommand("Open settings", () => {
alert("Settings clicked!");
}, { accessKey: "s" });
// Separator (empty name)
GM_registerMenuCommand("");
// Nested in the script's sub-menu (default); shown as-is in context menu
const id2 = GM_registerMenuCommand("Toggle dark mode", () => {
document.body.classList.toggle("dark");
}, { nested: true });
// Individual item — not merged with identically-named items across frames
const id3 = GM_registerMenuCommand("Reload data", () => {
location.reload();
}, { individual: true, autoClose: false });
// Dynamically update a menu item by re-registering with the same id
setTimeout(() => {
GM_registerMenuCommand("Reload data (updated)", () => location.reload(), { id: id3 });
}, 3000);
// Remove a menu item
GM_unregisterMenuCommand(id1);
```
--------------------------------
### Per-Tab Data Storage with GM_getTab/saveTab/getTabs
Source: https://context7.com/scriptscat/scriptcat/llms.txt
GM_getTab and GM_saveTab allow storing and retrieving arbitrary data objects associated with the current browser tab. Data persists across navigations within a tab but is lost when the tab closes. GM_getTabs retrieves data from all open tabs running the script.
```javascript
// ==UserScript==
// @name Tab Data Demo
// @match *://*/*
// @grant GM_getTab
// @grant GM_saveTab
// @grant GM_getTabs
// ==/UserScript==
// Read the current tab's stored data
GM_getTab((tabData) => {
console.log("Current tab data:", tabData);
// Add or update values and save back
tabData.visitCount = (tabData.visitCount || 0) + 1;
tabData.lastUrl = location.href;
GM_saveTab(tabData);
console.log("Saved. Visit count:", tabData.visitCount);
});
// Get data from ALL open tabs running this script
GM_getTabs((allTabs) => {
// allTabs is { [tabId: number]: object }
for (const [tabId, data] of Object.entries(allTabs)) {
console.log(`Tab ${tabId}:`, data);
}
});
// Promise style
(async () => {
const data = await GM.getTab();
data.flag = true;
await GM.saveTab(data);
const all = await GM.getTabs();
console.log("All tabs:", all);
})();
```