Docs MCP server
The MCP server, every tool
Claude, or any client that speaks the Model Context Protocol, gets the same reach as the Mosaic window: it can make profiles, start them, and read and click the page in front of them. This list is read from the server’s own tool table at every build.
- Endpoint
http://127.0.0.1:39218/mcp- Routes
- 194
- MCP tools
- 168
- Plan
- Pro
Connecting an assistant
- In Mosaic, open Settings › MCP and turn the server on. It is off until you do, because its tools start browsers that hold logged-in sessions.
- Make an API key on the API screen. The MCP server takes the same keys as the REST API.
- A client that speaks HTTP posts JSON-RPC to
http://127.0.0.1:39218/mcpwithAuthorization: Bearer <key>. A client that only launches a local command, such as Claude Desktop, runs the stdio bridge Mosaic writes, with the key inMOSAIC_API_KEY; Settings › MCP shows the config to paste.
The server listens on 127.0.0.1 only, so the assistant runs on the same computer as Mosaic. It is part of Pro, like the REST API.
The page tools read a page from an isolated world and never enable the DevTools Runtime domain, which we measured turning a detector’s verdict to “bot”. Clicks and keys go through the same human-input code the warm-up robot uses.
- Driving a page 29
- Tabs and windows 12
- Fingerprints 8
- Warm-up and checks 12
- Trash and backups 8
- Cookies, logins and bookmarks 19
- Presets and extensions 9
- Proxies and providers 26
- Profiles and projects 26
- The app 19
Driving a page 29
Read a running profile’s page as a tree of refs and act on it: clicks, typing with human timing, waits, the network and the console. None of it enables CDP Runtime.
type_text
Type into whatever is focused in a running profile, as a person would — per-key delays, occasional typos that are then corrected, and real key events rather than a paste. It matters because a profile that browses like a person for a month and then fills a login in one input event has told the site something no fingerprint work takes back. For a saved password or a 2FA code use fill_credential, which never returns the secret. Click the field first with click_element: typing goes to whatever the page has focused, and a click that lands on a wrapper leaves it going to document.body.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id; it has to be running |
textrequired | string | What to type |
charactersPerMinute | number | Mean speed. 200–400 is ordinary, 500+ is a fast typist. |
typoRate | number | Chance per character of a wrong key that is then corrected, 0–0.1 |
thinkingPauses | boolean | Longer pauses now and then, as if reading |
page_snapshot
The page as a tree of roles, names and states, with a ref on everything you can act on. Start here: it is a few hundred lines where the HTML is tens of thousands, and every other page tool takes the refs it mints. Refs belong to the snapshot that made them — navigate or re-snapshot and the old ones are refused by name rather than silently hitting the wrong element.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
tabId | string | Tab id from list_tabs; omit for the tab with content on it |
maxNodes | number | Cap on nodes, 50-5000 (default 1500) |
everything | boolean | Include layout wrappers with no role of their own (default false) |
page_find
Find elements by CSS selector, visible text, ARIA role, accessible name, or any combination, and get a ref for each. Text matching returns the innermost match, so searching for "Sign in" gives you the button rather than the <body> that also contains it.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
selector | string | CSS selector to search within |
text | string | Visible text the element contains |
role | string | ARIA role, e.g. button, link, textbox |
name | string | Accessible name |
exact | boolean | Require the name to match exactly rather than contain |
limit | number | Maximum matches, 1-200 (default 20) |
tabId | string | Tab id; omit for the tab with content on it |
page_dom
The page’s actual HTML, whole or one subtree by ref or selector. Use it when you need the markup itself — an attribute, a data- value, a hidden input. For deciding what to click, page_snapshot is smaller and more useful.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
ref | string | Ref from a snapshot; the subtree under it |
selector | string | CSS selector; the subtree under the first match |
maxChars | number | Cap on characters returned (default 40000) |
tabId | string | Tab id; omit for the tab with content on it |
page_screenshot
A PNG of the viewport, the full page, or one element by ref or selector. Returned base64.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
ref | string | Ref of an element to photograph on its own |
selector | string | CSS selector of an element to photograph on its own |
fullPage | boolean | Capture the whole page rather than the viewport |
tabId | string | Tab id; omit for the tab with content on it |
page_click
Click an element by ref, CSS selector or visible text. Scrolls to it with a real wheel first, then moves the pointer along a human trajectory and presses — not element.click(), which dispatches an untrusted event with no preceding move and is what behavioural detection separates from a person. Reports forced: true on the rare element only a programmatic scroll could reach.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
ref | string | Ref from page_snapshot or page_find |
selector | string | CSS selector |
text | string | Visible text; refuses if more than one element matches |
first | boolean | With text, act on the first match instead of refusing |
tabId | string | Tab id; omit for the tab with content on it |
page_hover
Move the pointer onto an element and leave it there, for menus and tooltips that open on hover.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
ref | string | Ref from page_snapshot or page_find |
selector | string | CSS selector |
text | string | Visible text |
first | boolean | With text, act on the first match |
tabId | string | Tab id; omit for the tab with content on it |
page_type
Type text as a person types it: real keydown, keypress, input and keyup per character, human inter-key timing, occasional typos corrected with a backspace. With a ref or selector it clicks the field first; with neither it types into whatever already has focus. Never a paste — a field that goes from empty to forty characters in one event fires no keydown at all, which is among the cheapest bot signals a site can collect.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
textrequired | string | The characters to type |
ref | string | Ref of the field |
selector | string | CSS selector of the field |
clear | boolean | Select the existing value first, so this replaces it |
tabId | string | Tab id; omit for the tab with content on it |
page_fill
Clear a field and type a value into it. The same human typing as page_type; the clear uses the select-all shortcut for the platform the page believes it is on, so a profile presenting as Windows sends Control+A rather than contradicting its own fingerprint.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
textrequired | string | The value to put in the field |
ref | string | Ref of the field |
selector | string | CSS selector of the field |
tabId | string | Tab id; omit for the tab with content on it |
page_press
Press one named key, optionally with modifiers held. Keys: …. Modifiers: …. For ordinary characters use page_type.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
keyrequired | string | Key name, e.g. Enter, Tab, Escape, ArrowDown |
modifiers | string[] | Alt, Control, Meta, Shift |
tabId | string | Tab id; omit for the tab with content on it |
page_select
Choose one or more options in a native <select>, by value or by visible label. A native dropdown is drawn by the operating system and is not in the page, so there is nothing to click; this sets the selection and fires the input and change events a browser would. For a custom dropdown, click it and then click the option.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
valuesrequired | string[] | Option values or labels to select |
ref | string | Ref of the select |
selector | string | CSS selector of the select |
tabId | string | Tab id; omit for the tab with content on it |
page_scroll
Scroll the page with a real wheel, or scroll an element into view. The wheel deltas match the pointing device this profile was assigned — a trackpad and a notched mouse produce different event streams, and mixing them inside one session describes two different computers.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
amount | number | Pixels to scroll; positive is down (default 400) |
ref | string | Ref of an element to bring into view instead |
selector | string | CSS selector of an element to bring into view instead |
tabId | string | Tab id; omit for the tab with content on it |
page_drag
Drag from one element to another, as a press, a human-shaped move and a release.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
fromrequired | object | Where to start: { ref } or { selector } or { text } |
torequired | object | Where to drop: { ref } or { selector } or { text } |
tabId | string | Tab id; omit for the tab with content on it |
page_upload
Attach files to a file input, by absolute path on this machine. Point it at the <input type="file"> itself, which is often hidden behind a styled button — find it with a selector rather than by clicking the button.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
pathsrequired | string[] | Absolute file paths on this machine |
ref | string | Ref of the file input |
selector | string | CSS selector of the file input |
tabId | string | Tab id; omit for the tab with content on it |
page_reload
Reload the controlled tab and wait for it to load.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
tabId | string | Tab id; omit for the tab with content on it |
page_history
Go back or forward through the tab’s history. Uses the tab’s real history rather than history.go(), so it crosses origin boundaries the way the back button does.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
deltarequired | number | -1 for back, 1 for forward, and so on |
tabId | string | Tab id; omit for the tab with content on it |
page_wait
Wait for a selector to appear or disappear, for text to show up, or for the network to go quiet. Returns met: false on a timeout rather than failing, because "it never appeared" is often the answer you wanted — why says which it was. Network idle needs page_network_start running first, since without it there are no events to be idle between.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
selector | string | CSS selector to wait for |
text | string | Visible text to wait for |
gone | boolean | Wait for it to disappear instead of appear |
networkIdleMs | number | Wait until no request for this many ms |
timeoutMs | number | Give up after this long, default 10000 |
tabId | string | Tab id; omit for the tab with content on it |
page_evaluate
Run JavaScript against the page. world: "isolated" is the default and the page cannot see it — that is also where refs resolve, so pass a ref and the expression receives it as element. world: "page" runs in the page’s own realm, which is the only way to reach a framework’s globals and is the one mode the page could notice.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
expressionrequired | string | A JavaScript expression; an await is fine, the result is awaited |
world | string | "isolated" (default, invisible) or "page" |
ref | string | A ref to hand the expression as element; isolated world only |
timeoutMs | number | Give up after this long, default 20000 |
tabId | string | Tab id; omit for the tab with content on it |
page_console
Read what the page has logged, from two sources with two different costs. Free and invisible, always on: the browser’s own entries — failed requests, CSP violations, deprecations — which arrive with a browser:<source> kind. Off by default because the page could detect it: the page’s own console.log calls AND its uncaught errors and unhandled rejections, which need page_console_mode. That split is measured: an uncaught exception is reported only to the world it was thrown in, so nothing outside the page’s own world can see it without a CDP domain that makes the profile detectable. note always says which sources you are getting.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
limit | number | Return at most this many, newest last |
kinds | string[] | Filter: uncaught, rejection, log, info, warn, error, debug, trace |
clear | boolean | Empty the buffer after reading it |
tabId | string | Tab id; omit for the tab with content on it |
page_console_mode
Turn on capture of everything in the page’s own world: its console.log calls, its uncaught errors and its unhandled rejections. This is the ONE page-control feature a page could detect — seeing a console.log call means being the function that gets called, so console is wrapped in the page’s own world and the error listeners live there too. Off by default. There is no invisible alternative for these three, and that is measured rather than assumed. Turning it off restores the original console exactly. Turn it off when you are done.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
moderequired | string | "off" or "page" |
tabId | string | Tab id; omit for the tab with content on it |
page_network_start
Start recording every request this tab makes, and keep recording across navigations until you stop it. Unlike watch_network, which records for a fixed window and returns, this one runs in the background so you can act and then read. Requests from before you started are not in it — reload if you need the ones that built the page.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
tabId | string | Tab id; omit for the tab with content on it |
page_network
Read the recorded requests with their method, type, status and failure reason. Reports total, how many were dropped when the buffer filled, and stoppedBecause when the log simply ends — a truncated list that reports itself as complete is worse than no list.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
limit | number | Return at most this many, newest last |
filter | string | Substring of the URL, or an exact resource type or method |
clear | boolean | Empty the log after reading it |
tabId | string | Tab id; omit for the tab with content on it |
page_network_stop
Stop recording this tab’s requests. What has already been recorded stays readable.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
tabId | string | Tab id; omit for the tab with content on it |
page_network_body
The response body of one recorded request, by URL. Fetched on demand rather than buffered, so recording a busy page does not hold every response in memory. Needs the recording still running.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
urlrequired | string | The exact URL from page_network |
tabId | string | Tab id; omit for the tab with content on it |
page_dialogs
Read what alert, confirm and prompt have asked, and set how they are answered. Driving a page makes this necessary: Chromium dismisses a dialog itself when nothing is attached, but once page control attaches, the page blocks until we answer. The default is to dismiss and record, so attaching never hangs a page. Call with no policy to just read the log.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
policy | string | "dismiss" (default) or "accept" |
promptText | string | What to type into a prompt when accepting |
tabId | string | Tab id; omit for the tab with content on it |
page_attachments
Every tab page control currently holds open, with whether it is recording and how long it has been idle. Attachments are made on first use and dropped when the profile stops or after ten idle minutes; this exists so one that outlives its usefulness is visible rather than merely forgotten.
No arguments.
page_detach
Release the page-control attachment for a tab, or for every tab of a profile. Rarely needed — they expire on their own and a stopped profile drops all of its own — but it is here for when you want the page left with nothing attached to it. Refs from previous snapshots die with it.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
tabId | string | Tab id; omit to release every tab of this profile |
typing_defaults
The default timings human typing uses — the delays, the error rate, the correction behaviour. Read them to know what you are overriding before passing options to type_text.
No arguments.
Tabs and windows 12
The tabs a running profile already has open, read and steered as they are, and its windows arranged on the screen.
list_tabs
List the tabs a running profile has open, with their ids, titles and URLs. Every other browser tool takes a tabId from here; omit it and they act on the first tab, which is what you want when the profile has one.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
open_tab
Open a URL in a new tab of a running profile and return the new tab. The browser navigates it itself, so this returns as soon as the tab exists rather than when the page has loaded — read it with read_page, which waits.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
urlrequired | string | Absolute URL to open |
close_tab
Close one tab of a running profile. Closing the last tab does not stop the profile; use stop_profile for that.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
tabIdrequired | string | Tab id from list_tabs |
read_page
Read a tab: its URL, title, visible text and first hundred links. This is innerText, which is what a person sees — not textContent, which would include the contents of every <script> on the page and, on a detection site, the collector’s own source. Pass html for the markup as well when the text is not enough.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
tabId | string | Tab id; omit for the first tab |
html | boolean | Also return the page markup |
maxChars | number | Cap on the text and markup returned (default 20000) |
screenshot_tab
A PNG of the tab, base64-encoded. For when the answer is visual — a CAPTCHA, a layout, a detection site whose verdict is a coloured card rather than text.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
tabId | string | Tab id; omit for the first tab |
fullPage | boolean | Capture past the viewport rather than only what is visible |
run_script
Evaluate a JavaScript expression in the tab and return its value. Runs in the page’s own world, so it sees the page’s variables and the fingerprint exactly as the page does — which is what makes it useful for checking what a site is reading. The value is returned by value, so return something JSON can carry.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
expressionrequired | string | A JavaScript expression. An await is fine; the result is awaited. |
tabId | string | Tab id; omit for the first tab |
click_element
Click the element a CSS selector names, as a real mouse event at its centre. Deliberately not element.click(): that dispatches an untrusted event with no preceding move and isTrusted === false, which is precisely what a behavioural detector separates from a person.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
selectorrequired | string | CSS selector for the element to click |
tabId | string | Tab id; omit for the first tab |
watch_network
Record every request a tab makes for a number of seconds and return them with their status, type and size. Answers the questions a screenshot cannot: which third party a page is really calling, whether a request went out at all, what a detector posted its verdict to. The recording domain is enabled only for the window you ask for and turned off again.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
seconds | number | How long to record, 1-60 (default 8) |
tabId | string | Tab id; omit for the first tab |
read_browser_storage
Read what the site has stored in this profile: its cookies, localStorage and sessionStorage. The cookie jar is the profile’s real identity — more of what re-identifies a returning visitor lives here than in any fingerprint field.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
tabId | string | Tab id; omit for the first tab |
urls | string[] | Restrict cookies to these URLs |
write_browser_storage
Set or delete localStorage / sessionStorage keys for the tab’s origin. A value of null removes the key. Storage is same-origin, so this writes to whatever the tab is currently on — navigate first if that is not where you mean.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
whichrequired | "local" | "session" | Which store to write |
entriesrequired | object | Key to value; null deletes the key |
tabId | string | Tab id; omit for the first tab |
arrange_windows
Lay the running browsers out on screen: grid, cascade or stack. For watching a batch work at once. It moves windows and nothing else — no profile is started or stopped.
| Argument | Type | What it is |
|---|---|---|
ids | string[] | Running profile ids; omit for all of them |
layout | "grid" | "cascade" | "stack" | Default grid |
Fingerprints 8
Draw, check and repair the machine a profile claims, and match it to its exit.
match_profile_to_exit
Resolve where a profile actually comes out — through its proxy, or the direct connection when it has none — and bring the fingerprint into line with it. Timezone and geolocation are moved whenever they disagree, because neither is visible to a site that already knows the profile. The language is moved only for a profile that has never run: Accept-Language rides every request, so changing it under a session with history tells that site something true about itself, and the mismatch is reported in skipped instead. Pass language: "move" to move it anyway — correct when the profile is not signed in anywhere, and a change the sites it is signed into would see when it is. Use after attaching a proxy to profiles that already exist.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
language | "auto" | "move" | What to do with Accept-Language on a profile that has already run. "auto" (the default) leaves it and reports the mismatch in skipped. "move" changes it to the exit country’s language — visible to every site the profile is already signed in to, and the only way to fix a profile drawn for one country and now browsing out of another. |
preview_fingerprint
Generate a fingerprint without saving it, to inspect what a given set of options produces. The hardware half comes out of one catalogue row — the GPU and its renderer string, the thread counts that model ships with, the displays it actually has — so the parts always belong to a machine somebody can buy. Pass deviceId from list_devices to pin the machine and let the locale, the seed and the rest vary.
| Argument | Type | What it is |
|---|---|---|
seed | string | Reuse a seed to reproduce an exact identity |
deviceId | string | A machine from list_devices. A phone id implies android, so it is enough on its own. An unknown id falls through to a normal draw rather than failing. |
os | string | |
brand | string | Chrome, and there is one. Edge is refused: the engine builds its User-Agent suffix and its client-hint version lists from the same switch, so it can produce a correct Edge User-Agent or a correct Sec-CH-UA-Bitness, never both. Omit it. |
countryCode | string | ISO-3166 alpha-2 |
timezone | string | IANA zone, e.g. Europe/Vienna. Normally the proxy exit’s, and omitting it draws one that agrees with the country. |
languages | array | Accept-Language list, most preferred first. Drawn from the locale when omitted. |
latitude | number | The exit’s own latitude, when it is known. Jittered before use. |
longitude | number | The exit’s own longitude, when it is known. Jittered before use. |
audit_fingerprint
Ask whether an identity contradicts itself or the computer it will run on. Two separate answers. problems is what is impossible on any machine — a Metal renderer on Windows, a browser version that disagrees with its own User-Agent — and is always a bug. warnings is what is possible somewhere but not here: a platform this engine cannot back below JavaScript, a GPU vendor that contradicts what navigator.gpu reports from a worker realm, a chip different from the one in this machine, or a thread count or display the claimed model never shipped with. The generator never produces either, so anything reported came from editing by hand. Neither blocks anything; each names what was measured so the trade can be judged.
| Argument | Type | What it is |
|---|---|---|
profileId | string | Audit a stored profile. Omit to audit a freshly generated one instead. |
os | string | … Only used when generating a fingerprint to audit. |
countryCode | string | ISO-3166 alpha-2 — only used when generating one to audit |
list_devices
The device catalogue a profile can claim. Each entry is one machine somebody can buy — its GPU as the driver actually names it, the hardwareConcurrency values that model ships with, the memory it comes in, and the displays it has. Every renderer string here has been observed in the wild rather than composed by hand; a hand-written one is missing things like the PCI device id real Chrome reports, which is a tell rather than a disguise. Pass an id back to preview_fingerprint or the create call to draw that exact machine.
backed says whether this computer can stand behind the claim, and it turns on things a page reads directly: the OS, because fonts and their metrics come from the real machine; the GPU vendor, because navigator.gpu reports the real adapter from a worker realm; and on a machine that names its own chip, the chip itself, which was measured rather than reasoned about. The thread count is deliberately not one of them — the browser applies that override itself, so it holds in every realm. Machines that fail backed are listed rather than hidden, because a profile may be destined for a different computer; choosing one raises a warning from audit_fingerprint rather than an error.
The android rows are captured phones rather than catalogue entries assembled from tables, and backed asks a different question of them: one flag, whether this engine moves the whole mobile record below JavaScript, rather than the host OS, GPU vendor and chip a desktop claim turns on.
| Argument | Type | What it is |
|---|---|---|
os | string | windows, macos, linux or android. Omit for all. |
backedOnly | boolean | Only devices this computer can back. |
repair_hardware
Make a profile’s claimed machine constructible again. Two kinds of wrong, repaired differently: a machine nobody sells — an M3 Max beside a 13-inch Air panel, a thread count that model never shipped — is patched in place from the catalogue row that carries its chip, and a machine this computer cannot back is redrawn from the profile’s own seed with its locale, timezone and every noise setting held. The seed is the point: the canvas and audio hashes survive, so the profile keeps everything a site re-identifies it by and only the hardware underneath moves. Idempotent, and refuses a running profile.
| Argument | Type | What it is |
|---|---|---|
idsrequired | string[] | Profiles to repair |
regenerate_fingerprint
Redraw a stored profile’s identity. Pass nothing and it draws a whole new machine from a new seed — which is a different profile wearing the same name, so every site that knew it will see a stranger. Pass deviceId to move it onto one exact machine from list_devices while keeping the seed, which is the safe version: the canvas and audio noise, the fonts and everything a site re-identifies it by survive and only the hardware moves.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
deviceId | string | A machine from list_devices; keeps the seed |
os | string | |
seed | string | Reuse an exact seed. The same seed rebuilds the identical machine on any computer. |
validate_fingerprint
Audit a profile’s stored identity for contradictions — a GPU that does not belong to the platform, a timezone that disagrees with the language, hardware no real machine ships. Reads what is stored rather than drawing anything, so it is the call for "is this profile still coherent" after an edit.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
new_seed
A fresh identity seed. Everything about a drawn machine follows from one of these, so passing the same seed twice to preview_fingerprint gives the same machine — which is how a profile is reproducible without being shared.
No arguments.
Warm-up and checks 12
Warm a profile up before it meets the site that matters, and run it past the leak test and the public detectors.
run_leak_test
Launch a profile and verify from inside the page that the exit IP, WebRTC, timezone and geolocation match what it claims. Reports any leak.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
list_warmup_plans
List saved warm-up plans. A plan is a named list of sites plus how to behave on them — dwell range, scrolling, how many same-origin links to follow — and is the thing to pass to run_warmup when warming more than one profile. Includes every option, so a plan can be read before it is run.
No arguments.
save_warmup_plan
Create or replace a warm-up plan. The options are checked now rather than at run time: a dwell range the wrong way round, a site that is not a site or a siteCount of zero is refused here rather than discovered forty profiles into a batch nobody is watching. Omit options fields to keep what the plan already had.
| Argument | Type | What it is |
|---|---|---|
id | string | Existing plan to replace; omit to create |
name | string | What the plan is called |
description | string | What it is for, in your own words |
options | object | The run settings: preset, sites, siteCount, minSecondsPerSite, maxSecondsPerSite, scroll, followLinks, maxLinksPerSite, acceptCookieBanners, watch, headless. sites replaces the preset entirely. |
delete_warmup_plan
Delete a warm-up plan. A delete that removed nothing is a 404, never a cheerful success.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Plan id |
run_warmup
Warm several profiles with one plan, one after another. Sequential rather than parallel on purpose: each run launches that profile's own browser, so a fan-out would race the concurrency cap and silently exceed it. Long-running — a plan of eight sites at 12-35s each is roughly three minutes per profile. Every profile gets a row whether or not it worked; a dead proxy on one does not stop the rest. Pass planId, or the options inline, but not both.
| Argument | Type | What it is |
|---|---|---|
profileIdsrequired | string[] | Which profiles to warm |
planId | string | A saved plan from list_warmup_plans |
options | object | Inline options instead of a plan. See save_warmup_plan. |
cancel_warmup
Stop the profile that is warming up and every one still queued behind it in a batch.
No arguments.
list_detection_tests
List the catalogue of third-party sites that test a browser fingerprint: consistency scanners built to catch anti-detect browsers, bot and headless detectors, uniqueness and entropy measures, network leak tests, and live commercial bot gates. Each entry says what it measures and what a pass looks like.
| Argument | Type | What it is |
|---|---|---|
category | string | consistency, automation, uniqueness, leak or waf. Omit for all. |
open_detection_test
Open one of the detection test sites in a new tab of a profile, starting the profile if it is not running. Returns no verdict — read the page yourself, because scraping another site's results panel is a heuristic that silently goes wrong when they redesign it.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
testIdrequired | string | A test id from list_detection_tests, e.g. creepjs |
library_health
One pass over the library: what is wrong with it, with the profile ids and names behind every count so you can act without going looking. The findings worth acting on are a profile whose timezone contradicts its proxy’s measured exit — the first comparison every consistency scanner makes, and it drifts on its own whenever a pool re-homes a subnet — a profile whose Accept-Language contradicts it, which rides every single request, a profile describing a machine nobody sells, and one claiming something this computer cannot back. no-proxy and never-run are info because neither is a fault. Scope it with projectId and os, or omit both for the whole library. Auditing reads every profile off disk, so call it when you need it rather than on a timer.
| Argument | Type | What it is |
|---|---|---|
projectId | string | Only this project. Omit for every project. |
os | string[] | Only these platforms: windows, macos, linux, android. |
list_warmup_presets
The browsing plans the cookie robot can run, and the defaults it runs them with. A brand-new profile with an empty cookie jar is itself a signal; a warm-up gives it a history of ordinary sites before it is used for anything.
No arguments.
warm_up_profile
Browse real sites in a profile so its cookie jar looks lived-in. It runs in the same headed browser the profile uses, never headless — a headless Chrome announces HeadlessChrome in its own User-Agent and drops the real GPU, so warming up there writes a bot’s history into the jar and calls it a reputation. Scrolling, dwell time and clicks go through the same human input the rest of the product uses. Long-running; list_warmup_presets reports which profiles are mid-run.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
preset | string | A preset id from list_warmup_presets: general, social, shopping or tech |
sites | string[] | Browse these instead of a preset’s list; anything here replaces the preset entirely |
siteCount | number | How many sites to visit from the pool, sampled at random |
minSecondsPerSite | number | Shortest dwell on a page |
maxSecondsPerSite | number | Longest dwell on a page |
followLinks | boolean | Click through to a few pages within each site |
acceptCookieBanners | boolean | Click through consent banners, which gate most of the cookies worth having |
list_warmup_runs
Which profiles are warming up right now. A warm-up run holds a browser, so this is what to read before starting one on a profile that may already be busy.
No arguments.
Trash and backups 8
What was deleted, what can come back, and the library backups.
list_trash
What is in the trash and how long each entry has left. Deleting a profile or a project moves it here rather than destroying it; expiresInDays counts down to the automatic purge, and kind says whether restoring it brings back one profile or a project and everything that went with it.
No arguments.
restore_from_trash
Bring a deleted profile or project back, with its cookies, logins and browser data untouched. The kind has to match what list_trash reported: restoring a project also restores every profile that was deleted along with it.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile or project id, from list_trash |
kindrequired | string | "profile" or "project" |
empty_trash
Destroy what is in the trash. This is the irreversible one: every profile it removes takes its cookies, logins and history with it, and nothing here can bring them back.
It refuses to guess how much you meant. Calling it with no arguments is an error, not a full purge — name a projectId, name an os list, or pass all: true to mean every row. The old default cost 586 profiles to a script that meant "tidy up after myself". A platform filter deliberately spares trashed projects — a project is not in a platform, and purging one because "android" was named would take desktop profiles nobody asked about. Call list_trash first if you are about to run this on somebody’s behalf.
| Argument | Type | What it is |
|---|---|---|
projectId | string | Only this project’s trash |
os | string[] | Only these platforms: windows, macos, linux, android. Spares trashed projects. |
all | boolean | Every row, with nothing spared. Cannot be combined with the other two. |
list_backups
Snapshots of the store, newest first — the undo for empty_trash above. One is taken daily and one immediately before anything irreversible, so there is almost always something to go back to.
A snapshot holds the library’s metadata: every profile’s fingerprint, proxy binding, locale, notes and tags, plus the projects, proxies and settings. It does not hold profile-data/ — the browser directories are 570 times the size and mostly cache. So a restore brings back the identity and not the session: the profile returns with its fingerprint and its proxy, and logged out. Say that to the user rather than letting them assume cookies are coming back.
No arguments.
create_backup
Take a snapshot now. Worth doing before a bulk edit, an import or a mass delete — the operations that change many profiles at once and have no undo of their own. Costs about twelve kilobytes per profile, so there is no reason to weigh it.
No arguments.
preview_restore
What restoring a snapshot would do, without doing it. Returns missing — profiles the snapshot has and the library no longer does, which is what recovery means — and present, which exist in both.
Read that split before restoring anything. Bringing a missing profile back is recovery; restoring a present one writes over every change made to it since the snapshot, which is a second destructive act hiding inside the undo for the first.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | The snapshot id from list_backups |
restore_backup
Restore profiles from a snapshot. Additive by default: profiles that still exist are skipped unless overwrite is true, because the ones that were not deleted have been edited since the snapshot was taken and replacing them loses that work. ids narrows it to specific profiles.
A snapshot of the current state is taken first, so the restore is itself undoable. Restored profiles come back live rather than in the trash, and one whose project no longer exists lands in the active project. Tell the user that cookies and browsing data are not included — a restored profile is logged out.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | The snapshot id from list_backups |
ids | string[] | Only these profile ids. Omit for every profile the snapshot has and the library does not. |
overwrite | boolean | Also replace profiles that still exist, discarding changes made since the snapshot. Default false. |
purge_from_trash
Destroy one trashed item permanently, by id and by kind. This is irreversible: a purged profile takes its cookies, logins, history and downloaded files with it. One id, never a list — the unscoped version of this cost 586 real profiles, and a loop built from what a listing returned is how that happened. Call list_trash first and name what you meant.
| Argument | Type | What it is |
|---|---|---|
kindrequired | "profile" | "project" | "warmupPlan" | What the id names |
idrequired | string | The trashed item’s id |
Cookies, logins and bookmarks 19
Everything one profile carries: cookies, saved logins and 2FA codes, bookmarks, history and downloads.
list_credentials
List the logins saved on a profile. Returns labels, sites and usernames only — never a password or a two-factor secret, which stay encrypted in the OS keychain and leave the app only as keystrokes into the browser.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
add_credential
Save a login on a profile. The password and any two-factor secret are encrypted through the OS keychain before they are written. A two-factor secret may be given as base32 or as a whole otpauth:// URI.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
label | string | What this login is for |
site | string | The site it belongs to |
username | string | Username or email |
password | string | Password, in plain text — it is encrypted before storage |
totpSecret | string | Two-factor secret, base32 or an otpauth:// URI |
notes | string | Anything else worth remembering |
list_browser_logins
List the logins the browser itself has saved for a profile — what Chromium stored while somebody used it, as opposed to what Mosaic holds for the profile (see list_credentials). Passwords come back decrypted; a row that could not be decrypted reports password: null, which is not an empty password. passwordManagerOff means the profile has Chromium's password manager disabled, so an empty list there is a setting rather than a fact about the browser.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
add_browser_login
Save a login into the browser itself, as though Chromium had saved it — so the browser will offer to fill it. The profile must be stopped: Chromium keeps its password store in memory while it runs and rewrites the file on exit, so a login written underneath a live browser is discarded when that browser closes. Refuses rather than doing nothing.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
urlrequired | string | The sign-in page — its origin becomes the realm |
usernamerequired | string | Username or email |
passwordrequired | string | Password, in plain text — Chromium encrypts it with the profile's own key |
remove_browser_login
Remove one login the browser has saved, named by realm and username — both required, because an unscoped delete on an irreversible route is how a cleanup becomes a loss. Needs the profile stopped, for the same reason adding one does.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
realmrequired | string | The realm, as list_browser_logins reports it |
usernamerequired | string | Username of the row to remove |
list_browser_bookmarks
The bookmarks the browser itself holds, flattened out of Chromium's tree with the folder each sits in. Distinct from the profile's own bookmarks field, which is what Mosaic writes into the bar before every launch. A profile that has never run answers with an empty list rather than an error.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
list_browser_history
Domains this profile has visited, most visited first, with counts — domains rather than individual URLs. Enough to answer whether a profile has actually been used without reading somebody's browsing.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
limit | number | How many domains. Default 40. |
get_totp_code
Generate the current two-factor code for a saved login, with the seconds it stays valid. Check expiresIn before using it — a code with a second left will be rejected by the time it is submitted.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
credentialIdrequired | string | Credential id |
fill_credential
Type one field of a saved login into the focused field of a running profile, as real keystrokes with human timing rather than a paste. Focus the field in the browser first: this fills whatever is focused and deliberately does not guess which input is the password box. Returns the number of characters typed, never the value.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
credentialIdrequired | string | Credential id |
field | string | username, password or totp. Default password. |
list_downloads
What each profile has downloaded, when downloadMode is "perProfile": the folder, the file count, the bytes and when the newest one landed, plus any folder left behind by a profile that no longer exists. In "shared" mode the browser writes to a folder this app does not own — the response says which mode it is in rather than returning an empty list that reads as "no files".
No arguments.
clear_downloads
Permanently delete downloaded files. It refuses to guess how much you meant: name ids, or pass all: true for every profile’s files including folders orphaned by deleted profiles. There is no trash for these and nothing to restore from — the same rule empty_trash carries, for the same reason. Reports per profile with the file count and bytes that went, because a single number over a list is not an answer.
| Argument | Type | What it is |
|---|---|---|
ids | string[] | Profile ids whose files to delete. |
all | boolean | Every profile’s files, and the orphaned folders. Cannot be combined with ids. |
list_cookies
A profile’s cookies. Read from the live browser when one is running, which is the only place the current session lives, and otherwise from the profile’s own jar — the answer says which, because the two can legitimately differ while a browser is open and writing.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
import_cookies
Put cookies on a profile, replacing its imported list. Either a cookies array or a pasted text blob (Netscape cookies.txt, JSON, or header form) with a domain for the lines that do not carry one. An imported cookie reaches the browser once — at its next launch, or now if it is running — and after that only if you import it again with a different value or attributes; an unchanged one never overwrites a newer cookie the site has set since. The answer says how many were applied now, how many are pending for the next launch and how many were unchanged; liveError says why a running browser did not take them. Rows that could not be read come back in errors rather than being dropped — a cookie silently skipped is a login that silently does not work.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
cookies | object[] | Cookie records, as list_cookies returns them. |
text | string | A pasted blob instead: cookies.txt, JSON, or header form |
domain | string | The domain to assume for pasted lines that do not name one |
clear_cookies
Empty one profile’s cookie jar. By id, always — there is no form of this that means every profile. It logs that persona out of everything it was signed into, and nothing restores it.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
list_bookmarks
The bookmarks Mosaic holds for a profile — the ones written into the bar at launch, which a preset can fill in. Not the same as list_browser_bookmarks, which reads what Chromium itself saved while somebody used the browser.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
add_bookmarks
Set a profile’s bookmarks, replacing the list. Either a bookmarks array of { title, url } or a pasted text blob of URLs, one per line.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
bookmarks | object[] | |
text | string | URLs one per line instead, titles read off the lines |
clear_profile_cache
Empty profiles’ browser caches — HTTP cache, code cache, GPU and shader caches — and keep everything else: cookies, logins, local storage, history and extensions stay, so every profile is still signed in. For shrinking profiles and clearing a stale cached script without logging out. A running profile is skipped by name, never stopped for you. By id — there is no form of this that means all of them.
| Argument | Type | What it is |
|---|---|---|
idsrequired | string[] | Profile ids |
update_credential
Change a saved login. PATCH-shaped: an absent field is no change, and that matters more here than anywhere — omitting password keeps the stored one rather than blanking it. A new password or two-factor secret is encrypted through the OS keychain before it is written, and neither is ever returned.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
credentialIdrequired | string | The saved login’s id |
label | string | What this login is for |
site | string | The site it belongs to |
username | string | Username or email |
password | string | A new password, in plain text — encrypted before storage |
totpSecret | string | A new two-factor secret, base32 or an otpauth:// URI; null removes it |
notes | string | Anything else worth remembering |
delete_credential
Remove one saved login from a profile, by id. The secret goes with it and nothing restores it; the site’s own cookies are a separate thing and are untouched.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
credentialIdrequired | string | The saved login’s id |
Presets and extensions 9
Presets (templates in the API) that make profiles, and the extensions a profile loads.
list_extensions
Unpacked extensions in the library, which a profile can be given by id. Separate from the companion Mosaic installs in every profile — that one is generated per launch and declares no page-visible surface at all.
| Argument | Type | What it is |
|---|---|---|
projectId | string | Only this project’s, plus the global ones |
add_extension
Register an unpacked extension directory so profiles can load it. The path must be a folder containing a manifest.json; Mosaic loads it as unpacked rather than from a store, which is why there is no id to look up.
| Argument | Type | What it is |
|---|---|---|
namerequired | string | What to call it |
pathrequired | string | Absolute path to the unpacked extension directory |
projectId | string | Scope it to one project; omit for every project |
remove_extension
Take an extension out of the library. Profiles that listed it stop loading it at their next launch; the directory on disk is left alone unless Mosaic unpacked it itself.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Extension id |
list_templates
Profile presets: saved settings — proxy, privacy, start pages, extensions, tags — that a new profile starts from. Each one describes either a desktop or a phone; filter with kind rather than applying one to the other. A preset never carries an identity; every profile draws its own fingerprint whatever the preset says, because two profiles sharing one is two profiles a site reads as one.
| Argument | Type | What it is |
|---|---|---|
projectId | string | Only this project’s, plus the global ones |
kind | "desktop" | "mobile" | Only presets describing this kind of machine. A preset saved from a phone applied to a desktop profile produces a machine that is neither — the screen, touch points, GPU and capability record all come from a captured device record rather than the desktop catalogue. |
create_template
Author a preset from scratch — what every profile made from it starts with. Bookmarks, a default note, which extensions to load, which tabs to open, which tags to wear, and which provider to mint a proxy from. A provider and never an address: one gateway line mints a different session, and so a different exit, per profile, whereas an address stored here would put every profile the preset ever makes on one IP. The identity is not in here at all — each profile draws its own fingerprint from fingerprintOptions.
| Argument | Type | What it is |
|---|---|---|
namerequired | string | Preset name |
description | string | What it is for, shown beside the name |
projectId | string | Scope it to one project; omit for every project |
fingerprintOptions | object | What each profile’s identity is drawn from — os, brand, timezone, languages. The os here is also what decides whether this preset describes a desktop or a phone. |
privacy | object | Privacy switches, as on a profile. |
startOptions | object | Launch mode and window geometry, as on a profile. |
startPages | string[] | Tabs to open on launch. |
extensions | string[] | Absolute paths to unpacked extensions. |
tags | string[] | Tags every profile made from this preset wears. |
bookmarks | object[] | Bookmarks in the bar of the first window. Each is { title, url }; an http:// or https:// address is required, and a missing title shows as the URL, which is what Chromium does. |
note | string | The profile’s note, pre-filled. Markdown — the same field the companion edits. |
proxy | object | A provider to mint a fresh proxy from, per profile. Never an address: { providerId, pick }, where the pick is { country, state, city, minutes } in that seller’s own words. A pick the vendor cannot spell is refused by name rather than dropped — a dropped token authenticates and puts the profile somewhere else without saying so. |
update_template
Change a preset. PATCH-shaped: an absent field is no change, and proxy: null takes the provider off. There was no way to do this — a preset could only be made and deleted, so editing one meant rebuilding it from memory.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Preset id |
name | string | New name; it cannot be emptied |
description | string | What it is for |
projectId | string | Scope it to one project; null for every project |
fingerprintOptions | object | What each profile’s identity is drawn from. |
privacy | object | Privacy switches. |
startOptions | object | Launch mode and window geometry. |
startPages | string[] | Tabs to open on launch. |
extensions | string[] | Absolute paths to unpacked extensions. |
tags | string[] | Tags every profile made from this preset wears. |
bookmarks | object[] | Replaces the list. Each is { title, url }. |
note | string | The profile’s note, pre-filled. |
proxy | object | { providerId, pick }, or null to mint nothing. |
delete_template
Delete a preset. The profiles already made from it are untouched — a preset is a starting point, not a link.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Preset id |
save_profile_as_template
Turn a profile’s settings into a reusable preset. The identity is deliberately not copied — see list_templates.
| Argument | Type | What it is |
|---|---|---|
profileIdrequired | string | Profile to take the settings from |
namerequired | string | Preset name |
description | string | What it is for |
projectId | string | Scope it to one project; omit for every project |
update_extension
Rename an extension in the library, or re-point it at a different folder. Profiles reference the path, so moving the path is how a shared extension is updated everywhere at once.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Extension id |
name | string | New display name |
path | string | New absolute path to the unpacked folder |
autoAdd | boolean | Attach it to every new profile in its project |
Proxies and providers 26
Saved proxies, provider accounts that mint a session per profile, checks, rotation and reputation.
list_providers
List proxy providers — the seller accounts kept as templates, each of which mints a fresh proxy per profile. Each row says which of country, state, city, session and duration that seller's gateway can actually be asked for (supports), what its pasted line already asks for (current), one real example of the credential it produces (preview), and how many profiles were minted from it. Providers are global: there is no project to restrict them to.
No arguments.
add_provider
Add a proxy provider from one pasted gateway line — the line a seller's dashboard gives you, in any of the forms add_proxies reads. The line is the specification: the vendor, the grammar, the account prefix and whatever it already asks for are all read back off it, so a seller that spells its keys differently still round-trips. Refuses a line that is the same gateway as one already stored, because five lines off one dashboard are five examples of one gateway differing in a session id this app rewrites anyway.
| Argument | Type | What it is |
|---|---|---|
linerequired | string | One gateway line, e.g. host:port:user-country-us-session-abc:pass |
name | string | What to call it. Defaults to the vendor's own name. |
notes | string | Anything worth remembering about this account |
type | string | Default type when the line has no scheme: http, https, socks5 or socks4 |
defaults | object | What every profile minted from this provider asks for unless it says otherwise: country, state, city, minutes. |
read_provider_line
Say what a pasted gateway line means without storing it: which vendor it belongs to, which options that vendor can be asked for, what the line already asks for, and one real example of the credential this app would produce from it. Use before add_provider when you want to confirm the line was read the way you meant — particularly for a seller with more than one pool, where only the hostname tells them apart and the grammars differ.
| Argument | Type | What it is |
|---|---|---|
linerequired | string | One gateway line |
type | string | Default type when the line has no scheme |
update_provider
Change a provider's name, notes, defaults — or its line. A new line is re-read from scratch rather than merged, because a seller that moves an account to a different host is a different grammar and possibly a different carrier, and a merged parse would match neither.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Provider id |
line | string | A replacement gateway line |
name | string | New name |
notes | string | New notes |
type | string | Default type for a replacement line |
defaults | object | Replacement defaults: country, state, city, minutes. |
delete_provider
Delete a provider. Profiles minted from it keep the proxy they were given and go on browsing from it — the credential lives on the profile, not behind a reference — so nothing loses its exit. What is lost is the ability to mint more. keptProfiles says how many are in that position.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Provider id |
check_provider
Check a provider by minting one proxy from it and sending a real request through it. There is nothing else to check: a template is not an address, and nothing is listening until a credential names a session. The result is recorded on the provider, which is evidence about the account — has the balance run out, has the session limit been hit — rather than about any exit a profile will later use.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Provider id |
mint_proxy
Mint one proxy from a provider without attaching it to anything, and return the credential. Every call mints a new session id, because that is what minting is — two profiles sharing a session id share an exit address, which is the single thing a proxy per profile exists to prevent. Refuses, naming the field, a pick this seller's gateway has no word for: writing one anyway produces a proxy that authenticates and then quietly ignores where you asked it to be.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Provider id |
country | string | ISO country code, or "any" to take the option off |
state | string | Subdivision name or code |
city | string | City name |
minutes | number | How long the exit holds, 0 to 1440 |
list_proxy_vendors
Every proxy seller this app recognises by hostname, and which options each one's gateway can be asked for. A seller not in this list still works — its line is read and used exactly as pasted — but nothing is added to it, because a guessed key name produces a proxy that authenticates and comes out in the wrong country without saying so.
No arguments.
list_exit_places
Where an exit can be asked to be. With no argument: every country code and name. With a country: its subdivisions and its larger cities. Cities are suggestions rather than a closed list — every vendor takes a city as a free string — but the subdivisions matter, because sellers disagree about whether a state is written as a code or spelled out and this app converts between the two using exactly this table.
| Argument | Type | What it is |
|---|---|---|
country | string | ISO country code |
list_proxies
List saved proxies, including the result of their last connectivity check.
| Argument | Type | What it is |
|---|---|---|
projectId | string | Restrict to one project |
add_proxies
Bulk-add proxies from pasted text or the contents of a .txt/.csv file. Reads every common format and detects it per line: host:port, host:port:user:pass, user:pass:host:port, user:pass@host:port, scheme://user:pass@host:port (http, https, socks4, socks5), IPv6 in brackets, whitespace-separated fields, a trailing |US for the country, and a table with a header row separated by commas, tabs or semicolons (columns found by name: host/ip, port, username/login, password, type/protocol, country, name, rotation_url, tags, notes, or one proxy column). A line already saved — same type, host, port and credentials — is skipped rather than added twice, and every line not imported comes back in skipped or errors with its reason. Call parse_proxy_list first to preview. With check: true every new proxy is checked, a few at a time, and checked names which answered and which did not.
| Argument | Type | What it is |
|---|---|---|
textrequired | string | The list: one proxy per line, or a table with a header row |
type | string | The type for a line that does not say (default http) |
projectId | string | Restrict these proxies to one project; omit for every project |
namePrefix | string | Name them "<prefix> 1", "<prefix> 2", … continuing after the highest number already used |
tags | string[] | Tags added to every imported proxy |
check | boolean | Check every new proxy after importing it (default false) |
concurrency | number | How many checks run at once, 1–16 (default 6) |
check_proxy
Test a saved proxy: where it exits (IP, country, city, ISP, ASN, whether the range looks like a datacentre), whether it will CONNECT — a gateway can answer plain HTTP perfectly and refuse to tunnel, and that proxy loads nothing in a browser — and whether two connections come out of the same place, which decides whether any profile behind it can hold a timezone. It also scores the exit against blocklists, because an exit on one loses the account before the fingerprint is ever examined. The result is cached on the proxy and a successful check corrects the country it was declared with.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Saved proxy id |
list_proxy_checks
Which proxies have a check in flight this second. A check is owned by the app rather than by whoever started it, so it keeps running after the caller goes away — which means a fresh caller cannot tell forty running checks from none, and would start them all again. Ask this before check_proxy on anything you did not start yourself. An empty list means nothing is running now, not that nothing has been checked: the last result is on the proxy.
No arguments.
save_profile_proxy
Promote a profile’s pasted, not-yet-saved proxy into the Proxies library and link the profile to it, so the same address can be reused and edited in one place. Refused by name when there is nothing to save: a profile already on a saved proxy, a profile with no proxy, or a provider-minted session — that last one is one launch’s session id, not a reusable address, and saving it would pin many profiles behind one exit. Returns the new saved proxy.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
name | string | Name for the saved proxy; defaults to "host:port" |
score_proxy_reputation
Score what a site sees when this proxy connects: whether the exit is a datacentre or looks residential, whether it is on public blocklists, and whether repeated samples come out of the same address. Refuses on a proxy that has never answered rather than quietly running a connectivity check first — there would be no exit address to score, and an errand the caller did not ask for is one they cannot see. Run check_proxy first.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Saved proxy id |
update_proxy
Change a saved proxy. PATCH-shaped: an absent field is no change. Editing the address clears its last check, because a result recorded against the old host says nothing about the new one.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Saved proxy id |
name | string | What it is called in the list |
type | string | http, https, socks4 or socks5 |
host | string | Hostname or address |
port | number | Port |
username | string | Username |
password | string | Password |
notes | string | Anything worth remembering |
countryCode | string | Where the seller says it exits, as a two-letter code |
city | string | Where the seller says it exits |
tags | string[] | Tags on the proxy row |
rotateOnLaunch | boolean | Ask for a fresh session on every launch |
rotationUrl | string | A URL the seller rotates the session on |
sessionId | string | A session token to pin, which rotation then leaves alone |
provider | string | The dialect id, from list_proxy_dialects |
projectId | string | Scope it to one project; null for every project |
delete_proxy
Remove a saved proxy from the library, by id. Profiles already carrying it keep the address they have — it is a working exit, and taking it out from under a configured profile would be a surprise nobody asked for. What they lose is the link back to the row.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Saved proxy id |
assign_proxy
Point profiles at saved proxies, in one of four modes. one: every profile on proxyId, and null detaches. roundRobin: proxyIds dealt out in order, wrapping when there are more profiles than proxies. unique: one proxy per profile that no other profile holds — refused, naming the shortfall, when there are not enough, because the point of owning forty proxies is forty exits. country: proxies that come out in country (measured where checked, declared otherwise), unused first. The pool for unique and country is proxyIds when given, otherwise every saved proxy the profile’s project can see. The mode defaults to roundRobin when proxyIds is given and one otherwise. The answer says whether any proxy is now shared (reused, with a shared-exit entry in warnings naming the most profiles on any one) and names every assignment.
| Argument | Type | What it is |
|---|---|---|
profileIdsrequired | string[] | The profiles to change |
mode | "one" | "roundRobin" | "unique" | "country" | How to choose; see the description |
proxyIds | string[] | The pool, dealt out in order for roundRobin |
proxyId | string | Mode one: one proxy for all of them, or null to detach |
country | string | Mode country: a two-letter code, like "US" |
scope_proxy
Move saved proxies between projects, or make them global. projectId: null means every project. By id — there is no form of this that means all of them.
| Argument | Type | What it is |
|---|---|---|
idsrequired | string[] | Saved proxy ids |
projectId | string | The project to scope them to, or null for every project |
parse_proxy_list
Read a pasted blob of proxy lines — or a .csv/.txt file’s contents — and say what each one came out as, without saving anything. Every line comes back in lines with a status: ok, duplicate (the same proxy earlier in the list), exists (already saved; pass projectId to compare against what that project can see) or error, and every one that will not be imported carries its reason by name — the port that is not a number, the scheme that is not a proxy type. Use it before add_proxies on a list you have not imported before.
| Argument | Type | What it is |
|---|---|---|
textrequired | string | The pasted lines |
type | string | The type to assume where a line does not say (default http) |
projectId | string | Compare against the proxies this project can see |
export_proxies
The saved proxies as text another tool can read — including this one. url is scheme://user:pass@host:port, one per line; colon is host:port:user:pass, what most sellers print (it cannot carry a type); csv has a header row with name, type, host, port, username, password, country, rotation_url, tags and notes. Pass ids for a selection or projectId for one project; with neither, every saved proxy. The passwords are in the output, because a list without them imports nothing.
| Argument | Type | What it is |
|---|---|---|
format | "url" | "colon" | "csv" | Default url |
ids | string[] | Only these proxies |
projectId | string | Only the proxies this project can see |
rotate_proxy
Fetch a saved proxy’s change-IP link (rotationUrl) from Mosaic, wait for the modem to re-dial, then check the proxy: { status, before, after, changed, check }. changed is true or false only when both exits are known. A link that answers anything but 2xx is refused naming the status — nothing was rotated — and a proxy with no link is refused by name. Pass ids to rotate several, one after another; the answer names every one that failed.
| Argument | Type | What it is |
|---|---|---|
id | string | One saved proxy |
ids | string[] | Several, rotated in sequence |
check_proxies
Check several saved proxies at once, a few in flight at a time, and say how each one went by name: { checked, ok: [{ id, name, ip, countryCode }], failed: [{ id, name, reason }] }. Each result is also recorded on its proxy, as check_proxy does. By id — there is no form of this that means all of them.
| Argument | Type | What it is |
|---|---|---|
idsrequired | string[] | Saved proxy ids |
concurrency | number | How many checks run at once, 1–16 (default 6) |
list_proxy_dialects
The proxy dialects this build understands — the per-seller rules for how a session id and a country are spelled into a credential. Not the same as list_proxy_vendors, which is the catalogue of sellers; a dialect is the grammar, and it is what decides whether a targeting token reaches the gateway or is silently dropped.
No arguments.
check_proxy_line
Check an address that is not in the library: pass host, port and credentials and get the same result a saved proxy’s check returns — reachable, the exit address, and where the seller says it is. For deciding whether to keep a proxy before adding it.
| Argument | Type | What it is |
|---|---|---|
hostrequired | string | Hostname or address |
portrequired | number | Port |
type | string | Default http |
username | string | Username |
password | string | Password |
check_profile_proxy
Check the proxy a profile is actually carrying, whatever it is — a saved row, a pasted line, or one minted from a provider. The result is written back onto the profile, which is what a launch reads to decide whether it may start, so this is the call that turns "never checked" into a profile that will open.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
Profiles and projects 26
Create, start, stop, move and organise profiles, projects and tags.
list_projects
List all projects with their profile counts. Profiles always belong to exactly one project.
No arguments.
create_project
Create a project to group profiles.
| Argument | Type | What it is |
|---|---|---|
namerequired | string | Project name |
icon | string | Emoji icon |
color | string | Hex colour |
get_project
One project, with how many profiles it holds and how many of those are phones.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Project id |
update_project
Rename a project or change its icon or colour. Only the fields you send are changed. Exactly one project carries system: true — the one Mosaic made, where every profile lands before it is filed — and its name, icon and colour are fixed; sending any of them is refused with the field named. Its sortOrder is still yours to set.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Project id |
name | string | New name |
icon | string | Emoji or icon name |
color | string | Hex colour, e.g. #4a6cc4 |
delete_project
Delete a project. Every profile in it goes to the trash with it, recoverable for the retention period, and restoring the project brings back exactly those profiles. Refuses when it is the last project, and for the system project — nothing re-creates that one. This is a destructive call on everything the project holds — check list_profiles for that project first if you are not certain what is in it. Any browser open in the project is closed first, and a browser that will not close keeps the whole project rather than hiding a running window behind a deleted row.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Project id |
list_profiles
List profiles, optionally filtered by project, search text or tag. Each summary carries status, the live run state.
| Argument | Type | What it is |
|---|---|---|
projectId | string | Restrict to one project |
search | string | Match against name, note and tags |
tag | string | Exact tag match |
os | string | Keep only this platform: windows, macos, linux or android |
limit | number | How many to return. Default 100, max 500. |
offset | number | Skip this many. total counts every match, not the page, so it is what says whether another page exists. |
sort | string | Order the whole result before paging: …. Omit for most-recently-used first, falling back to when the profile was made. Sorting matters here precisely because the answer is paged — without it, "the five profiles I used most recently" needs every row fetched. |
order | string | asc or desc. Defaults to desc for the two dates and asc for the rest. A profile that has never run sorts last either way. |
get_profile
Fetch one profile in full, including its complete fingerprint, proxy and privacy settings.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
create_profile
Create one or more profiles. Each gets a fresh, internally coherent fingerprint drawn from real-device distributions. Nothing is required: create_profile with no arguments works. Two defaults exist so you never need a setup call — the profile lands in the system project when you name none, and proxy takes a pasted proxy string that is attached to this profile and saved nowhere.
A profile created with a proxy is drawn for that proxy’s exit. The proxy is measured first and the country, timezone, languages and geolocation come from the address it really leaves by — you do not have to pass countryCode, and you should not guess one. Every result carries exitMatch, which says whether that measurement happened and, when it did not, why: a dead gateway still creates the profiles, with an identity from the table, and says so rather than reporting a clean batch.
| Argument | Type | What it is |
|---|---|---|
projectId | string | Target project. Optional — omitting it uses the system project, the one Mosaic made at first launch and the one that cannot be deleted. The same answer every run, unlike “whichever project the window is showing”. |
name | string | Profile name. {n} is the number in a batch, {n:3} pads it to three digits — Shop-{n:3} |
count | number | How many to create (default 1, max 500) |
startAt | number | The first number a batch is named with; default is after the highest that name already has |
note | string | Free-text note |
tags | string[] | Tag names |
os | string | |
deviceId | string | Draw one exact machine from list_devices rather than a weighted draw. A phone id such as sm-s918u implies android. |
countryCode | string | ISO-3166 alpha-2; sets timezone, languages and geolocation coherently |
proxyId | string | Attach a proxy from the saved list by id. Use this for an exit you keep and share; use proxy for anything else. |
proxy | value | A proxy for this profile alone, as a plain string — the field you almost always want. Any of scheme://user:pass@host:port, user:pass@host:port, host:port:user:pass, host:port@user:pass, or a bare host:port (scheme defaults to http). It is NOT added to the saved proxies list, so a run through a hundred rotating sessions leaves that list exactly as it found it. If the exit is already saved, the profile links to that entry instead of duplicating it. An unreadable line is refused, quoting it. Or, instead of a line, an object naming a provider and where its exit should be: {"providerId": "…", "country": "US", "state": "California", "city": "Los Angeles", "minutes": 30}. That mints a proxy from that seller’s template with a session id nothing else holds, which is how two profiles are kept off one exit address. Every field but providerId is optional; one the seller’s gateway cannot spell is refused by name rather than quietly dropped. See list_providers. With count above 1, a line or a proxyId puts the whole batch on one address: allowed, not recommended, and answered with a shared-exit entry in warnings; a provider mints one exit per profile. |
matchExit | boolean | Measure the attached proxy and draw the identity for the address it actually exits from. On by default, which is what you want: a profile whose timezone and language contradict its exit fails the first comparison every consistency scanner makes. Pass false to skip the lookup and draw from the table instead — faster, and correct only when you do not care where the profile appears to be. |
update_profile
Update a profile. Only the fields you pass change. proxy is the quickest way to move a profile onto a new exit: pass the line and it replaces whatever was there, saved proxy included.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
name | string | New name |
note | string | New note |
tags | string[] | |
proxyId | string | Saved proxy id, or empty string to detach |
proxy | value | A proxy for this profile alone, as a plain string — the field you almost always want. Any of scheme://user:pass@host:port, user:pass@host:port, host:port:user:pass, host:port@user:pass, or a bare host:port (scheme defaults to http). It is NOT added to the saved proxies list, so a run through a hundred rotating sessions leaves that list exactly as it found it. If the exit is already saved, the profile links to that entry instead of duplicating it. An unreadable line is refused, quoting it. Pass an empty string to remove the proxy entirely, which also clears proxyId. Or, instead of a line, an object naming a provider and where its exit should be: {"providerId": "…", "country": "US", "state": "California", "city": "Los Angeles", "minutes": 30}. That mints a proxy from that seller’s template with a session id nothing else holds, which is how two profiles are kept off one exit address. Every field but providerId is optional; one the seller’s gateway cannot spell is refused by name rather than quietly dropped. See list_providers. |
oneTime | boolean | Mark it a throwaway: its browser data is discarded when it stops |
pinned | boolean | Keep it at the top of the list, in every order |
delete_profile
Move a profile to the trash. Reversible: it keeps its cookies, logins and browser data and waits out the retention window, and restore_from_trash brings it back whole. This said "Irreversible" and was wrong — store.deleteProfile has always trashed rather than purged, and an assistant reading that description would refuse the safe operation and reach for something worse. purge on empty_trash, or the REST DELETE /trash/profiles/:id, is the one that actually destroys. If the profile is running its browser is closed first; a browser that will not close is refused by name and the profile stays on the list, because a trashed row has no Stop button.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
start_profile
Launch a profile and return its DevTools endpoint for Puppeteer, Playwright or raw CDP.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
headless | boolean | Run without a visible window. Changes the User-Agent to HeadlessChrome unless the profile sets one; prefer offscreen. |
offscreen | boolean | Run headed but parked off-screen, with no Dock identity — for a run nobody is going to watch. Keeps the real User-Agent and GPU. |
url | string | Open this URL instead of the start pages |
stop_profile
Stop a running profile. The browser flushes its cookies and storage to disk first, rather than being killed mid-write.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
list_running
List every currently running profile with its process id and DevTools endpoint.
No arguments.
list_tags
List the tags in a project with their colours and how many live profiles carry each. Tags cut across projects — a profile has any number of them. Use the tag argument of list_profiles to filter by one.
| Argument | Type | What it is |
|---|---|---|
projectId | string | Restrict to one project |
rename_tag
Rename a tag, or change its colour, or both. A rename reaches every profile carrying it — profiles store tags by name, so this is the only correct way to change one. Renaming onto a name that already exists in the project is refused rather than merging, because merging two tags is a bigger decision than a rename.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Tag id, from list_tags |
name | string | The new name; omit to change only the colour |
color | string | A hex colour like #2b7fbd; omit to change only the name |
delete_tag
Delete a tag. The tag is removed from every profile that carried it; no profile is deleted or otherwise changed. Call list_tags first if you want to tell the user how many profiles it is on.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Tag id, from list_tags |
start_profiles
Start several profiles, one at a time with a gap between them.
Prefer this over calling start_profile in a loop, and the reason is not politeness. The concurrency cap counts sessions that are still starting as well as running, so parallel starts all read the count before any has registered, all pass the check, and exceed the cap the operator set. This awaits each launch, which is what makes that setting mean what it says. It is also what keeps the machine usable: every launch is a browser with its own renderer, GPU process and network service.
A profile already running is skipped, not a failure. One that cannot start — a dead proxy, a missing engine — costs that row and nothing else.
| Argument | Type | What it is |
|---|---|---|
idsrequired | string[] | Profile ids to start. |
staggerMs | number | Gap between launches in milliseconds, 0–60000. Default 1000. |
stop_profiles
Stop several profiles. Each is closed through Browser.close so Chromium flushes its cookie jar rather than being killed mid-write — a profile killed instead of closed can lose the session it just built. Concurrent, unlike starting: nothing is being competed for. A profile that is not running is skipped.
| Argument | Type | What it is |
|---|---|---|
idsrequired | string[] | Profile ids to stop. |
bulk_update_profiles
Apply the same change to many profiles at once. Only the fields you pass move; everything else is left alone on every profile, including where they differ from each other. Tags add and remove rather than replace, so a profile keeps tags you did not name. Running profiles are skipped rather than half-edited, and the answer says which. Putting the selection on one saved proxy (proxyId) or one pasted line (proxy) is allowed and answered with a shared-exit warning; a provider gives each profile its own exit.
| Argument | Type | What it is |
|---|---|---|
idsrequired | string[] | Profiles to change |
proxyId | string | Attach this saved proxy, or empty string to detach |
proxy | value | Recommended: mint from a proxy provider, { providerId, country, state, city, minutes } — each selected profile gets its own session id, and so its own exit address. Also accepted: one proxy for the whole selection, as a pasted line (scheme://user:pass@host:port, host:port:user:pass, …) or a config object, or null to detach. One address for many profiles is allowed and is not recommended: sites can link accounts that share an address, so the answer carries a shared-exit entry in warnings naming how many now share it. |
oneTime | boolean | Mark them throwaways, or take the mark off |
pinned | boolean | Pin them to the top of the list, or unpin them |
addTags | string[] | Tag names to add |
removeTags | string[] | Tag names to remove |
duplicate_profile
Copy a profile’s settings — proxy, privacy, start pages, extensions, tags — into a new one. The identity is drawn fresh by default, because two profiles sharing a seed share a canvas and audio fingerprint and are one profile to any site that measures them; newFingerprint: false copies it verbatim instead, which is only right when the original is being replaced rather than joined. Cookies, storage and history are never copied: a duplicate starts with an empty jar, and export_profile over REST is what moves a session.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
name | string | Name for the copy; defaults to "<name> copy" |
newFingerprint | boolean | Draw a new identity (default true). False copies the original’s, which makes two profiles one to a fingerprinter. |
create_profile_shortcut
Put a shortcut to one profile on this computer: a small app on macOS, a .lnk on Windows, a .desktop file on Linux. Opening it starts that profile’s browser without opening the Mosaic window — Mosaic runs in the background for as long as the browser is open, because the proxy relay and the cookie flush live there, and quits when it closes. place is desktop (default) or applications (~/Applications, the Start menu, or ~/.local/share/applications). Returns the path written. Creating one again replaces the earlier one for that profile in that place.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | Profile id |
place | string | Where to put it. Default desktop. |
move_profiles
Move profiles into another project, by id. Its own tool rather than a field on bulk_update_profiles, which is where this was mapped and does not accept a projectId — so until now there was no way to move a profile from this surface at all. Nothing about a profile changes except which project it belongs to: the fingerprint, proxy, cookies, logins and history are untouched and a running browser keeps running. Tag names travel and are registered in the destination project, because a tag’s colour belongs to a project and a moved profile would otherwise keep the words and lose the colours. Reports what moved by name, and separately any id whose profile could not be read.
| Argument | Type | What it is |
|---|---|---|
idsrequired | string[] | Profile ids to move |
projectIdrequired | string | The project to move them into, from list_projects |
delete_profiles
Move several profiles to the trash, by id. Each one’s browser is closed first, at this door like every other — a hidden row with a live window still on its proxy and still writing cookies is the state this rule exists to prevent. A profile whose browser would not close stays on the list, where it still has a Stop button, and comes back named rather than counted.
| Argument | Type | What it is |
|---|---|---|
idsrequired | string[] | Profile ids |
export_profiles
Write profiles to a Mosaic archive on disk, and return where it went. A path rather than bytes, because an archive is megabytes of zip and a tool result is text — and the file is what import_profiles takes. includeBrowserData carries the cookies, logins and history; leave it off for a library you are handing to somebody else.
| Argument | Type | What it is |
|---|---|---|
idsrequired | string[] | Profile ids to export |
pathrequired | string | Absolute path to write the .zip to |
includeBrowserData | boolean | Carry cookies, logins and history (default true) |
import_profiles
Read a Mosaic archive off disk into this installation. A library exported from another platform is carried rather than refused — the profiles land flagged, which library_health counts and Repair redraws, because refusing somebody’s whole library at the door is worse than carrying it and saying what is wrong with it.
| Argument | Type | What it is |
|---|---|---|
pathrequired | string | Absolute path to the .zip |
projectId | string | Where to put them; omit for the system project |
create_tag
Create a tag with a colour. Tags are also created implicitly by naming one on a profile or a preset; this is for choosing the colour up front rather than taking whatever was assigned.
| Argument | Type | What it is |
|---|---|---|
namerequired | string | Tag name |
color | string | Hex colour, e.g. #c9a227 |
projectId | string | Scope it to one project; omit for every project |
The app 19
Settings, the engine, updates, the account, support and what the API has been doing.
submit_support_request
Write to Mosaic’s support: kind is support (a question or a problem — this one also emails the support inbox), feature (a request) or bug (a report). Works signed out, in which case email is required — it is where the reply goes. Up to 4 screenshots as base64 PNG, JPEG or WebP, 3 MB each; their metadata is stripped before they are stored. diagnostics: true attaches the app and engine versions, the operating system and the last log lines with credentials, tokens and addresses scrubbed — call preview_support_diagnostics first to read exactly what that sends, and only send it if the operator has agreed. The answer is the new request; list_support_requests shows replies as they arrive.
| Argument | Type | What it is |
|---|---|---|
kind | "support" | "feature" | "bug" | What this is. Default support |
subject | string | One line, up to 140 characters. Optional — the first line of the message when absent |
messagerequired | string | What happened, or what is wanted. Up to 10,000 characters |
email | string | Where to reply. Required when Mosaic is not signed in; ignored otherwise |
screenshots | object[] | Up to 4 of { name, type: "image/png"|"image/jpeg"|"image/webp", data: base64 } |
diagnostics | boolean | Attach the scrubbed diagnostics. Default false |
list_support_requests
Every support request this person has filed — the account’s, and any filed from this install while signed out — newest activity first, each with its status (open, in_progress, answered, fixed, closed), how many replies it has and who wrote last (lastFrom: "staff" means an answer is waiting).
No arguments.
get_support_request
One support request with its whole conversation, oldest first, and the list of its screenshots.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | The request id, from list_support_requests |
reply_support_request
Add a message to a support request. A reply to one that was answered, fixed or closed opens it again.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | The request id |
messagerequired | string | The reply, up to 10,000 characters |
get_support_screenshot
One screenshot of a support request, as base64 with its type.
| Argument | Type | What it is |
|---|---|---|
idrequired | string | The request id |
screenshotIdrequired | string | The screenshot id, from get_support_request |
preview_support_diagnostics
Exactly what diagnostics: true would attach to a support request, scrubbed, so it can be read before anything is sent. Sends nothing.
No arguments.
get_account
The plan this Mosaic is on — Free or Pro — what it allows, and how much of it is in use: limits.profiles, limits.creations (profiles made in all, counted by the account server per account and per computer — deleting one does not give it back), limits.projects and limits.devices (null is unlimited; on Free they are this account’s own — freeTier is current, or legacy for an account made before the Free plan shrank, which keeps 5 profiles and 20 creations), whether the API and MCP are included, usage (usage.creations is the server's last count), and source, which says why (a paid subscription, a Free account, or a build with no account server, which limits nothing). billing is card for a Stripe subscription or crypto for Pro paid ahead, where periodEnd is the paid-until and nothing renews. interval is month or year; status paused with resumesAt is a break in billing (Pro withheld, profiles kept). Never returns a token. Read-only: signing in and paying happen in the Mosaic window.
No arguments.
delete_account
Delete the Mosaic account this app is signed in to — at the account server, for good — and sign this Mosaic out. Irreversible: the account, its sign-in sessions on every computer and its support history go; a live subscription is cancelled first so the card is not charged again. Every browser is stopped first (one that will not close is named and nothing is deleted), then Mosaic restarts on its sign-in screen. The account's profiles can never be opened again: they stay on this disk, encrypted, but their key belonged to the account and is deleted with it — and they were never on the server, so no copy exists anywhere. This computer keeps its count of profiles made, so a new account here starts where the old one stopped. Requires the account password, every time; a wrong one deletes nothing. The root (operator) account cannot be deleted from the app.
| Argument | Type | What it is |
|---|---|---|
passwordrequired | string | The account's password, typed again: the confirmation |
api_activity
What the API is doing right now: which keys have driven Mosaic in the last five minutes, how many profiles they are running, every profile any of them has touched — each a full profile row carrying its project and the key that touched it — and a feed of recent actions in plain words ("Created profile — Ads scraper 4"). profiles and actions cover the same retained events, so a profile named in the feed is always in the list. The same picture the interface shows on its API activity page. Useful before you start work: if another key is already driving a profile, you are about to fight it. Never returns a key, only the name its owner gave it.
No arguments.
set_traffic_inspection
Turn traffic inspection on or off, and read where it points. With it on, every profile launched from now on is routed through an inspecting proxy — Proxyman, Charles, mitmproxy, Fiddler, Burp — so its requests can be read. Call with no arguments to read the state without changing it.
Put it back the way you found it. The returned was is the state before your call. If it was off and you turned it on, turn it off again when you are finished; if it was already on, leave it on — the operator has something open and watching, and switching it off mid-session takes their tooling away with nothing saying why. This is the whole discipline of this tool: it is a global switch on a machine somebody else is using.
Only launches are affected, and only from the next one: a browser already running keeps the chain it started with, so turning this on does not begin recording a session in progress — restart the profile.
address is host:port, stored normalised — and on a machine with Proxyman you can leave it alone, because Mosaic asks the inspector where it listens. A profile with a proxy of its own needs the inspector forwarding back to Mosaic (browser → inspector → Mosaic → the exit), and Mosaic arranges that itself through the inspector’s own command line, putting it back when inspection is switched off. There is nothing to ask the operator to configure. The chain is measured before each window opens and a launch is refused with a 502 rather than sent out of this computer’s address — so a start that succeeds is a start that is correctly chained.
A profile that is already running is not affected, in either direction. Chromium is handed its proxy on the command line and there is no way in from outside, so switching this on leaves every open browser going out exactly as it was, and switching it off leaves an open one still going through the inspector. GET /running reports inspectedBy per profile — what that browser was actually launched through — so the disagreement is readable rather than guessed at. Restarting the profile is what moves it.
HTTPS also needs the inspector’s CA certificate trusted on this machine, which is something only the operator can do. If pages fail to load in an inspected profile, that is the first thing to ask about.
| Argument | Type | What it is |
|---|---|---|
enabled | boolean | Turn inspection on or off. Omit to read the current state without changing it. |
address | string | Where the inspecting proxy listens, host:port — e.g. 127.0.0.1:9090, which is Proxyman’s default. Omit to keep the stored address. |
get_settings
Mosaic’s own settings: the API and MCP ports, the default engine, the concurrency cap, the trash retention window and where profile data lives. Read-only on purpose — changing a port or the data directory from here would move the ground under the client that is talking to it.
No arguments.
list_engines
List browser engines: whether the browser is installed, its version, and whether it is the copy bundled with the app or a newer downloaded one. install reports a download in progress and the last failure, and install.update whether a newer engine is published (available, latest, current) — an optional update, offered and never installed on its own; engine_install takes it.
No arguments.
engine_available
What the published browser is, which build this machine can take, and whether it is newer than the one in use (updateAvailable). Reads only — nothing is downloaded. The source is engineManifestUrl when set, otherwise the Mosaic account server (sent this install’s session). A manifest with any field missing, unknown, not https or loopback is refused rather than repaired, because it decides which executable holds every cookie jar on this machine.
No arguments.
engine_install
Download and install the published browser for this machine — an engine update, independent of the app. About a gigabyte; the checksum is verified before anything is unpacked and the binary is asked its version before it is used. The copy bundled with the app is never touched; the download wins from the next launch because it is newer. Refuses while a profile is running on a previously downloaded copy, because that is the one being replaced.
No arguments.
update_settings
Change Mosaic’s settings. PATCH-shaped: an absent field is no change. An unknown key is refused and named rather than dropped, because a misspelled setting and a stored one are byte-identical from out here. Read get_settings first for the field names — until now exactly one setting was reachable from this surface, through set_traffic_inspection.
No arguments.
check_for_update
Is there a newer Mosaic. Reads the release manifest at downloads.mosaicbrowser.com — public, no credential — and returns the updater's whole state: phase (idle, checking, up-to-date, available, downloading, ready, installing, error), current, latest with its release notes, download progress, runningProfiles, restartWhenIdle, and replaceable/blocked for a copy that cannot replace itself (a development build, one outside /Applications, or a Windows copy from the portable zip rather than the installer). A check that could not run is reported in error with the reason, never as "no update"; error.quiet is true when it was only the network, which is retried by itself. With updateAutoDownload on, a found update starts downloading in the background. cached: true reads the state without contacting anything.
| Argument | Type | What it is |
|---|---|---|
cached | boolean | Read the state without checking. Default false. |
download_update
Fetch the newer version and verify it, without installing anything. The archive is checked against the SHA-256 in the manifest before it is unpacked or run, the download is asked its own version and has to agree (the bundle on macOS, the installer's version resource on Windows), and when this copy is Developer-ID signed the new one must be signed by the same team and pass codesign --verify. Downloading is allowed while profiles run — it touches nothing they use; restarting is where they are counted. Returns { version, bytes } once the update is ready.
No arguments.
apply_update
Restart Mosaic into the downloaded version. Never restarts under a running profile: with browsers open, when: "now" is refused with the count unless stopProfiles: true asks for them to be stopped first (each through the browser's own exit, so cookies are written); when: "when-idle" records the wish and restarts by itself once the last profile closes; when: "cancel" withdraws that. A restart ends the process this tool is served from, so it is the last call in a session: the answer is returned first and the restart follows a moment later. On macOS the old application is moved aside rather than deleted, and a swap that fails puts it back; on Windows the verified installer runs silently and starts the new version.
| Argument | Type | What it is |
|---|---|---|
when | "now" | "when-idle" | "cancel" | Default now. |
stopProfiles | boolean | With when: now, stop running profiles first. Default false. |
app_info
What this installation is: the version, the platform and architecture it is running on, where its data lives, and whether the REST and MCP servers are up. The first call to make when a report has to say which build it came from.
No arguments.
Run the API on your own profiles
The REST API and the MCP server are part of Pro: $49 a month, with the first 14 days free. Free has every browser feature and no API key.
Mosaic is a desktop app
Email yourself the link and open it on your computer.