VeilBrowserDocs

Limits

Plan limits, the null-means-unlimited convention, and exactly where each ceiling is enforced.

Every organization has a subscription that carries four limits. Knowing which of them block a request — and which are only recorded — saves a lot of debugging.

The four limits

Prop

Type

Read the current values for your organization from GET /v1/profiles/stats, or for every plan from the public GET /v1/plans.

null means unlimited

Limits use an explicit null = unlimited convention. A custom enterprise plan can set unlimited profiles and unlimited concurrency and still be metered for visibility. Treat null as "no ceiling", never as zero.

Where each is enforced

LimitEnforced atFailure
profileLimitPOST /v1/profiles, POST /v1/profiles/:id/duplicate403 with AUTHORIZATION_ERROR
profileLimit (as concurrency)POST /v1/license/authorize, before every launch402 with reason: "concurrency_limit"
memberLimitPOST /v1/organizations/:id/members/invite403 with AUTHORIZATION_ERROR
apiRpmLimit / apiRphLimitNot enforced on requests today

Profiles

Creating or duplicating a profile counts the organization's existing profiles first. At the ceiling, the request fails with a detail object carrying current and limit, so you can show the user exactly how far over they are.

Concurrency

Concurrency is counted organization-wide, not per host. Before launching, a worker calls POST /v1/license/authorize; the cloud counts running profile sessions across the whole organization and compares against the ceiling.

In the shipped implementation the concurrency ceiling is the organization's profile limit. There is no separate concurrency plan field, so a 200-profile plan permits 200 simultaneous browsers.

Authorization is fail-closed: if the cloud denies the request or is unreachable, the worker does not launch. Sessions already running are never killed. See Licensing & concurrency.

API rate limits

RPM and RPH are recorded, not enforced

apiRpmLimit and apiRphLimit are plan metadata. They are stored on the subscription, surfaced through GET /v1/plans and the dashboard, and used to compute remaining quota for display — but no middleware currently rejects a request for exceeding them. Do not design a client that relies on the API throttling you; build your own pacing.

The one place a rate limit is genuinely enforced is the public contact endpoint, which allows five submissions per hour per IP.

Add-ons

Paid plans can extend the base ceilings with add-ons. The effective limit is the plan's base value plus any purchased additions, snapshotted onto the subscription at purchase time:

effective = baseLimit + additional

Because the base values are snapshotted, a later change to the plan catalog does not retroactively alter an existing subscription. Both apiRpmLimit and apiRphLimit stay null when the base is null, regardless of add-ons.

Checking usage

GET /v1/profiles/stats returns current consumption alongside the ceilings:

{
  "success": true,
  "data": {
    "totalProfiles": 143,
    "activeProfiles": 12,
    "profileLimit": 200,
    "memberLimit": 6,
    "apiRpmLimit": 100,
    "apiRphLimit": 2000
  }
}

activeProfiles is the number currently running, which is what the concurrency check compares against.

Next steps

Was this page helpful?

On this page