Ikun Scripts

Writing guide

Scripts published here install in Ikun Browser. The client is close to a userscript manager, but not a full desktop one. Check the rules below before publishing so installs and updates do not fail.

The site language is a directory in the URL, such as /zh-CN/, /zh-TW/, /ja/, /ko/, /id/, and /en/. Lists show scripts in that language by default. The install URL /s/id.user.js has no language directory.

Publishing

  1. Sign up and log in.
  2. Open Publish and paste the full source. It must include an ==UserScript== header.
  3. To update, open Publish a new version on that script and paste the new source. Do not change the script ID, or installed users will not get the update.

At most 50 scripts per person. Once unlisted, the install link returns 404 and the script disappears from search.

Smallest working script

// ==UserScript==
// @name         Example script
// @namespace    https://scripts.ikunbrowser.com
// @version      1.0.0
// @description  Add a line on the example page
// @match        https://example.com/*
// @grant        none
// ==/UserScript==

(function () {
  document.body.insertAdjacentHTML("beforeend", "<p>Example script ran</p>");
})();

Metadata

You need @name, plus @match or @include.

FieldNotes
@nameA name without a language suffix wins. If there are only localized names such as @name:zh-CN, the first one is used.
@name:zh-CN @description:jaA name and description for one language. That directory shows them first. If there is no plain @name, the first localized name decides the script language.
@namespace @version @descriptionWrite all of them. @description:xx is used only when there is no default description.
@matchChrome match patterns. *://, *.example.com, and <all_urls> work. The site page lists scripts by the domains in these rules, for example /scripts/by-site/example.com.
@include @excludeWildcards * and ?, or /regex/i.
@exclude-matchExclude with match rules.
@run-atdocument-start / document-end / document-body / document-idle. Omitted means idle.
@noframesDoes not run in subframes.
@grantUnknown grants do not block installation. Unimplemented functions exist and do nothing.
@require @resourcehttp or https only, at most 8 each. data:, file:, and relative paths fail to install.
@connect @icon @authorIgnored by the client and does not affect installation.

At most 64 match rules and 64 exclude rules. Each @require is at most 512KB, about 1MB combined. Each @resource is at most 256KB.

Updates

The client does not compare semantic versions. After trimming, the new @version string must differ from the current one. The script is replaced only when the user checks for updates manually. Two empty versions also count as unchanged.

When serving /s/{id}.user.js, this site inserts @downloadURL and @updateURL at the start of the metadata block, both pointing at that URL. The client reads only the first one, so an update URL you write later is ignored. Do not point @updateURL at .meta.js. The client skips that kind of URL.

The browser does not update in the background. Users check manually in Settings → Userscripts.

Install link

The Install button on the detail page is a normal .user.js link. Ikun Browser intercepts any http(s) URL ending in .user.js and shows a confirmation. No extra protocol is required.

Greasy Fork style URLs also work: /scripts/id.user.js, /scripts/id.meta.js, /scripts/id/code/name.user.js, the /scripts/id-name page, and /scripts/id.json. The update URL given to Ikun Browser stays /s/id.user.js.

The same script, day, and IP counts as one install.

APIs the client supports

Both synchronous GM_* and Promise-style GM.* are injected. The script runs in the page context. unsafeWindow is the page window. There is no separate sandbox.

APIBehavior
GM_addStyle GM_addElementInsert a style or an element.
GM_getValueStored locally and isolated per script. One value is at most 32KB. Change listeners stay on the current page and do not cross tabs.
GM_xmlhttpRequestSupports common methods plus arraybuffer / blob. Request bodies are at most 256KB and responses at most 1MB. Public http(s) only; local addresses are rejected. It does not go through page JS or the browser proxy.
GM_setClipboard GM_download GM_openInTabClipboard, in-app download confirmation, and opening http(s) in a new tab.
GM_getResourceText GM_getResourceURLRead resources cached at install time.
GM_registerMenuCommandIf the current page registers a command, the bottom bar shows Script commands.
GM_notificationShows a toast only. There is no click callback.
GM_getTabOnly an in-memory object in the current script process, not multiple windows.

These still install if you @grant them, but the functions do nothing: GM_cookie, GM_webRequest, and any grant not listed above. Do not rely on rewriting requests or reading and writing cookies.

Runtime notes

What kind of script fits

A good fit: change the DOM, add CSS, store a little config, make occasional requests, use the clipboard, download a file, toggle from a menu, and load something like jQuery with @require.

A poor fit: heavy Cookie use, intercepting network requests, needing the exact start of the document, a strict page CSP, or a very large script and dependencies.