# Recipes for multi-account apps

> How an app that posts, reads inboxes or collects data for many social accounts should use Browlix — one binding per account, identity first, holds per job, people for challenges, and the app's own state kept by the app.

These recipes are for apps that work with many accounts on sites such as Facebook, Instagram, LinkedIn or X. They describe how to use Browlix, not how to automate a particular site. Every piece of code they rely on is in the [sample app](https://browlix.com/en/docs/sample-app) and [Move from a local Chrome profile](https://browlix.com/en/docs/migrate-from-chrome), both run on Browlix's lab machines.

Use them within each site's terms and the [acceptable use policy](https://browlix.com/en/legal/acceptable-use). Browlix does not promise that a site will never restrict an account.

## 1. One binding per account

Bind each account once: `bindings.create` with your `app_id` and the account's `external_account_id`, pointing at its profile. Look it up with `bindings.list` before creating, and on `CONFLICT` use the binding that won (the sample app shows this). Keep `metadata` small and non-secret — credential-like keys are refused.

Group profiles by team or client with `groups.*` and label them with `tags.*`; both can be renamed or deleted from the API.

## 2. Identity before any action

A browser that opens is not proof of which account is signed in. After attaching, read the signed-in account from the site and compare it with the binding's `external_account_id` before doing anything:

| Site | Read from the page after it loads |
|---|---|
| Facebook | The signed-in user's numeric ID |
| Instagram | The signed-in viewer's account |
| LinkedIn | The signed-in member's identifier (URN) |
| X | The signed-in viewer, read again after every open |

If it does not match, or nobody is signed in, stop: do not post, read or retry under that binding. Mark the account in your app and let a person look at it.

## 3. Hold the browser per job

- `acquireSession` with a `holderRef` that names the worker process. The SDK renews the hold while the job runs.
- Between jobs on the same account, `detach({ keepWarmSeconds })` keeps the browser open so the next job starts at once.
- At the end of the day, detach with `keepWarmSeconds: 0` and `stopSession`: data is sealed and synced after the browser closes.
- `BUSY` means a person or another app holds the browser. Wait and try later; never take it over.
- `FENCED` means your hold was superseded. Stop acting on that page immediately — another worker owns it now.

See [Hold a browser from your app](https://browlix.com/en/docs/app-sessions) for the full lease rules.

## 4. Challenges go to a person

When a site asks for a code, a confirmation, a captcha or an identity check, stop the job and hand the account to a person, who can finish it in the web app's live view while your app waits. Browlix has no captcha solving and your app should not add one.

## 5. The app keeps its own state

Your job queue, schedules, do-not-contact lists, per-account quotas and outgoing-message outbox belong to your app. A session closing is not a job completing: record the job's outcome in your app before you let go of the browser, and make sending idempotent on your side so a retried job never sends twice.

## 6. When something goes wrong

| Signal | What to do |
|---|---|
| `RECOVERY_REQUIRED` | The previous session ended uncertainly. Decide with `sessions.recover`, then open again — see [Sessions](https://browlix.com/en/docs/sessions) |
| A `session.failed` event, or the session leaving `ready` | Stop the job; retry later |
| A machine goes offline | Holds lapse. The profile opens on another machine once its last session's data is synced; until then opening it answers `SYNC_PENDING` |

Follow events with [`sessions.events`](https://browlix.com/en/docs/reference/sessions.events) or [webhooks](https://browlix.com/en/docs/webhooks).

## 7. Moving accounts in

Move accounts from local Chrome directories one at a time, verify each identity, and keep the old directory until you are sure — [Move from a local Chrome profile](https://browlix.com/en/docs/migrate-from-chrome).

## Tell us what is missing

If an operation you need is not in the API, an AI agent working on your integration can file it with `feedback_submit`, or you can — see [Feedback from agents](https://browlix.com/en/docs/feedback).
