Docs

Writing Automations

A browser automation is a small .js file that drives a browser tab. This page is the reference for writing your own — the tranquil API you script against, and the patterns the shipped examples use. If you haven’t run one yet, start with Running Automations and Your First Automation; this page goes deeper.

Browser automations vs. workflows. This page is about browser automations — scripts you run inside the desktop app against a live page. Tranquil also has workflows: @tranquil/sdk programs that run headless on the Engine, on a schedule or webhook. Those are a separate topic — see Engine.

Dev preview — not stable. Tranquil is in early, active development. Everything here — APIs, interfaces, and behavior — is provisional and will change before a stable release, often without notice or backward compatibility. Don’t build anything you depend on against it.

Where automations live

Scripts live as .js files under Automations/browser/ in the guided sample project (open it with File → New Default Window). Any .js file works, though — put yours wherever you like in your project and run it the same way.

How a script runs

Your script runs in Tranquil (a Node/Atom context), not in the web page. The runner injects five globals into every script:

GlobalWhat it is
tranquilThe automation API (tabs, files, notifications, …) — documented below.
atomThe full Atom/Tranquil API, for anything tranquil doesn’t wrap.
requireNode require, for built-ins (path, fs, …) and installed modules.
__dirnameThe directory containing the running script (files resolve against it).
__filenameThe running script’s absolute path.

To touch the page itself — its document and window — you pass a function to tab.evaluate(). That function is serialized and runs inside the page; everything outside it runs in Tranquil:

const tab = await tranquil.getActiveTab();     // in Tranquil
const title = await tab.evaluate(() => {       // this callback runs IN THE PAGE
  return document.title;
});
tranquil.notify(title);                        // back in Tranquil

Each tab is a real Puppeteer Page, so beyond evaluate() you also get click(), type(), waitForSelector(), goto(), screenshot(), and the rest.

Running: with the .js editor focused (not the browser tab), press Cmd-Shift-R (tranquil-automations:run-in-webview). It runs the whole file, or — if you have text selected — just the selection, which makes it a quick REPL for experimenting a line at a time.

The tranquil API

Tabs

Every tab method returns a Puppeteer Page.

MethodReturnsDescription
getActiveTab()Promise<Page>The most recently viewed browser tab. Throws if none has been visited.
getTab(urlOrPattern)Promise<Page>An open tab matching an exact URL string or RegExp (waits up to 5 s).
getTabs()Promise<Page[]>All open http(s) tabs (excludes Tranquil’s own UI).
openTab(url)Promise<Page>Opens a new visible tab and resolves once it’s loaded (waits up to 10 s).
openBackgroundTab(url)Promise<Page>Loads a page in an off-screen webview (no visible tab) — for scraping or auth. Always closeTab() it when done.
closeTab(page)Promise<void>Closes a visible tab or destroys a background one.

Notifications

notify(message, level?) — shows a notification. level defaults to 'info'; valid levels are 'info', 'success', 'warning', 'error'.

tranquil.notify('Done!', 'success');

Files

Paths resolve against __dirname (the script’s own directory).

MethodReturnsDescription
writeFile(name, content)stringWrites the file; returns its absolute path.
readFile(name)stringReads a file as UTF-8.
openFile(path, options?)Promise<TextEditor>Opens a file in the editor. options passes through to atom.workspace.open — most usefully split: 'left' \| 'right' \| 'up' \| 'down'.

Everything else

MethodDescription
clipboard.read() / clipboard.write(text)Tranquil’s clipboard (distinct from the page clipboard inside evaluate).
getProjectDir()Absolute path of the first open project root, or ''.
exec(command)Runs a shell command (cwd = script dir); resolves with trimmed stdout.
config.get(key) / config.set(key, value)Persistent config that survives runs and restarts. Namespace keys (e.g. price-checker.lastPrice) to avoid collisions.
autoInject.register(urlPattern) / unregister()Re-run this script automatically whenever a matching URL finishes loading. Run once to register; persists across restarts.

Example catalog

These ship in Automations/browser/ — open one, focus a browser tab, and run it. Each shows a different shape.

Read the pagecount-elements.js:

// Notify how many of a tag are on the page (edit the selector as needed).
const tab = await tranquil.getActiveTab();
const count = await tab.evaluate(() => document.querySelectorAll('img').length);
tranquil.notify(`This page has ${count} image(s).`, 'info');

Restyle the pagereader-mode.js hides clutter and widens the main column:

// Rough "reader mode": hide common clutter and widen the main column.
const tab = await tranquil.getActiveTab();
await tab.evaluate(() => {
  document.querySelectorAll('header, footer, aside, nav, [role="banner"]').forEach((el) => {
    el.style.display = 'none';
  });
  const main = document.querySelector('main, article') || document.body;
  main.style.maxWidth = '720px';
  main.style.margin = '0 auto';
  main.style.fontSize = '18px';
  main.style.lineHeight = '1.6';
});

highlight-links.js is the same shape — it outlines every external link.

Toggle somethingpage-banner.js adds a banner, or removes it if it’s already there (run it again to toggle):

// Toggle a small "enhanced by Tranquil" banner on the active page.
const tab = await tranquil.getActiveTab();
await tab.evaluate(() => {
  const existing = document.getElementById('tranquil-banner');
  if (existing) { existing.remove(); return; }
  const el = document.createElement('p');
  el.id = 'tranquil-banner';
  el.textContent = 'This page was enhanced by a Tranquil automation.';
  el.style.cssText =
    'margin:1rem 0;padding:0.75rem 1rem;background:#f0f4ff;border:1px solid #c7d8ff;' +
    'border-radius:6px;font:14px Inter,sans-serif;color:#333';
  (document.querySelector('main') || document.body).prepend(el);
});

Scrape to a filepage-info.js reads stats from the page, writes them, and opens the result in the editor (writeFile + openFile):

// Scrape a few page stats and open them as a text file in the editor.
const tab = await tranquil.getActiveTab();
const stats = await tab.evaluate(() => {
  const links = document.querySelectorAll('a').length;
  const images = document.querySelectorAll('img').length;
  const headings = document.querySelectorAll('h1,h2,h3').length;
  return `${document.title}\n\nLinks: ${links}  |  Images: ${images}  |  Headings: ${headings}`;
});
await tranquil.openFile(tranquil.writeFile('page-info.txt', stats));

Patterns beyond one tab

  • Background scraping — pull data without a visible tab, then present it:

    const bg = await tranquil.openBackgroundTab('https://api.example.com/data');
    const data = await bg.evaluate(() => JSON.parse(document.body.innerText));
    await tranquil.closeTab(bg);
  • Multiple tabsgetTabs() for every open tab, or getTab(/pattern/) to target a specific one.

  • Auto-injection — call tranquil.autoInject.register(/example\.com/) once, and the script re-runs itself on every matching page load (same as pressing Cmd-Shift-R, but on the load event).

Debugging

console.log in the script body prints to the renderer DevTools (the app’s own dev tools). Logs inside tab.evaluate(() => { … }) run in the page, so they appear in that tab’s DevTools instead. Setup problems (like “no active browser tab”) surface as warning notifications; any other thrown error shows a red notification titled Script error in <file>.

Save it as a command

Once a script is useful, run “Automations: Register Current File” from the command palette (Cmd-Shift-P) with it focused. It becomes a permanent palette command named automatically from the filename — count-paragraphs.jsAutomations: Count Paragraphs — that targets the active tab and persists across restarts, no longer needing the file open. See Your First Automation for the walkthrough.


Next: Engine — the headless, scheduled kind of automation that runs in the cloud.