RTO_form_api.js

Core helper (recommended). Promise-based wrapper around the RTO postMessage protocol.
Docs updated: 2026-03-24

What it is

RTO_form_api.js is the foundation helper used by the documentation and most sample projects. It hides the raw window.postMessage protocol and gives you a clean async API: detect the extension, open and control tabs (by tabKey), and send predefined commands.

All methods return a Promise. Failures are normalized to an object like { code, message }.

Requirements

  • The RTO extension must be installed and enabled.
  • Your admin page origin must be allowed in the extension Allow-list.
  • Any target host you want to open or automate must also be allow-listed.
Best practice: always gate your UI with RTOForm.detect(1500). If detection fails, show a friendly “install / enable / allow-list this site” message.

Download

Download RTO_form_api.js

Minimal usage

This is the smallest “copy/paste” snippet that reliably works: detect the extension, then open a controlled tab using a stable tabKey.

<script src="../RTO_helpers/RTO_form_api.js"></script>
<script>
(async function () {
  try {
    // detect(timeoutMs:number)
    await RTOForm.detect(1500);

    // focus=true brings the tab/window to front.
    const res = await RTOForm.openTab(
      { "tabKey": "demo", "url": "https://example.com", "focus": true, "newTab": true },
      { "timeoutMs": 20000 }
    );

    // openTab returns tabId at the root (not inside data.*)
    console.log("Controlled tabId:", res && res.tabId);

  } catch (e) {
    console.error("RTO error:", e && e.code, e && e.message);
  }
})();
</script>
Note: RTOForm.openTab() forwards only url, focus and newTab. If you need to pass extra action fields supported by the extension, use send() (see below).
7.13.0 tip: keep one stable tabKey per workflow (auth, billing, monitor). Reusing the same tabKey now cleanly reuses the same controlled tab instead of creating near-simultaneous duplicates.

Optional configuration

Set these globals before loading RTO_form_api.js:

Global Type Default What it does
window.RTO_PAGE_ORIGIN string "rto-page" Value placed into outbound messages as origin
window.RTO_STRICT_ORIGIN boolean false If true, only accepts responses where the payload origin string matches the extension origin string.
window.RTO_TABKEY string (empty) Default tabKey if you omit it in calls.
window.tabKey string (empty) Legacy fallback for tabKey.
This helper does not support a configurable RTO_EXT_ORIGIN global.

API quick reference

Exports: window.RTOForm with these methods:

MethodPurposeTypical timeout
detect(timeoutMs)Fast check that the extension is listening.~1500ms
openTab(args, opts)Open/control a tab identified by tabKey.~20000ms
navigate(args, opts)Navigate an existing controlled tab.~20000ms
focusTab(args, opts)Bring the controlled tab to front.~5000ms
closeTab(args, opts)Close the controlled tab.~8000ms
listTabs(args, opts)List controlled tabs (debug/UI).~8000ms
registerMasterTab(args, opts)Register the current page tab as the master tab.~5000ms
focusMasterTab(args, opts)Ask the extension to activate the registered master tab.~7000ms
adoptTab(args, opts)Attach an existing tabId to a tabKey (advanced).~8000ms
command(msg, opts)Send a named predefined command (incl. advanced operations).~20000ms
send(type, payload, opts)Low-level: send any action type + payload.depends
bestEffort(promise, opts)Ignore selected errors for non-critical steps.n/a
onStatus(handler)Subscribe to tabStatus events posted by the extension (status stream).n/a
offStatus(handler)Unsubscribe a previously registered status handler.n/a
waitForStatus(filter, timeoutMs)Resolve with the next tabStatus event matching filter.timeoutMs default: ~15000ms
Master tab flow: call registerMasterTab() on your UI page, then later call focusMasterTab() from any flow to ask the extension to return to that page tab.

Advanced: using send()

Use send() when you need to pass action-specific fields that are not covered by the convenience wrappers. (send() forwards all payload fields except timeoutMs, which must be provided in opts.)

<script src="../RTO_helpers/RTO_form_api.js"></script>
<script>
(async function () {
  await RTOForm.detect(1500);

  // Low-level openTab with explicit timeout handling
  await RTOForm.send(
    "openTab",
    { "url": "https://example.com", "focus": true, "newTab": true },
    { "tabKey": "demo", "timeoutMs": 20000 }
  );
})();
</script>

Allow-list note

RTO_form_api.js is the core helper. If your page also manages the allow-list, use RTO_domainList.js on top of it. In 7.13.0, page-side allow-list additions go through allowlistAddRequest and the user confirms on the matching master tab.

tabStatus events (status stream)

Subscribe to the extension's tab lifecycle stream (activation, URL changes, loading/complete…).

<script src="../RTO_helpers/RTO_form_api.js"></script>
<script>
(function () {
  function log(ev) {
    if (ev && ev.type === "tabStatus") console.log("tabStatus:", ev);
  }

  RTOForm.onStatus(log);

  // Example: wait until a given tabKey reports "complete"
  RTOForm.waitForStatus(function (ev) {
    return ev && ev.type === "tabStatus" && ev.tabKey === "demo" && ev.event === "complete";
  }, 15000).then(function (ev) {
    console.log("demo tab is complete:", ev);
  });
})();
</script>

Common errors

CodeMeaningTypical fix
EXT_NOT_DETECTED The extension did not respond. Check install/enable, then gate with RTOForm.detect(1500) and show guidance.
DOMAIN_NOT_ALLOWED Target host is not allow-listed. Add the host in the extension Allow-list, then retry.
NO_CONTROLLED_TAB No tab is controlled for this tabKey. Call openTab() first (or adoptTab()), verify tabKey.
TIMEOUT No response within timeout. Increase timeoutMs, confirm the tab finished loading, and retry.

Next