multipleof4andClaude Opus 5.5 9b80284519 Add OpenScript.button popup actions and release 1.0.6
Scripts can register buttons at runtime with OpenScript.button(label, onClick).
The popup lists buttons from scripts running in the active tab via
chrome.userScripts.execute in each script's world, and clicking one runs
the handler in the page before closing the popup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 07:14:51 -07:00
2026-09-12 22:14:22 -07:00
2026-09-10 19:42:48 -07:00

OpenScript

A lightweight, modern script manager built for Chrome Manifest V3 with the native chrome.userScripts API.

Install from Chrome Web Store

Empty state Scripts Secrets
OpenScript empty state OpenScript scripts OpenScript secrets

Prerequisites

OpenScript requires Chrome 138 or newer. To run scripts:

  1. Install OpenScript from the Chrome Web Store.
  2. Open chrome://extensions.
  3. Select Details on the OpenScript extension card.
  4. Enable Allow User Scripts.

Writing scripts

Scripts use a small metadata block followed by ordinary JavaScript. OpenScript supplies the async wrapper, so top-level await, return, and isolated declarations work without boilerplate.

// ==UserScript==
// @name         GitHub Repo Stats
// @version      1.0.0
// @description  Logs repository metadata
// @match        https://github.com/*
// @run-at       document_idle
// ==/UserScript==

const [, owner, repo] = location.pathname.split('/');
if (!owner || !repo) return;

const response = await fetch(`https://api.github.com/repos/${owner}/${repo}`);
console.log(await response.json());

Metadata

Directive Description Required
@name Name displayed in the popup Yes
@version Version displayed beside the script name No
@match Chrome match pattern; repeat for multiple patterns Yes
@description Short summary displayed in the popup No
@run-at document_idle, document_start, or document_end No
@require HTTP(S) library URL; repeat for multiple libraries No

The editor’s run-at selector is authoritative when a script is saved. Bare match URLs are normalized: github.com/* becomes *://github.com/*, and https://github.com becomes https://github.com/*.

Secrets and environment variables

Secrets saved in the popup are synchronized through chrome.storage.sync and exposed to every script through either namespace:

const token = OpenScript.env.GH_PAT;
const sameToken = env.GH_PAT;

Per-script storage

Every script gets isolated, persistent storage backed by chrome.storage.local:

await OpenScript.storage.set('repo_cache', { size: 1024 });
const cached = await OpenScript.storage.get('repo_cache'); // undefined when absent
const keys = await OpenScript.storage.list();
await OpenScript.storage.delete('repo_cache');

Stored keys are scoped to the current script and survive reloads and browser restarts. Orphaned values are removed when the popup opens after their script has been deleted.

Cross-origin network requests

Make cross-origin requests that bypass page CORS and CSP restrictions using the extension's privileged background worker:

const response = await OpenScript.fetch('https://api.example.com/data', {
  headers: { Accept: 'application/json' },
  credentials: 'include', // includes browser cookies for the target domain
});
const data = await response.json();

OpenScript.fetch(url, options) returns a native Response instance supporting .json(), .text(), .arrayBuffer(), .blob(), .status, .ok, and .headers. See the Cross-origin fetch guide for full options and examples.

Popup buttons

Scripts can add buttons under their entry in the popup's Scripts tab, for example to open a settings panel or trigger an action on the current page:

OpenScript.button('Settings', () => openSettingsPanel());

if (location.pathname.startsWith('/issues'))
  OpenScript.button('Export issues', exportIssues);

const remove = OpenScript.button('One-time action', doThing);
remove(); // takes the button away again

Buttons are registered at runtime, so they show only for scripts running on the active tab. A script that matches *://*/* therefore shows its buttons on any regular web page, but not on pages where Chrome blocks user scripts, such as chrome:// pages and the Chrome Web Store. Clicking a button runs its handler inside the page in the script's world, then closes the popup.

External libraries

Use @require to cache libraries when a script is saved:

// ==UserScript==
// @name         Alerts
// @match        *://*/*
// @require      https://cdn.jsdelivr.net/npm/sweetalert2@11
// ==/UserScript==

await Swal.fire('OpenScript is ready');

Libraries are prepended in declaration order inside the isolated USER_SCRIPT world. The cached source avoids page CSP restrictions and remains available offline. If a refresh fails, OpenScript uses the last cached copy; a script with a dependency that has never been cached is not registered.

Development

npm install
npm run dev
npm test
npm run build
npm run build:icons
npm run zip

Privacy

OpenScript does not track users or send analytics. Script code and per-script state stay in chrome.storage.local; secrets use chrome.storage.sync. URLs declared with @require are contacted only to download their requested libraries. See the Privacy Policy.

S
Description
A lightweight user script manager - browser extension for chrome
Readme
2.6 MiB
Languages
JavaScript 98.6%
CSS 0.8%
HTML 0.6%