ScalebrowserDOCS

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.

CallWhat it does
GET · POST /v1/groupsList, create.
GET · PATCH · DELETE /v1/groups/:idFetch, 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 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.
CallWhat it does
GET · POST /v1/presetsList, create.
GET · PATCH · DELETE /v1/presets/:idFetch, 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.

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.

The bulk operations

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

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.

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.

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.

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