Rootless

Automate iOS, iPadOS, and macOS using plain JavaScript. Build custom widgets and interact directly with native APIs.

Download on the App Store
Rootless app interface

Plain JavaScript

Supports ES6. Scripts are stored as plain .js files on your disk.

Native APIs & Documentation

Integrate directly with iOS native APIs. Fully documented, available offline.

Siri Shortcuts

Trigger scripts via Siri. Present tables, websites, and custom HTML natively.

System Integration

Run from the Share Sheet, process inputs, and manage local files via Files.app.

x-callback-url

Communicate seamlessly and trigger workflows with other apps on your device.

Customizable & Ready

Tailor the code editor to your liking. Includes several example scripts to start immediately.

Documentation

Also inside the app, or as rootless.json.

WebView

Load a page and read from it

Loads a page and runs JavaScript inside it, which reaches anything a browser can see. Use WebView.read to load a page and pull one value out; the constructor is for asking several questions of one page. It can also show the page. Every call blocks until the page or the script finishes. In-app only: a widget has no view hierarchy to build one in, so check WebView.isAvailable. A web view is heavy; call close() when you are done rather than leaving several open.

Properties

isAvailableBoolean

False in a widget.

Methods

.loadURL(url, options?)RootlessWebView

Loads a page and blocks until it has finished.

  • url String required

    The page to load.

  • options Any
    • timeout Duration

      How long to wait. Default 30 seconds.

.loadHTML(html, options?)RootlessWebView

Loads markup instead of fetching a page.

  • html String required

    The markup.

  • options Any
    • baseURL String

      Where relative links and assets resolve from.

    • timeout Duration

      How long to wait for the load.

.evaluate(script)Any

Runs JavaScript inside the loaded page and returns its result.

  • script String required

    The last expression is what comes back.

returns Anything JSON-able. A DOM node or a function does not cross and comes back null.

.present(options?)RootlessWebView

Shows the loaded page as a bottom sheet, and returns when it is dismissed.

  • options Any
    • detents [Any]

      The heights it can rest at: "medium", "large", or a fraction between 0 and 1.

    • grabber Boolean

      Show the drag handle at the top.

    • cornerRadius Number

      Corner radius of the sheet.

.close()

Releases the web view. Worth doing explicitly: they are not small.

WebView()RootlessWebView

Create a web view.

WebView.read(url, script, options?)Any

Loads a page, evaluates the script in it, returns the result, and throws the view away.

  • url String required

    The page to load.

  • script String required

    JavaScript evaluated in the page. Its last expression is the result.

  • options Any
    • timeout Duration

      How long to wait for the load and the script. Default 30 seconds.

    • baseURL String

      Resolves relative URLs when the page is passed as HTML rather than fetched.

Examples

Scraping one value

// A site with no API at all
var price = WebView.read(
  "https://example.com/product",
  "document.querySelector('.price').innerText"
);

Script.setWidget(new Widget({ child: Text(price, { font: Font.TITLE }) }));

Several questions, one page

var web = new WebView();
web.loadURL("https://example.com");

var title = web.evaluate("document.title");
var links = web.evaluate(
  "Array.from(document.querySelectorAll('a')).slice(0,5).map(a => a.href)"
);
web.close();