---
title: "How to create many browser profiles with one proxy each"
description: "Import a proxy list, make up to 100 Donut Browser profiles at once from a template, and give each profile its own proxy, in the app or with the local API."
url: "https://donutbrowser.com/docs/guides/bulk-create-profiles/"
---

# How to create many browser profiles, each with its own proxy

One account per profile and one exit IP per account keeps accounts apart. With 50 accounts, that means 50 profiles and 50 proxies. Donut Browser imports a proxy list in one paste, makes up to 100 profiles per batch from a template, and pairs profiles with proxies in order. You need Donut Browser [installed](https://donutbrowser.com/docs/install), the Wayfern engine downloaded, and a list of proxies from your provider.

## Limits to plan for

Every new profile gets a new device from the Wayfern engine, and new devices have an hourly limit (a rolling 60 minutes):

| Plan | New profiles an hour | Past the limit |
| --- | --- | --- |
| Free | 8 below 40 profiles, 6 below 80, 4 below 120, then 2 | A warning for one profile. A batch stops at the limit. Going on can block new devices for 24 hours or more. |
| Solo | 10 | Refused until the hour has room |
| Pro, Team, Enterprise | 100 | Refused until the hour has room |

A batch holds 1 to 100 profiles. Local profiles are unlimited on every plan.

## 1. Import the proxies

1. Open **Network** (**Cmd/Ctrl+Shift+N**) → **Proxies** and click **Import**.
2. Drop a `.txt` or `.json` file, or paste the list with **Cmd/Ctrl+V**.
3. Set **Name Prefix**. With the prefix `Shop`, the proxies are named "Shop Proxy 1", "Shop Proxy 2" and so on, after the numbers already in use.
4. Check the list under "Proxies to import" and click **Import N Proxies**.

A text list has one proxy per line. These forms work:

```text
socks5://user:pass@us1.example.com:1080
http://user:pass@us2.example.com:8080
us3.example.com:8080:user:pass
user:pass:us4.example.com:8080
user:pass@us5.example.com:8080
us6.example.com:8080
```

A line without a scheme is read as HTTP. Lines that start with `#` are skipped. When a line of four parts can be read both as `host:port:username:password` and as `username:password:host:port`, Donut asks you to pick the right one before the import.

Then select the new proxies and click **Check selected**. Donut checks 4 at a time and reports "Checks done. Passed: N. Failed: N." Delete or replace the failed ones now: a profile cannot be created with a proxy that does not work.

## 2. Save a template

Set up one profile the way every profile in the batch should be: group, tags, status, extension group, DNS blocklist, start pages, operating system and WebRTC mode. Leave its proxy empty, because a template keeps the profile's proxy and gives it to every new profile. Then open its panel and choose **Save as template**. New profiles made from the template get its settings and their own new device. The name, the note and the device stay with the original profile.

You can skip this step and set the options in **Create new profile** directly.

## 3. Create the profiles

1. On the **Profiles** page, click **New** (**Cmd/Ctrl+N**).
2. In **Create new profile**, choose the **Template**.
3. Enter a name, for example `Shop`, and set **Number of profiles**. The dialog shows how many more profiles the hour allows.
4. Leave the proxy picker on "No proxy / VPN" when each profile needs its own proxy. A proxy chosen here goes to every profile in the batch.
5. Click **Create**. Donut shows "Creating N of M" and a **Stop** button.

The profiles are named "Shop 1", "Shop 2" and so on, after the numbers already in use. If you stop the batch, or it reaches the hourly limit, the profiles made so far stay.

## 4. Give each profile its own proxy

1. Select the new profiles in the table.
2. In the action bar, open **More actions** → **Distribute proxies**.
3. In the dialog, tick the profiles and the proxies. The first profile gets the first proxy, the second gets the second, and so on. There is no wrap-around: extra profiles or proxies stay as they are.
4. Click **Distribute**. The toast reads "Assigned a proxy to N profile(s)".

By default, a proxy that another profile already uses is held back. Turn on **Allow sharing a proxy** only if you mean to put two profiles on one IP. Running profiles are not changed.

## 5. Match each profile to its proxy

These profiles were made without a proxy, so their timezone and language come from your own connection. At the first launch, Donut compares them with the new proxy and shows **Launch blocked**. Click **Match fingerprint to proxy**, then launch again. See [How to match a browser's timezone and language to its proxy](https://donutbrowser.com/docs/guides/match-timezone-to-proxy).

The API route below avoids this step, because each profile is made through its own proxy.

## Do it all with the API

The [local API](https://donutbrowser.com/docs/quickstart) does the same in three calls, on every plan. A template's `proxy_ids` list spreads the proxies over the new profiles, one each in turn, and each profile gets its location from its own proxy. Export the token as `DONUT_API_KEY` first.

```bash
API=http://127.0.0.1:10108/v1
AUTH="Authorization: Bearer $DONUT_API_KEY"

# 1. Import the proxies and keep their IDs.
PROXY_IDS=$(jq -n --rawfile list proxies.txt '{format: "txt", content: $list, name_prefix: "Shop"}' |
  curl -sS -X POST "$API/proxies/import" -H "$AUTH" -H "Content-Type: application/json" --data-binary @- |
  jq '[.proxies[].id]')

# 2. A template that spreads them.
TEMPLATE_ID=$(jq -n --argjson ids "$PROXY_IDS" \
  '{name: "Shop accounts", settings: {name_prefix: "Shop", tags: ["shop"], proxy_ids: $ids}}' |
  curl -sS -X POST "$API/templates" -H "$AUTH" -H "Content-Type: application/json" --data-binary @- |
  jq -r '.id')

# 3. One profile per proxy.
COUNT=$(echo "$PROXY_IDS" | jq length)
curl -sS -X POST "$API/templates/$TEMPLATE_ID/profiles" -H "$AUTH" \
  -H "Content-Type: application/json" -d "{\"count\": $COUNT}" | jq '{made: (.profiles | length), error}'
```

```python
import os, pathlib, requests

API = "http://127.0.0.1:10108/v1"
s = requests.Session()
s.headers["Authorization"] = f"Bearer {os.environ['DONUT_API_KEY']}"

imported = s.post(f"{API}/proxies/import", json={
    "format": "txt",
    "content": pathlib.Path("proxies.txt").read_text(),
    "name_prefix": "Shop",
}, timeout=30).json()
proxy_ids = [p["id"] for p in imported["proxies"]]
print(imported["imported_count"], "imported", imported["errors"])

template = s.post(f"{API}/templates", json={
    "name": "Shop accounts",
    "settings": {"name_prefix": "Shop", "tags": ["shop"], "proxy_ids": proxy_ids},
}, timeout=30).json()

result = s.post(f"{API}/templates/{template['id']}/profiles",
                json={"count": min(len(proxy_ids), 100)}, timeout=600)
body = result.json()
print(result.status_code, len(body.get("profiles", [])), "made", body.get("error"))
```

Creating a profile takes time, so give the last call a long timeout. Donut checks each proxy once before the batch starts.

| Route | Body | Returns |
| --- | --- | --- |
| `POST /v1/proxies/import` | `format` (`txt` or `json`), `content`, `name_prefix` | `imported_count`, `skipped_count`, `errors`, `proxies` |
| `POST /v1/templates` | `name` (1 to 60 characters, unique), `settings` | The template with its `id` |
| `POST /v1/templates/{id}/profiles` | `count` (1 to 100), optional `name` | `profiles` made so far, and `error` when the batch stopped early |
| `POST /v1/profiles/distribute-proxies` | `pairs`: a list of `profile_id` and `proxy_id` | One result per pair, with `ok` and `error` |

See [Templates](https://donutbrowser.com/docs/rest-api#templates) in the API reference.

## Troubleshooting

| Error | Status | What to do |
| --- | --- | --- |
| `PROFILE_GENERATION_LIMIT_REACHED` | `429` when nothing was made, or in `error` with status `200` | The hour is used up. `params.retryAfterSeconds` says how long to wait. There is no `Retry-After` header. |
| `WAYFERN_GENERATION_LIMIT_REACHED`: "Temporary fingerprint generation limit reached. Try again later." | `429` | The engine refused new devices. Wait before the next batch. |
| `BULK_CREATE_COUNT_INVALID` | `400` | `count` is outside 1 to 100. |
| `BULK_CREATE_BUSY` | `409` | Another batch is running. Wait for it, or stop it in the app. |
| `BROWSER_NOT_DOWNLOADED` | `400` | Download Wayfern in the app first. |
| A proxy or VPN that does not work | `400` | Check the proxies and remove the failed ones. |

In the app, a stopped batch reads "Created N of M profiles." followed by the reason.

## Related

- [Profiles and fingerprints](https://donutbrowser.com/docs/profiles#templates-clones-and-bulk-edits): templates, clones and bulk edits.
- [How to run several browser profiles at once with Playwright](https://donutbrowser.com/docs/guides/run-profiles-in-parallel)
- [How to use a SOCKS5 proxy with a username and password](https://donutbrowser.com/docs/guides/socks5-proxy-with-password)
- [How to rotate a proxy's IP with a change-IP link](https://donutbrowser.com/docs/guides/rotate-proxy-ip)

Pro raises the limit to 100 new profiles an hour. [Compare the plans](https://donutbrowser.com/pricing).
