AdsPower proxy setup: profile fields, bulk import and the checks before first login
I keep 60 to 80 AdsPower profiles alive at any given time. The browser handles the fingerprint side of that work. The address side is mine, and for a long stretch I handled it badly.
One failure rewrote my whole procedure, and it was a quiet failure. A profile opened, the built in proxy check reported success, the account loaded, and four days later that account asked for a phone number. Going back through the profile I found WebRTC sitting on its default mode and a name lookup that had left over my own connection during the first page load. AdsPower had reported success because success, to that button, means the endpoint answered one request.
What follows is the procedure I use today, written as steps with a verification after each one. Every section ends with the thing I look at before moving on. The sequence matches a real setup: the fields in the profile card, the difference between a saved entry and a proxy bound to one profile, the row shapes that survive a bulk import, the built in test and its blind spots, the three checks before a first login, the layout of profiles across addresses, the local API, credential storage, and the errors that greet you at profile start. Endpoint shapes and numbers come from profiles running on my own machines while I write this.
The proxy fields in the profile card, field by field
A new profile opens with two blocks: fingerprint on one side, proxy on the other. The proxy block holds six fields on the versions I run, and each one changes something downstream.
The first field decides where the entry comes from. AdsPower accepts a line typed by hand, an entry picked out of proxy management, or a pull from an integration tied to a provider account. My habit is to type the first profile of a batch by hand and save that entry only after it survives the checks further down.
Type comes next: HTTP, HTTPS, SOCKS5, or none. This field does more than label the row. It decides which transport Chromium negotiates on start, and it decides whether the credential pair is offered at all.
Host and port are the two fields nobody fills in wrong. Account and password are the two that break in silence, because a trailing space pasted out of a spreadsheet cell travels straight into the authentication attempt and nothing in the interface shows it to you.
The last field is the IP checker. AdsPower fires one request through the endpoint at a lookup service, then uses the answer to fill timezone, language and location hints on the fingerprint side. Two services can disagree about the same address by a whole zone, which is why this field belongs to setup work.
| Field | What AdsPower does with it | What I look at before saving |
|---|---|---|
| Proxy source | reads a typed line, a saved entry, or a provider pull | saved entries carry an edit history, typed lines do not |
| Proxy type | picks the transport and decides if credentials are sent | SOCKS5 with a login pair needs the type set before the pair is stored |
| Host | the address Chromium dials | no scheme in this box, the type field owns that |
| Port | the listening port on that address | HTTP and SOCKS5 ports differ on the same machine |
| Account | username sent on the proxy challenge | trailing space, and a capital letter the panel did not send |
| Password | secret sent on the same challenge | pasted from the panel, never retyped from a screenshot |
| IP checker | one lookup that fills timezone and language | the zone it returns has to match what I set on the fingerprint tab |
Verification for this step is small and takes ten seconds: save the profile, reopen the card, and read the six fields back. AdsPower normalises some input on save, and reading it back is how you catch a port that landed in the host box or a type that reverted to HTTP.
The shared proxy list and a proxy bound to one profile
AdsPower gives you two places to keep an endpoint, and mixing them up is the most expensive mistake in this whole article.
Proxy management holds saved entries. A profile that points at a saved entry holds a reference, so editing the entry once moves every profile attached to it. That behaviour is a gift when a package rotates its credential pair, and it is a hazard when 40 accounts share one line and that line stops answering. Every one of those 40 profiles goes down together.
A proxy typed into the card belongs to that profile alone. Nothing else moves when you edit it. Nothing else breaks when it dies. The cost is transcription: 40 profiles means 40 edits when something changes.
My split runs along the value of the account inside the profile. Accounts that took weeks to warm up get their own bound line, typed into the card, never shared. Throwaway profiles for reading public pages sit in groups of four on a shared saved entry, because losing four of those at once costs me a coffee break. Pairing endpoints with profiles this way is the part most guides skip, and it matters more than any fingerprint slider; my longer notes on proxy endpoints for antidetect profiles cover the same split from the endpoint side.
There is a third state worth naming. A profile set to "no proxy" opens on your own connection with a full fake fingerprint on top. That combination is the loudest signal you can send, because the fingerprint says one machine and the address says another. I keep a group named LOCAL for the two profiles allowed to do that, and no account ever logs in from that group.
To verify the split, open proxy management and sort by usage count. Any saved entry attached to more than four profiles gets a second look from me, and any entry attached to a profile holding a warmed account gets converted to a bound line on the spot.
Row formats when profiles arrive from a spreadsheet
Bulk import is where most people meet AdsPower's proxy parser, and the parser is stricter than the interface. The import template carries either split columns for the four proxy parts or a single column holding the whole string, and different template versions favour different shapes.
Split columns are the shape I trust. Four cells, four values, no parsing involved: type, host, port, account, password. When a spreadsheet arrives from someone else with everything mashed into one cell, I split it in the sheet before the import runs with a formula, because hand splitting 200 rows produces at least one error every time.
Here is how the shapes I have fed it actually land.
| String in the cell | How the importer reads it | Result |
|---|---|---|
45.153.14.62:8000 | host and port, no credential pair | opens where the machine address is bound in the panel |
45.153.14.62:8000:u17402:k93qmz | four parts split on colons | maps to host, port, account, password |
http://45.153.14.62:8000 | scheme plus host and port | scheme fills the type column, credentials stay empty |
socks5://45.153.14.62:1080 | scheme sets SOCKS5 transport | works, and the type column can be left blank |
u17402:k93qmz@45.153.14.62:8000 | userinfo ahead of the host | accepted by some builds, dropped in silence by others |
http://u17402:k93qmz@45.153.14.62:8000 | full URI form | the shape I use when one column has to carry everything |
45.153.14.62 8000 u17402 k93qmz | spaces where colons belong | the row imports with a broken host and no warning |
The dashboard I pull from hands out lists in exactly two shapes, IP:PORT and IP:PORT:LOGIN:PASS, by link or by file, which lines up with rows two and one in that table with no editing at all. For a batch of 50 profiles I paste the list into a column, run a split formula, and the import goes through untouched. Those SOCKS5 lines exported straight from the panel drop into the template as four columns, and the only cell I add by hand is the type.
One warning about the type column. Some template versions want a word, some want a number, and a mismatch there imports every row as HTTP without a single complaint. After any import I sort the profile list by proxy type and count the rows. If I imported 50 SOCKS5 lines and see 50 HTTP profiles, the type column mapping was wrong and the whole batch gets deleted and redone.
Verification after an import is a count and a spot check: profile count matches row count, then open three random profiles from the middle of the batch and read their proxy cards. Errors from a bad parse cluster, so three samples find them.
The built in connection test, and the parts it leaves out
Every proxy card has a check button. Press it and AdsPower opens a connection through the endpoint to a lookup service, then reports the address it saw, along with country, timezone and language hints. Green text, a few numbers, done.
That test answers exactly one question: did this endpoint accept a connection and pass one request through, at this second. Everything else people read into the green text is imagination.
Here is what the button does not touch. It says nothing about WebRTC, because WebRTC lives in the browser profile and the check runs outside it. It says nothing about where name lookups will go once the profile opens, because a single lookup through the endpoint proves nothing about the resolver Chromium picks later. It says nothing about stability, because one request finishing in 400 ms tells you nothing about a session held for 40 minutes. It says nothing about concurrency, since it opens one socket while your real work opens 30. And it says nothing about agreement between the address and the fingerprint you set on the other tab.
I still press it, for one reason. A red result means the line is wrong or the endpoint is down, and catching that in the card saves a profile start. Treat it as a syntax check on your typing.
The rest belongs to the next step, run inside the profile itself, where the browser stack is the thing being measured.
Three checks before the first login
This is the step my early setup skipped, and the one that cost me the account I described at the top. The profile opens, and before any login form gets touched, three things get proven from inside the browser.
Exit address. Open an echo page in the profile and read the address back. It has to match the host in the proxy card exactly. A mismatch here on a bound package usually means the profile fell back to your own connection during start, which some builds do when the endpoint refuses the first connection.
Name resolution. Load a resolver test page and read which servers answered. Resolvers that belong to your own provider mean the lookup left over your connection while the traffic went through the endpoint, and that split is visible to anything watching timing. With an HTTP endpoint, Chromium sends the hostname inside CONNECT and the proxy resolves it. With SOCKS5 the behaviour varies by build, so I test it every time and treat assumptions as unproven.
WebRTC. The profile's fingerprint tab carries a WebRTC mode, and the mode has to be the one that replaces candidates with the proxy address. Real mode publishes your actual address to any page that asks, through a channel that has nothing to do with the proxy. Disabled mode hides the address and also marks the profile as unusual, since almost no real browser has WebRTC switched off. Replaced is the mode I want, and I verify it with a snippet in the profile's own console.
const pc = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
});
pc.createDataChannel('probe');
pc.onicecandidate = (e) => {
if (e.candidate) console.log(e.candidate.candidate);
};
pc.createOffer().then((o) => pc.setLocalDescription(o));
Any candidate line carrying a public address that differs from the proxy host means the mode is wrong. Private ranges like 192.168.x.x in the candidate list are normal and harmless.
| Check | Where I run it | Pass condition | What a failure means |
|---|---|---|---|
| Exit address | echo page inside the profile | matches the host in the proxy card | fallback to the local connection at start |
| Name resolution | resolver test page inside the profile | answering servers sit behind the endpoint | lookups escaping the tunnel |
| WebRTC | profile console, snippet above | candidates carry the proxy address only | fingerprint tab set to real mode |
| Timezone | echo page, compared to the fingerprint tab | same zone on both sides | IP checker disagreed with your manual setting |
An endpoint that keeps the origin address out of every one of those four rows is doing the job I bought it for, and anonymous endpoints that hide the origin address are the ones I keep for profiles holding real accounts. Four rows, two minutes, one profile. For a batch of 50, I run all four on three profiles and accept the batch if all three pass, because they share one pool and one build.
Laying profiles out across addresses
Once the checks pass, the question turns into arithmetic: how many profiles per endpoint, and how many endpoints per package.
My package gives 1000 threads on the standard tier and up to 3000 on the corporate one, and packages do not stack; buying a second one adds a second pool of threads with its own ceiling. There is one detail that catches people sizing a fleet. A package carries 2 bound addresses, and with both in use the thread ceiling splits between them. Size against 500 whenever two machines are bound at once.
A browser profile is light on threads and heavy on time. One AdsPower profile browsing normally holds 6 to 20 sockets open, spiking during page load and dropping to near zero while a human reads. Against a 500 thread half that gives room for far more profiles than one machine can render, so threads stop being my limit long before RAM does. On a 32 GB box I run 12 profiles at once comfortably and 18 with the fans audible.
The layout that survived contact with reality looks like this. Accounts that matter get one endpoint each, held for the life of the account. Profiles doing read only work share endpoints four to one. Fresh profiles being warmed up get an endpoint from the pool and keep it for the first two weeks, since an account that changes address on day three of its life gets asked for verification more often than one that stays put.
The pool behind my lines runs around 12000 active entries with rotation happening automatically inside it, so a fresh line for a new profile is always a click away in the panel. Access is sold by term with no cap on transfer, which is what makes long browser sessions workable: a profile can sit open all afternoon streaming media in a tab and nothing meters it. For steady account work I keep access booked for the whole month running so the endpoint list under my profiles stays stable, and the endpoints I assign to profile groups come off private hardware, the same way proxy groups work in Dolphin Anty, which is why sessions hold long enough for the layout above to mean anything.
Verification here lives in a spreadsheet. One row per profile, columns for endpoint, group, account, date bound, last check. When a profile misbehaves I sort by endpoint, and twice that sort has shown me three failing profiles sharing one line that had gone bad, which turned a mystery into a single edit.
Driving AdsPower from the local API
Everything above is clickable. At 50 profiles clicking stops scaling, and the local API takes over.
AdsPower exposes an HTTP interface on the machine itself, at local.adspower.net:50325 by default, and the client has to be running for it to answer. First call in any script of mine checks that the client is up.
curl "http://local.adspower.net:50325/status"
-> {"code":0,"data":{},"msg":"success"}
Profile creation carries the proxy inside user_proxy_config. Custom endpoints go in with proxy_soft set to the generic value, since the named values belong to provider integrations.
curl -X POST "http://local.adspower.net:50325/api/v1/user/create" \
-H "Content-Type: application/json" \
-d '{
"name": "batch-c-014",
"group_id": "1937",
"user_proxy_config": {
"proxy_soft": "other",
"proxy_type": "socks5",
"proxy_host": "45.153.14.62",
"proxy_port": "1080",
"proxy_user": "u17402",
"proxy_password": "k93qmz"
},
"fingerprint_config": {
"webrtc": "proxy",
"language": ["en-US", "en"],
"flash": "block"
}
}'
The webrtc key set to the proxy value is the same setting I described two sections up, and setting it at creation time removes the manual step from every profile in the batch. That single line is the highest value thing in this whole request body.
Starting a profile returns the ports an automation library needs.
curl "http://local.adspower.net:50325/api/v1/browser/start?user_id=k11ozz8&ip_tab=1&open_tabs=1"
{
"code": 0,
"data": {
"ws": {
"puppeteer": "ws://127.0.0.1:52341/devtools/browser/9f2c...",
"selenium": "127.0.0.1:52341"
},
"debug_port": "52341",
"webdriver": "C:\\...\\chromedriver.exe"
},
"msg": "success"
}
With ip_tab=1 the profile opens its own address check tab on start, which turns my exit address verification into something that happens on every launch with no extra work. From there a script attaches over the returned socket.
const puppeteer = require('puppeteer-core');
const res = await fetch(
'http://local.adspower.net:50325/api/v1/browser/start?user_id=k11ozz8'
).then((r) => r.json());
const browser = await puppeteer.connect({
browserWSEndpoint: res.data.ws.puppeteer,
defaultViewport: null,
});
const page = (await browser.pages())[0];
await page.goto('https://target.example/account', { waitUntil: 'networkidle2' });
Two operational notes from running this at volume. The local interface accepts roughly one request per second, and a loop that fires faster comes back with a frequency error that looks like a bug in your code. I put a one second gap between calls and the errors went away. Second, always call the stop endpoint when a job finishes, because a profile left running holds its sockets and the next start on the same profile fails with a lock message.
curl "http://local.adspower.net:50325/api/v1/browser/stop?user_id=k11ozz8"
curl "http://local.adspower.net:50325/api/v1/browser/active?user_id=k11ozz8"
The active call is my verification for this whole step. After a batch run I loop it over every profile in the batch, and anything still reporting as active gets stopped by hand before the next run starts.
Where the login and password pairs live
Two credential pairs live in every profile: the proxy pair and the account pair. Both get stored inside AdsPower, and both deserve a policy.
Proxy pairs go into a saved entry when the endpoint is shared and into the card when it is bound. My source of truth for those pairs sits outside AdsPower, in a plain file exported from the panel, because a machine failure that takes the client with it should never take my endpoint list too. Restoring 60 profiles from a template plus a list takes an hour. Reconstructing an endpoint list from memory takes a week.
Account pairs go into the profile's account fields, which also hold a slot for a two factor secret. Storing the second factor next to the password in the same profile makes the second factor decorative for anyone who reaches the machine, so mine live in a separate manager and I paste the code at login. That costs me four seconds per login and removes a whole category of bad day.
One habit that pays off during a credential rotation. Name saved entries after their purpose, never after their address. An entry called warmup-pool-03 survives a host change with one edit. An entry called 45.153.14.62 becomes a lie the moment the line changes, and six months later nobody remembers which profiles it belongs to.
To verify the storage side, export the profile list from the client every week and diff it against last week's file. Profiles that changed endpoints show up as two changed columns, and if I did not make that change, something else did.
Errors at profile start, line by line
A profile that refuses to open produces a short message, and each message points somewhere specific. These are the ones I meet most.
| Message at start | What it points at | What I do |
|---|---|---|
| proxy connection failed | endpoint refused the socket, or host and port are wrong | retype host and port, then test the same line in another tool |
ERR_TUNNEL_CONNECTION_FAILED | CONNECT never completed, usually a rejected credential pair | check for a trailing space in the account field |
ERR_PROXY_CONNECTION_FAILED | endpoint is unreachable on both schemes | take a fresh line from the panel, the machine is out of the mix |
ERR_NAME_NOT_RESOLVED | a hostname went to a resolver that has no answer | proves lookups are escaping the tunnel, fix the transport first |
ERR_EMPTY_RESPONSE | connection opened, then closed with nothing sent | wrong transport, SOCKS5 endpoint addressed as HTTP |
| IP check failed | lookup service unreachable through the endpoint | usually the service, retry once before touching the profile |
| profile stuck on opening | browser core still downloading, or a previous session holding a lock | stop the profile through the API, then start again |
| local API frequency error | calls fired faster than one per second | add a gap, the limit counts calls across the whole client |
| port 50325 in use | a second client instance, or a stale process | close both, confirm the port is free, start once |
Two of those rows deserve a sentence more. The difference between a tunnel error and a proxy connection error is the fastest diagnostic in the list: a tunnel failure means the endpoint answered and refused you, and a proxy connection failure means nothing answered at all. The first is a credential problem on a live machine. The second is a dead line, and no amount of retyping fixes it.
The other row is the frequency error, because it looks like a code bug and reads like a server problem. Both readings miss it. The client throttles the local interface, the throttle counts calls across every profile at once, and a batch loop with no pause hits it on the third profile every time.
When a whole group starts failing at once, I go to the endpoint before I go to the profiles. Sort the tracking sheet by endpoint, find the shared line, take a fresh one from the panel, edit the saved entry once, and the group comes back together. That workflow only exists because of the split I described early on, which is the argument for spending ten minutes on how endpoints pair with antidetect browsers before spending a week on fingerprint settings that were never the problem.
If the same endpoints have to work outside AdsPower as well, the neighbouring guides pick up where this one stops: routing a normal Chrome install through the same lines is covered in the SwitchyOmega setup guide, sending desktop software that holds no proxy field of its own is covered in the Proxifier walkthrough for Windows, and attaching credentials in a headless script is covered in the Puppeteer proxy authentication guide. When a panel line has to become the exact string a template column or an API body expects, the connection string builder does the conversion between the four part form, the URI form and the split field form without the transcription errors that come from doing it in a spreadsheet at midnight.