---
title: "Groups, presets & bulk"
description: "Turning one profile into fifty: groups as labels, presets as stored templates, the bulk endpoints and their partial-failure shape, and how an agent leases a whole fleet at once."
canonical: "https://scalebrowser.net/docs/fleet"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://scalebrowser.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Groups, presets & bulk

> Turning one profile into fifty: groups as labels, presets as stored templates, the bulk endpoints and their partial-failure shape, and how an agent leases a whole fleet at once.

Profiles are unlimited; what your plan limits is how many run at the same time. So a fleet of two hundred profiles running five at a time is the normal shape of this product, and this page is the machinery for it.

## Groups
A group is a flat label a profile belongs to. Nothing more: no nesting, no inherited settings, no permissions.

| Call                                | What it does                                                                                |
| ----------------------------------- | --------------------------------------------------------------------------------------------- |
| `GET` · `POST /v1/groups`           | List, create.                                                                                |
| `GET` · `PATCH` · `DELETE /v1/groups/:id` | Fetch, rename, delete. Deleting a group leaves its profiles alone; their `group_id` becomes `null`. |

Groups are what a fleet lease narrows by, and what the profile list filters on.

## Presets
A preset is a stored template with two halves, and the split is the whole idea:

- **`constraints`** shape the identity that gets generated. Exactly one axis is honest here: `country`. [Profiles & personas](/docs/profiles#what-you-may-constrain) explains why the list is that short.
- **`config`** is the operating configuration each profile is stamped with: geo mode, group, proxy handling, and so on.

| Call                                 | What it does                        |
| ------------------------------------ | ------------------------------------- |
| `GET` · `POST /v1/presets`           | List, create.                        |
| `GET` · `PATCH` · `DELETE /v1/presets/:id` | Fetch, update, delete.          |

Read the allowed countries from `GET /v1/persona/constraints` rather than writing your own list.

## Making a fleet
`POST /v1/bulk/profiles` stamps out N profiles from a preset. Each gets its own identity; they share the preset's settings.

```bash
$ curl -X POST http://127.0.0.1:8787/v1/bulk/profiles \
    -H "Authorization: Bearer $SCALEBROWSER_BEARER_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"preset_id":"ps_31a0","count":50,"name_prefix":"shop-"}'
```

The ceiling is 1000 per call. Over MCP the same operation is capped at 100, which is a narrower limit for an agent on purpose rather than a different implementation.

<Note>

**All or nothing.** A failure part way through rolls back everything the call already created. Fifty half-made profiles are worse than none, because you cannot tell from the outside which of them are complete.

</Note>

## The bulk operations
| Call                                 | Body                       | What it does                                        |
| ------------------------------------ | -------------------------- | ----------------------------------------------------- |
| `POST /v1/bulk/start`                | `{ ids, headless? }`       | Start each, one after another.                       |
| `POST /v1/bulk/stop`                 | `{ ids }`                  | Stop each.                                            |
| `POST /v1/bulk/delete`               | `{ ids }`                  | Delete each, with its browser directory.              |
| `POST /v1/bulk/assign-proxy`         | `{ ids, proxy_id }`        | Set the proxy on each. `null` clears it.              |
| `POST /v1/bulk/assign-extensions`    | `{ ids, ext_refs }`        | **Replace** each profile's extension set. An empty array gives them none. |

Every one of them answers with a per-id list of `{ id, ok, error? }`, so one bad id does not fail the batch.

`bulk/start` adds three fields on top: `started` (how many browsers came up), `remaining` (ids never attempted) and `stopped_reason` when it ended early. `headless` is one decision for the whole batch.

<Warning>

**A bulk start stops at the first capacity refusal.** Running out of memory or slots says nothing about the profile that happened to be next, so continuing would report fifty identical failures that read like fifty broken profiles.

Look at `remaining`: those ids were never tried, and retrying them once capacity frees up is the right move. Any *other* per-profile error does not stop the run.

</Warning>

## From an agent
Two tools cover this, both in the `management` set:

`preset.instantiate` is the bulk create, capped at 100.

`profile.batch` is the other four, plus delete, as one call with an `action`:

```json
{ "action": "assign_proxy", "ids": ["pr_9c21e4", "pr_0f7b12"], "proxy_id": "px_7f3a" }
```

`action` is one of `start`, `stop`, `delete`, `assign_proxy`, `assign_extensions`, and `ids` takes at most 100. A profile somebody else is actively leasing is refused rather than acted on.

<Warning>

**`action: "delete"` is real.** It stops the browser, drops the profile and reclaims its disk, which takes every login inside it. It is the one destructive tool the Windows desktop client serves out of the box, and there is no confirmation step anywhere in this layer.

</Warning>

## Leasing a fleet
`lease_fleet` is the fleet shape of `lease_profile`: reserve several profiles at once and get a handle for each. Use it when the work is the same across many identities.

It hands back whatever it managed rather than failing. If the machine fills up or the group runs out, you get the handles it did issue plus the reason it stopped. Release each one separately with `release_profile`, because how each run went is a different answer per profile.

<Note>

**Order survives the concurrency limit.** Twenty profiles with five slots is the normal case, and the thing that says what is still outstanding after a batch is interrupted is the profile's own task list, not the batch call. See [Tasks & memory](/docs/agents/tasks).

</Note>

## Listing at fleet scale
`GET /v1/profiles` pages: `limit` (default 100), `offset`, `sort`, `order`, and the filters `group`, `state`, `q` (name substring) and `enabled`.

`GET /v1/profiles/ids` takes the same filters, ignores paging and answers `{ count, ids }`. That is what a "select all matches" action needs, and it is why the route exists separately: fetching 2000 full profile objects to collect their ids is a waste on both ends.

`GET /v1/profiles/count` answers the other question a paged list cannot: how many there are. It takes `group` and `q`, and reports `{ total, stopped, starting, running, crashed }`, so "how big is the fleet" and "how many are running right now" cost one request together rather than a walk through every page.

## Next
- [Profiles & personas](/docs/profiles): what each of these profiles is made of.
- [Proxies & exits](/docs/proxies): why fifty profiles behind one address is the thing to avoid.
- [Plans & limits](/docs/account/plans): what "at the same time" costs.
- [The management app](/docs/ui): the same operations with a mouse.
