# Tabs: Mosaic API reference

> Tabs in Mosaic’s local REST API: 11 routes, each with its method, path, fields, what it returns and the errors it names.

Source: https://mosaicbrowser.com/docs/api/tabs

**Automation** REST API

## Tabs

Read and drive the tabs a running profile already has open. These attach to an existing tab rather than a scratch one, because the point is to see what the person sees. They existed only as MCP tools until 2026-09-15; the routes here are the same capability on the REST surface, where the project’s own rule always required them.

- [GETList open tabs](#list-tabs)
- [POSTOpen a tab](#open-tab)
- [DELETEClose a tab](#close-tab)
- [POSTNavigate a tab](#navigate-tab)
- [GETRead a page](#read-tab)
- [GETScreenshot a tab](#screenshot-tab)
- [POSTRun script in a tab](#evaluate-tab)
- [POSTClick a selector](#click-tab)
- [POSTRecord requests for a window](#watch-network-tab)
- [GETRead site storage](#read-tab-storage)
- [POSTWrite site storage](#write-tab-storage)

## [List open tabs](#list-tabs)

GET`/api/v1/profiles/:id/tabs`

Every page target the profile has open, newest last, `chrome://` pages included. The ids are what every other tab and page route takes as `tabId`.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Returns

`{ total, tabs: [{ id, title, url, type, attached }] }`

#### Errors

- `400` — the profile is not running.

## [Open a tab](#open-tab)

POST`/api/v1/profiles/:id/tabs`

Opens a URL in a new tab. The browser navigates it itself, so this returns as soon as the tab exists rather than when the page has loaded — wait for it with `POST /profiles/:id/page/wait` or read it with a page route, which do wait.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Body

| Field | Type | What it is |
| --- | --- | --- |
| `url`required | `string` | Absolute URL to open. |

#### Returns

The new tab.

## [Close a tab](#close-tab)

DELETE`/api/v1/profiles/:id/tabs/:tabId`

Closes one tab. **Closing the last one stops the profile**, a couple of seconds later, through the same clean shutdown `POST /profiles/:id/stop` runs — cookies flushed, session written, exit marked clean. It used to leave the browser running: macOS keeps an application alive with no windows, so what was left was four processes, a Dock tile with nothing under it, and `GET /running` still reporting the profile. Opening another tab inside that couple of seconds cancels it, so close-then-open is not a race. A one-time profile retires to the trash, exactly as it would have on `stop`.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |
| `tabId`required | `string` | The tab to close. |

#### Returns

`{ closed: true, tabId }`

#### Errors

- `404` — no profile with that id, or it is not running.

## [Navigate a tab](#navigate-tab)

POST`/api/v1/profiles/:id/tabs/navigate`

Navigates an existing tab and waits for its load event.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Body

| Field | Type | What it is |
| --- | --- | --- |
| `url`required | `string` | Absolute URL. |
| `tabId` | `string` | Tab id from `GET /profiles/:id/tabs`. Omit for the tab with content on it. |

#### Returns

`{ tabId, url }`

## [Read a page](#read-tab)

GET`/api/v1/profiles/:id/tabs/read`

The visible text of the page, its title, its URL and its links. Uses `innerText` rather than `textContent`, so it is what a person sees rather than the contents of every `<script>` and `<style>` — which on a detection site is the collector’s own source.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Query parameters

| Field | Type | What it is |
| --- | --- | --- |
| `tabId` | `string` | Tab id from `GET /profiles/:id/tabs`. Omit for the tab with content on it. |
| `html` | `boolean` | Also return `document.documentElement.outerHTML`. |
| `maxChars` | `number` | Cap on characters, 200–200000 (default 20000). |

#### Returns

`{ url, title, text, links, html? }`

## [Screenshot a tab](#screenshot-tab)

GET`/api/v1/profiles/:id/tabs/screenshot`

A PNG of the tab, base64, for when the text is not the answer.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Query parameters

| Field | Type | What it is |
| --- | --- | --- |
| `tabId` | `string` | Tab id from `GET /profiles/:id/tabs`. Omit for the tab with content on it. |
| `fullPage` | `boolean` | Capture beyond the viewport. |

#### Returns

`{ format: "png", base64 }`

## [Run script in a tab](#evaluate-tab)

POST`/api/v1/profiles/:id/tabs/evaluate`

Evaluates a JavaScript expression in the page’s own world and returns its value, so it sees the page’s variables and the fingerprint exactly as the page does. An `await` is fine; the result is awaited. Return something JSON can carry. For the invisible world, and for refs, use `POST /profiles/:id/page/evaluate`.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Body

| Field | Type | What it is |
| --- | --- | --- |
| `expression`required | `string` | A JavaScript expression. |
| `tabId` | `string` | Tab id from `GET /profiles/:id/tabs`. Omit for the tab with content on it. |

#### Returns

`{ value }`

## [Click a selector](#click-tab)

POST`/api/v1/profiles/:id/tabs/click`

Clicks the element a CSS selector names, as a real mouse event at its centre. Deliberately not `element.click()`, which dispatches an untrusted event with no preceding move. `POST /profiles/:id/page/click` is the fuller version: it scrolls with a real wheel first and moves along a human trajectory.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Body

| Field | Type | What it is |
| --- | --- | --- |
| `selector`required | `string` | CSS selector. |
| `tabId` | `string` | Tab id from `GET /profiles/:id/tabs`. Omit for the tab with content on it. |

#### Returns

`{ x, y }` — where it clicked.

## [Record requests for a window](#watch-network-tab)

POST`/api/v1/profiles/:id/tabs/watch-network`

Records every request the tab makes for a number of seconds and returns them. Answers what a screenshot cannot: which third party a page really calls, whether a request went out at all, where a detector posted its verdict. The recording domain is enabled only for the window you ask for and turned off again. For recording that spans several actions, use `POST /profiles/:id/page/network/start`.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Body

| Field | Type | What it is |
| --- | --- | --- |
| `seconds` | `number` | How long to record, 1–60 (default 8). |
| `tabId` | `string` | Tab id from `GET /profiles/:id/tabs`. Omit for the tab with content on it. |

#### Returns

`{ total, requests: [{ method, url, resourceType, status, mimeType, fromCache, failed }] }`

## [Read site storage](#read-tab-storage)

GET`/api/v1/profiles/:id/tabs/storage`

What the site has stored in this profile: 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.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Query parameters

| Field | Type | What it is |
| --- | --- | --- |
| `tabId` | `string` | Tab id from `GET /profiles/:id/tabs`. Omit for the tab with content on it. |

#### Returns

`{ local, session, cookies }`

## [Write site storage](#write-tab-storage)

POST`/api/v1/profiles/:id/tabs/storage`

Sets or removes `localStorage` or `sessionStorage` keys for the tab’s origin. A `null` value removes the key.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Body

| Field | Type | What it is |
| --- | --- | --- |
| `which`required | `"local" \| "session"` | Which store to write. |
| `entries`required | `Record<string, string \| null>` | Keys to set; `null` removes. |
| `tabId` | `string` | Tab id from `GET /profiles/:id/tabs`. Omit for the tab with content on it. |

#### Returns

`{ written }`

## 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.
