Skip to main content
Stay up to date with the latest changes to Figranium. For documentation changes, see the source repository directly.
This week

Features

API trigger endpoint now accepts bodyless requests

POST /api/tasks/:id/api no longer requires a JSON body or a Content-Type: application/json header. Requests without a parsed body are treated as {} and the task runs with its default variables. Tools that can’t set request headers on outbound calls (for example, Clay’s HTTP action) can now trigger a task with a bare POST to the endpoint URL.To pass variables, webhookUrl, statelessExecution, or sessionId, keep sending Content-Type: application/json with a JSON body — that path is unchanged.

Full endpoint URL and method in the API trigger panel

The task editor’s Trigger via API panel now shows the complete origin-aware endpoint URL (for example, https://your-figranium.example.com/api/tasks/task_1/api) with a POST method badge next to it. The copy button copies the same full URL, so you can paste it straight into external tools without prefixing your instance origin by hand.See REST API Reference — POST /api/tasks/:id/api.
Earlier this week

Features

Opt-in CloakBrowser browser engine

Figranium now ships two interchangeable browser engines behind the same Playwright API, and you can switch between them with a single environment variable. Agent, Headful, and CLI-launched tasks all use whichever engine is active — no task edits required.
  • Default (USE_CLOAK_ENGINE unset or false): Playwright Chromium patched at the JS level with playwright-extra and puppeteer-extra-plugin-stealth. Same behavior as previous releases.
  • Opt-in (USE_CLOAK_ENGINE=true): the CloakBrowser stealth-patched Chromium binary. Evasions are applied at the binary level rather than injected at runtime, which is harder for modern bot detectors to fingerprint. Use this when the default stack is being detected on a target site — typically CAPTCHA walls that trigger on Playwright/Chromium runtime tells.
  • License key: set CLOAKBROWSER_LICENSE_KEY to unlock the latest stealth binary. Without a key, CloakBrowser falls back to the free legacy binary. You can also run npx cloakbrowser login to write the key to ~/.cloakbrowser/license.key, which cloakbrowser reads natively.
  • Lean installs: the CloakBrowser binary is only fetched during postinstall when the flag is enabled, so the default install stays the same size as before.
.env
See Stealth & Anti-Detection — Browser Engine and Configuration for the full switch behavior and env-var reference.Agent tasks now click through common cookie-consent banners for you before your first action block runs. Figranium injects the community-maintained idcac-playwright ruleset (a port of the “I don’t care about cookies” extension) into every page in the Agent browser context on domcontentloaded.
  • Covers hundreds of providers (OneTrust, Cookiebot, TrustArc, Quantcast, and more). The script always clicks reject or close — never accept.
  • Always on in Agent mode. Headful mode is unchanged (it’s for human interaction), and Scrape mode doesn’t render banners because it no longer launches a browser.
  • If no matching banner is present, the script silently no-ops so your task runs as usual. If a specific site’s dialog isn’t covered, you can still author an explicit Click block.
See Stealth & Anti-Detection — Cookie-Consent Auto-Dismissal for details.

Changes

Scrape mode is now browserless (no screenshots or video)

Scrape mode has been rewritten as a lightweight HTTP fetch. It now issues the request through got-scraping (with the same proxy pool and user-agent rotation as before) and parses the response with Cheerio, instead of spinning up a Playwright/stealth-Chromium browser for each run.
  • Faster and cheaper: No browser process means dramatically lower CPU, memory, and cold-start cost per scrape.
  • Preserved: Selector extraction, HTML cleanup, link extraction, proxy and user-agent rotation, the headful → scrape cookie handoff, and the sandboxed extraction-worker script pipeline all still work exactly as before.
  • Removed: No screenshots and no video recordings in Scrape mode. There is no page to photograph. The Results panel’s Screenshot pane now shows “Scrape mode does not support screenshots” instead of the misleading “Waiting for Frame…” placeholder. If you need visual evidence of the page, run the task in Agent mode.
See Captures & Storage and Architecture for the updated behavior.
Earlier this week

Features

Visual field-mapping mode for extraction scripts

The Extraction Script editor (both the canvas block and the Extraction tab in Task Settings) now opens in a new Visual mode by default. You describe the data you want as a list of named fields with a selector, an attribute type (Text, HTML, Input Value, or Attribute), and an optional Multiple (list) toggle. Figranium generates the underlying JavaScript for you and keeps it in sync as you edit — no raw code required for typical scraping tasks.
  • The mode toggle at the top of the editor flips between Visual and JavaScript. The selected mode now has a solid fill so it’s obvious which one is active.
  • Every field has a target icon that hands off to the Headful Browser inspector. Click an element on the page and the selector, plus a row of alternative candidates, get written back into the field.
  • Playwright-only :has-text(...) selector candidates are filtered out of the pick list for extraction fields only. Extraction scripts run through native document.querySelector, which does not understand that pseudo-selector, so surfacing it would have produced selectors that returned null at extraction time. Action blocks (Click, Type, etc.) still receive the full candidate list because Playwright runs those.
  • Switching to JavaScript mode surfaces the auto-generated script in the code editor, still fully editable. Existing hand-written extraction scripts open in JavaScript mode automatically so your code is never hidden behind an empty field list.
  • The canvas Extraction Script modal no longer closes when you click the backdrop, so a stray click on the dimmed area outside the modal will not throw away in-progress edits. Use the Done button or the close icon in the header to save and dismiss.
See Extraction Scripts — Visual field mapping for the full field reference and an end-to-end example.
Earlier update

Updates

Agent Mode description clarified in Task Settings

The mode picker in the Task Settings cabinet previously described Agent Mode as “Autonomous decision making,” which suggested the runner would decide steps on its own at execution time. That was misleading: Agent Mode runs a fixed sequence of action blocks that you author, and any branching comes from explicit control-flow blocks (If, While, Loop, etc.) on the canvas.
  • The label under Agent Mode now reads “Custom action sequence with logic.”
  • No behavior change. If you were choosing Scraper Mode because you didn’t want the runner making its own decisions, you can safely use Agent Mode — the same author-defined blocks execute in the same order on every run.
  • If you want an actual AI-driven, decision-making runner, that lives in MCP Integration, not in Agent Mode.
Earlier update

Updates

headless flag and automatic fallback for POST /api/browser/open

The programmatic browser launch endpoint now accepts a headless boolean and recovers automatically when no display server is available.
  • Pass "headless": true in the request body to launch Chromium without a display. This is the right choice when you run Figranium directly on a Mac (outside Docker) or on a headless CI runner. The HEADLESS environment variable is also honored.
  • If you don’t set headless and the initial headful launch fails because there is no display, Figranium retries once in headless mode and returns the running session. External orchestrators no longer have to detect HEADFUL_DISPLAY_UNAVAILABLE and reissue the call themselves.
  • The display-unavailable detector now also matches no display server, X11 connection failed, cannot open display, and unexpected target closed errors during launch, so the fallback triggers on Mac hosts where the underlying error text differs from Linux.
See REST API — POST /api/browser/open for the full request and error schema.

Bug fixes

  • Headful VNC viewer no longer gets stuck on “Reconnecting…”start-vnc.sh was embedding literal double-quote characters into the x11vnc -passwd argument because of unquoted shell word-splitting, so the password x11vnc actually enforced never matched the one served to the noVNC client. Every connection attempt failed authentication and dropped immediately, which showed up in the UI as an endless reconnect loop. The password is now passed through a bash array as a single unmodified argument. If you were affected, pull the latest image and reopen the headful session — no config change is required.
  • Proxy credentials pasted as a full URL are now split out on add — Pasting http://user:pass@host:port into Settings > Proxies > Add Proxy > Server previously stored the whole URL (credentials included) as the server value, which surfaced as a duplicate-looking entry in the list and failed upstream authentication in rotation pools. normalizeProxy now extracts embedded credentials into username and password on both the add and bulk-import paths. Existing broken entries self-heal on next read — no manual cleanup needed. See Proxy Rotation — Adding a proxy.
  • Backdrop blur restored on modals and overlay panels in Dark and Solarized Dark themes — A dark-theme CSS override was force-replacing translucent bg-black/NN backgrounds with a fully opaque color, defeating backdrop-blur on the Task Settings panel, the confirm modal, and other overlays. The override has been removed, and the confirm modal now uses a translucent theme-aware background instead of a hardcoded opaque one.
  • Browser open and inspector highlight on Mac — Launching the managed browser session from POST /api/browser/open and resolving a targetHint through POST /api/inspector/highlight now work when Figranium runs on macOS. Chromium is launched without the --disable-gpu, --window-position=0,0, and --start-maximized flags on Darwin, which were causing the process to exit before the first page was ready. The CDP Browser.setWindowBounds maximize call is also skipped on Darwin. Selector generation, XPath resolution, and the top-match highlight overlay for /api/inspector/highlight now run in a single in-page evaluation, so they don’t lose the element handle to a mid-flight page navigation.
  • GitHub star prompt no longer appears on first run — The in-app prompt asking you to star the Figranium repo is now gated on both 3+ successful task runs and 3 days since your first run (tracked locally in the browser). It also uses a quick slide-in animation instead of the previous fade so it’s easier to notice when it does appear. Dismissing or clicking through still permanently silences it.
Earlier update

Updates

Single self-theming brand icon

The Figranium mark at public/figranium_icon.svg is now a single SVG that adapts to the viewer’s color scheme, instead of shipping as separate dark and light variants.
  • The mark fills black by default and switches to white inside @media (prefers-color-scheme: dark), so it stays legible on both light and dark surfaces.
  • Use this file when you can only supply one logo URL — for example, third-party integrations, README embeds, or partner directories that accept a single <img src>.
  • No configuration change is required. Existing embeds keep working; you can drop the separate dark/light variants from your integration if you were maintaining both.
If your embedding surface forces a fixed background and ignores the OS color scheme, keep pointing at whichever variant matches that background.
Earlier update

Features

Multi-theme support

Figranium now ships with four selectable UI themes: Dark (default), Light, Solarized Light, and Solarized Dark.
  • Switch themes from Settings → System → Theme. Each option shows a preview image plus a surface and accent color swatch.
  • The choice is stored in the browser’s local storage (figranium.theme), so it persists across reloads on the same device.
  • The first time you open Figranium after upgrading, a one-time picker prompts you to choose a theme. Dismissing it also persists locally and it will not appear again.
  • Themes are implemented as CSS custom properties (--app-bg, --app-surface, --app-accent, and the full syntax-highlight palette), so the whole UI — including code blocks — retunes for readability under each background.
See UI Tour — System settings for the switcher location.

Authenticated programmatic browser & inspector API

The programmatic browser endpoints introduced in the previous release now require authentication and are safe to expose to external orchestrators (MCP servers, custom agents, CLIs).
  • POST /api/browser/open launches or reattaches a managed headful session and returns { sessionId, status, wsEndpoint }.
  • POST /api/inspector/highlight activates the inspect overlay on the active session and, given a targetHint, returns up to five candidate elements with CSS selectors, XPath, confidence scores, and an optional base64 JPEG snapshot of the viewport.
  • PATCH /api/tasks/:id performs a partial update on a task. Figranium snapshots the current task into the version history before applying the change.
  • DELETE /api/tasks/:id now also removes any in-process schedule registered for the task, so a scheduled run cannot fire after deletion.
Every endpoint accepts either a signed-in dashboard session or an API key (x-api-key, Authorization: Bearer, or an apiKey body field). External callers should use the API-key path.
See REST API — Browser and REST API — Inspector for full request and error schemas.

Security

VNC and websockify path hardening

  • The noVNC/websockify proxy path now requires authentication before it will accept an upgrade or serve public/novnc.html. Unauthenticated attempts are dropped.
  • websockify binds to the IPv4 loopback (127.0.0.1) explicitly, closing a mismatch where Docker on macOS could bind unpredictably across IPv4/IPv6 loopback and leave the VNC stream unreachable or unexpectedly reachable.
  • sessionId and taskId are strictly validated before they are used to look up files on disk, closing a path-traversal edge case.
  • Raw cron ranges are now validated for correct ordering as well as bounds, so a malformed field cannot slip past the scheduler.
If you built a custom client that reached /websockify directly, update it to authenticate with a session cookie or an API key. See Headful browser — Access control and Security — Headful / VNC access control.

Bug fixes

  • Captures now surface reliably — Runs no longer produce screenshots or recordings that fail to appear in the UI. The capture read path in server.js and src/server/routes/data.js now matches the actual write path, and captures are also served from the alternate public/captures location used inside Docker.
  • Captures survive container restarts — Runtime capture artifacts persist to a host volume instead of being lost when the container is recreated.
  • Persistent browser session ID — Session IDs are stored across reconnects instead of being regenerated on every new session, so external tooling that pins to a sessionId stays valid.
  • Mac/Docker WebSocket disconnects — Loopback WebSocket connections used by the headful viewer no longer drop on Mac hosts, and the HeadfulModal no longer flashes its loading state during a normal reconnect.
  • Apple Silicon headful browser “Connecting… Disconnected” loop — The GHCR publish workflow now builds and pushes a true multi-architecture image (linux/amd64 and linux/arm64). Apple Silicon Macs pull the native ARM64 image instead of running the AMD64 image under Docker Desktop’s QEMU emulation, where Xvfb and x11vnc were prone to crashing seconds after start. That crash also silently broke the selector-picker SSE stream, which shares the same headful browser session.
  • Headful viewer auto-reconnect — Xvfb, x11vnc, and websockify each now run inside restart loops (with per-process logs under data/xvfb.log, data/x11vnc.log, and data/novnc.log), and the noVNC page auto-reconnects with backoff on RFB disconnect. A quick post-connect drop is now surfaced as “Browser session crashed, retrying…” instead of a plain “Reconnecting…” so a genuine crash is visually distinguishable from a normal reconnect.
  • Theme contrast fixes — Dot-grid canvas background, theme-accent buttons, and previously hardcoded blue accent text (API keys, Add API Key button) are readable across all four themes; syntax-highlight colors were retuned to meet WCAG AA contrast on every theme’s actual code background.

Updates

Exported task filename

Exported task bundles are now named figranium-tasks-<date>.json (previously doppelganger-tasks-...).

Font change

The UI now uses Space Mono in place of JetBrains Mono. Custom stylesheets that referenced the old font family should be updated.

Under the hood: CAPTCHA detection scaffolding

Figranium 0.14.0 lands the foundation for a future human-handoff CAPTCHA workflow. This release includes only the internal engine layer — a DOM/shadow-DOM/iframe observer that classifies interactive elements (slider, audio, grid, rotational, distorted-text, widget-frame, form), a 2 GB memory guardrail (os.totalmem() plus cgroup v1/v2 limits), and typed handoff interfaces (onCaptchaDetected, pauseForHuman, submitSolution) that pipe an externally supplied solution into the existing human-like mouse trajectory generator.There is no automated solver and no user-facing API for this yet — the module ships as internal scaffolding only. Tasks continue to pause for manual intervention through the headful browser as they do today.
Earlier update

Features

Model Context Protocol (MCP) server

Figranium now ships an official MCP server so LLM clients like Claude Desktop, Cursor, and Manus AI can discover, run, inspect, and schedule Figranium tasks directly.
  • Prebuilt image: pull ghcr.io/figranium/figranium-mcp:latest — no Node.js install or local clone required.
  • STDIO transport: works with any MCP-compatible client over the standard STDIO transport.
  • Point at your instance: configure FIGRANIUM_BASE_URL and FIGRANIUM_API_KEY in the client’s MCP server config. Use http://host.docker.internal:11345 when Figranium runs on the same host.
  • Registry namespace: clients that support automatic registry resolution can install it as io.github.figranium/figranium-mcp.
See MCP Integration for client-by-client setup, the available tools, and local development instructions.
Earlier update

Features

Named session snapshots (sessionId)

Tasks and API-triggered runs now accept a sessionId field that persists browser cookies and local storage to a dedicated snapshot file per name.
  • Pass sessionId: "acct-alice" on a run and Figranium loads data/sessions/acct-alice.json as the browser’s initial storage state. After the run, the current state is written back to the same file.
  • Different sessionId values give you fully isolated logged-in identities on the same target — one per customer, tenant, or account, without touching the shared profile directories.
  • sessionId is sanitized to [a-zA-Z0-9_-]; other characters are stripped for path safety.
  • Combining sessionId with statelessExecution: true keeps the run stateless — the snapshot is not written.
See Named Session Snapshots for the full walkthrough and POST /api/tasks/:id/api for the API field.

Updates

Async and top-level return in Run JavaScript

The Run JavaScript action block now wraps your code in an async function, so top-level await and top-level return work directly. Existing scripts that used plain expressions or return from eval continue to work — the block falls back to the previous behavior if the async wrapper cannot compile the code.See JavaScript Execution for examples.
Earlier update

Security

Hardened VNC and websockify access

Unauthenticated access to the headful browser’s VNC stack is now closed. This affects anyone who was reaching the VNC or noVNC ports directly (for example, from a custom client or an exposed Docker port).
  • Localhost-only binding: both x11vnc (port 5900) and websockify/noVNC (NOVNC_PORT, default 54311) now listen on 127.0.0.1 only. Publishing these ports on the Docker host no longer exposes them.
  • Password-protected VNC: x11vnc requires a random password generated on first start and stored at data/vnc_password.txt. The embedded viewer fetches it automatically from the new authenticated endpoint GET /api/headful/vnc-password.
  • Authenticated /websockify upgrades: every WebSocket upgrade to /websockify on the main Figranium port must pass the IP allowlist, an Origin/Host match (CSWSH protection), and present either a session cookie or an API key. Unauthenticated attempts are dropped and logged.
What this means for you: if you use the headful browser through the Figranium UI, nothing changes — the embedded viewer authenticates automatically. If you built a custom VNC client that connected directly to port 54311 or 5900, update it to proxy through wss://<host>:11345/websockify with an API key (?apiKey=... or x-api-key header). Retrieve the VNC password from GET /api/headful/vnc-password.See Headful browser — Access control and Security — Headful / VNC access control for the full details.
Earlier update

Updates

Expanded PostgreSQL storage

PostgreSQL is now a first-class backend for nearly all Figranium configuration, not just tasks and logs.
  • More data in Postgres: proxy configuration, saved credentials, AI model selections, and Ollama API keys are now persisted in the database when DB_TYPE=postgres.
  • SSL support: a new DB_POSTGRESDB_SSL=true environment variable enables encrypted connections to managed Postgres providers (RDS, Cloud SQL, Supabase, Neon, etc.).
  • Longer API keys: API key columns are now TEXT instead of VARCHAR(255), and existing tables are migrated automatically on startup.
  • Graceful fallback: if the database is unreachable at startup, Figranium falls back to file-based storage.
See PostgreSQL Support for the full configuration reference.

Expanded SSRF protection

The default SSRF blocklist now covers a much broader set of internal and reserved network addresses, hardening Figranium against requests that target internal infrastructure.
  • More IPv4 ranges blocked by default: in addition to RFC 1918 private ranges and loopback, Figranium now blocks IETF protocol assignments (192.0.0.0/24), TEST-NET ranges, benchmarking (198.18.0.0/15), shared CGN space (100.64.0.0/10), multicast, and other reserved space.
  • Full IPv6 coverage: loopback (::1/128), unique local (fc00::/7), link-local (fe80::/10), unspecified, and multicast ranges are blocked.
  • Hostname blocking: localhost, *.localhost, and host.docker.internal are blocked unless ALLOW_PRIVATE_NETWORKS=true.
  • Proxy server validation: proxy URLs added through Settings or the API are validated against the same blocklist. Invalid entries are rejected with INVALID_URL, and bulk imports fail atomically if any entry is unsafe.
  • Ollama URL validation: Ollama base URLs are validated both at save time and again at request time, with every redirect hop re-checked and sensitive headers stripped on cross-origin redirects.
  • Output provider credentials: baseUrl values (e.g. Baserow) are validated when credentials are saved, rejecting unsafe URLs with INVALID_BASE_URL.
  • Redirect protection: outbound webhook and output provider requests now validate every hop in an HTTP 3xx chain (up to 5 redirects).
What this means for you: if you previously pointed Figranium at a service on localhost, host.docker.internal, or any private network, you’ll need to set ALLOW_PRIVATE_NETWORKS=true for local development. Production deployments are protected by default with no configuration required.See Security for the full list of blocked ranges and configuration details.

Gemini API key transport

Gemini API keys are now sent via the x-goog-api-key HTTP header instead of the ?key= query parameter, preventing keys from leaking through server access logs, reverse-proxy logs, or Referer headers. No configuration is required.If you previously relied on the ?key= form for log inspection or proxy filtering, update your tooling accordingly.