Solutions
Ad accounts
- 40 a day
- The ad scenario's page ceiling at full pace, reached on day seven of the warm-up ramp
- 4 consoles
- Google Ads, Meta Ads, TikTok Ads and Microsoft Ads, each with rules written per host
- 56 rules
- What an ad profile loads: 31 general tracker rules plus 25 written for the consoles
- 1 a day
- Payment edits the scenario treats as a safe day, its most conservative ceiling
A ban should stop at the account it hit
Losing one ad account is a cost of doing business. Losing five because one of them was reviewed is a different problem, and it is usually not about the ban at all. It is about what the platform can see those five accounts have in common.
Open two consoles in one browser and they share everything that matters: the cookie jar, local storage, service workers, saved cards, one exit address and one set of device readings. A reviewer looking at one account has the rest one query away. An incognito window does not fix this. Incognito forgets at the end of the session, it does not give the second account a different computer.
ARMANOS gives each ad account a browser of its own. Nothing crosses between two profiles unless you put it there. The rest of this page is which link is cut, how, and in which file.
What this is not is a way around review. Platforms suspend accounts over spend patterns, creatives, landing pages, complaints and account age, and none of that is a browser question. Isolation buys one thing, and it is worth buying: the blast radius of a ban is one profile.
One cookie jar
The console's own login cookie is the shortest link there is, and every window of that browser can see it.
One storage
localStorage, IndexedDB and service workers persist per browser profile, and ad platforms write identifiers into all three.
One device
Screen, cores, memory, GPU strings, fonts, timezone and language are identical in every window of the same browser.
One exit address
Two consoles reached from the same IP minutes apart are related without anyone having to look hard.
One payment identity
A saved card, an autofilled billing address and the browser's own payment profile follow the browser, not the account.
Choosing the ad scenario writes five decisions into the profile
The scenario is a record in the code, not a label on a card. Picking Ad accounts when you create a profile sets the page it opens, the tracker lists it loads, whether links are cleaned, which page scripts are installed, and the daily ceilings the app shows next to that profile.
Two of those change what leaves the browser. The tracker lists are compiled into a small extension the app writes into the profile directory before launch, so blocking happens as network rules and not as a script a page could read back. Link cleaning strips 40 tracking parameters on navigation, and the click identifiers of every console the scenario covers are in that list: gclid, wbraid, gbraid, msclkid, fbclid and ttclid among them.
One of them changes nothing about the browser at all. The action ceilings are numbers the app puts on screen. That difference is kept explicit further down this page, because a ceiling nobody enforces is still useful and is not worth lying about.
The record below is read out of the code, not written for this website. The app reads the same lines when it launches the profile and again when it draws the card.
- scenario id
- ads
- start page
- https://ads.google.com
- tracker lists
- general + ads, 56 rules
- page scripts
- fingerprint, stealth
- link cleaning
- on, 40 parameters
- daily page ceiling
- 40, warm-up over 7 days
- action ceilings
- 5: campaign edits, budget changes, new campaigns, payment edits, account switches
- consoles
- Google Ads, Meta Ads, TikTok Ads, Microsoft Ads
SCENARIOS.ads in packages/shared/src/index.js.
The rules name their host, because the console has to keep working
A blocklist built for privacy browsing is the wrong instrument inside an ad console. Cut one request too many and you cannot upload a creative, open a billing page or load a report, and the profile is useless for the work it exists for.
So the ad rule set is written the other way round. It contains no bare path rules at all: every entry names the host it belongs to, which is why a rule meant for one console cannot fire on a client's landing page. Requests a console needs in order to sign in, load, upload creatives, bill or answer its own API are excluded on purpose, and so is every host that answers a top-level navigation.
What is left is cross-account correlation: conversion and audience pixels, the signal endpoints, the third parties that sell the join. Twenty-five rules across the four consoles and the identity graph, on top of the 31 general rules every ARMANOS profile loads whatever its scenario.
Two rules are first-party, meaning they match requests a console makes to itself. Both carry their own host inside the rule, so neither can travel to another site.
| Console | Rules in the ad list | What they match |
|---|---|---|
| Google Ads | 8, plus 4 first-party | Conversion and audience pixels, tag services, and the console's own gen_204, jserror and csi beacons |
| Meta Ads | 4, plus 1 first-party | The signals script, fbevents.js, the tr pixel, and the ajax/bz logging call on facebook.com |
| TikTok Ads | 2 | Both analytics hosts, including the Singapore one |
| Microsoft Ads | 4 | The Bing click and log endpoints and the MSN event host |
| Any site | 7 third-party | The identity graph: adsrvr, demdex, rlcdn, agkn, crwdcntrl, scorecardresearch, everesttech |
Blocking is not the feature here, and it is not sold as one
The card and the login live inside the profile, not on your machine
A saved card, a billing address and an autofilled name are browser data. They live in the Chromium profile directory, and every ARMANOS profile has one of its own: the engine is launched with a user data directory pointing at fork-profiles and the profile's id. Cookies, local storage, service workers, saved cards and autofill are inside it. Two ad accounts are two directories.
The engine is also kept out of the machine's credential store. It runs with a mock keychain and a basic password store, so it encrypts its own cookie and password database instead of asking macOS, Windows or Linux for the key. That was measured, not assumed: without those flags a launch on macOS made zero requests and sat on a keychain prompt no password could satisfy. It also keeps the profile portable, which is what makes moving a live session to another machine possible at all.
The account's own login pair is held by the app rather than by the browser: sealed through the operating system's keychain and written beside the profile with owner-only permissions. It is never sent to our server. When the desktop syncs a profile, the request carries the id, the name, the folder, the scenario, the fingerprint template, the proxy and a couple of labels. There is no field in it for an account password. The one-time code sits in the same place: the 2FA secret belongs to the profile and stays on that machine.
The proxy password is handled the same way for a different reason. It is never placed on the command line, because a credential in an argument shows up in any process listing on the machine, and because the credentialled form was measured to load nothing at all on this engine. The browser is pointed at a loopback bridge that holds the credential and answers for it.
The profile directory
fork-profiles and the profile id, under the app's data folder: cookies, storage, service workers, saved cards, autofill.
The account password
Sealed by the OS keychain, owner-only file permissions, never uploaded to us.
The one-time code
The TOTP secret belongs to the profile, and the app generates the code beside the profile it belongs to.
The proxy password
Sealed at rest, and the proxy list reports only that a password is set. Taking the working credential is written to the log.
The payment edit ceiling
One a day, warning at 99 percent of it. Changing the card on three accounts in an hour is itself a pattern.
The device the console sees belongs to the profile, not to your laptop
The fingerprint is not stored anywhere. It is derived at every launch from four inputs: the template you picked, the profile's id, the country the proxy exits in and the engine's own version. The same four inputs always produce the same machine, so an account never finds its computer changed overnight.
That is what makes a shared profile usable in an agency. The id travels with the profile, so when a media buyer opens it on their own laptop, the readings are the ones the account saw yesterday. Their real screen, cores, memory and GPU do not leak into it. The comment on the sync path in the desktop app puts it in five words: the same identifier is the same machine.
Geography is measured rather than typed. Before the first launch the app asks up to four providers over HTTPS, through the profile's own proxy, where that proxy comes out, and the country decides the timezone and the language stack. Change the proxy to a different exit and the stored country is cleared, so the next launch measures again instead of showing a German address with Kyiv time.
The substitution happens in the engine. ARMANOS Browser 153.0.7978.0 is our own Chromium build, and the readings reach it as a seed on the command line rather than as a script patching the page. Generation 4 of the generator, five templates, 25 readings you can compare against your own browser on the fingerprint tool.
Template
One of five: macos-chrome, windows-chrome, linux-chrome, android-chrome, android-tablet.
Profile id
Seeds the GPU pair, the screen, the user agent and the platform version out of generation 4's pools.
Proxy country
Measured through the proxy itself, then mapped to a timezone and a language stack that agree with it.
Engine version
153.0.7978.0 is claimed in the user agent and in every client hint, because it is the engine actually rendering the page.
WebRTC is not offered a way around the proxy
A media buyer sees one client's folder and nothing else
An agency does not want a new buyer to see every client. A role cannot do that on its own, because a role covers the whole workspace: an operator sees every profile shared with them. Folder access is the part that narrows it. You choose which folders a member may see, and the server keeps one row per member per folder.
Three details turn that into a boundary instead of a filter on a list. A profile that is in no folder is not shown at all once access is set, so the restriction cannot be dodged by leaving a profile out of a folder. Opening a profile straight by its id is checked by the same rule and answers profile not found rather than forbidden, so the difference between the two answers cannot be used to map what the workspace holds. And the restriction is recorded against the workspace owner, so it does not follow a person to their next employer and lock them out there.
An empty list means the member sees everything. That is a deliberate choice. If no rows meant no access, the day the feature shipped would have locked out every existing team, and taking a member's last folder away would silently have meant taking away all of their access.
Access does not carry passwords with it. The proxy list never returns a password, only whether one is set; the working credential comes from a single endpoint and taking it is written to the log. The account password was never on the server to begin with. Handing out folder access is logged too, with who did it and which folders.
Owner
Everything, and cannot be removed from their own workspace or restricted to folders.
Admin
Billing, the team, the log, other members' profiles and machines. Hands out folder access.
Manager
Shared working resources: folders and the proxy pool, including rotating a mobile proxy. No money, no team.
Operator and member
Work with the profiles they were given, inside the folders they can see. Change nothing shared.
Seats
Business includes 3, Enterprise 20, and additional seats are 3 dollars a month each.

Two people cannot open one ad account at once
What the ceilings count, and what they only suggest
An ad profile carries five action ceilings and one page counter. The page counter is the only number the app measures. It counts top-level navigations in that profile's windows, keeps them in a small file so a relaunch on the same day does not reset the count, and starts fresh at midnight. At full pace it is 40 a day.
New profiles ramp. The first seven days multiply the ceiling by 0.2, 0.35, 0.5, 0.65, 0.8, 0.9 and 1.0, so an ad profile shows 8 on day one and reaches 40 on day seven. The bar turns amber at 80 percent of the day's ceiling and red at it. It never blocks anything, and the app does not pretend otherwise.
The five action ceilings are numbers, not counters. The app cannot see that you edited a campaign inside a console, so it shows what the scenario treats as a safe day, ramped by the same curve. Payment edits are the strictest of them, one a day with the warning at 99 percent, because a payment change is the event most likely to put a human reviewer in front of the account.
One caveat is built into the wording on screen. The day count is the age of the ARMANOS profile, not the age of the ad account behind it. The app has no way to know the second one, and the label was corrected once it was noticed that it had claimed to.
| What the scenario counts as a day | Full ceiling | Day one of the ramp | Warning at |
|---|---|---|---|
| Campaign edits | 12 | 2 | 70 percent |
| Budget changes | 4 | 1 | 50 percent |
| New campaigns | 3 | 1 | 67 percent |
| Payment edits | 1 | 1 | 99 percent |
| Account switches | 3 | 1 | 67 percent |
| Pages opened (measured) | 40 | 8 | 80 percent |

When an account goes anyway
Some will. What matters then is how much goes with it. In one shared browser the honest answer is often the neighbours as well. Here the loss is bounded by a directory: the banned account's cookies and storage sit in that one profile and touch nothing else, and every other profile keeps working through the ban and the appeal.
Most of the setup is still yours. The proxy stays in the shared pool with its measured exit country. The folder and its access rules stay. The scenario and its ceilings stay. The profile itself stays until you decide otherwise, with its launches in the log: who opened it, from which machine, and when.
A replacement is a copy. Cloning carries the scenario, the fingerprint template, the folder, the tags, the notes, the start page, the enabled extensions, the proxy (by reference to the pool when it came from there) and the measured exit country, because that last one is a measurement of the same proxy rather than a secret.
A copy deliberately does not carry three things: the account's login pair, its one-time code secret, and its fingerprint. The first two belong to an account that is gone, and putting them into a second profile is how you eventually sign in as the wrong account from the wrong address. The third is not copyable by design. A clone is a new profile with a new id, and the fingerprint is derived from the id, so the copy is a different machine. Two profiles wearing one fingerprint would be tied together more tightly than anything else in this product could tie them.
Deleting is two steps. The profile goes to the recycle bin and can be restored, or it is purged. Purging closes the running browser first, then erases the directory, then clears the profile out of the launch notifications, the blocked-request counters and the pace counter, because a browser of this kind that keeps a launch history of profiles you deleted is keeping exactly the wrong thing.
- 1
Clone the profile
Settings, folder, proxy, measured country, extensions and start page come with it. The login pair, the 2FA secret and the fingerprint do not.
- 2
Give it a different exit
Another proxy from the pool, or a rotation on a mobile one. Changing the exit clears the stored country, so the next launch measures the new one and sets the timezone from it.
- 3
Register the new account inside it
The console meets an empty cookie jar, an address that account has never used, and a device it has never seen.
- 4
Purge the old profile when the appeal is over
The recycle bin holds it as long as you want. Purging erases the directory and every counter that referenced it.
The proxy is a decision, not a leftover
What this does not do
- It does not prevent bans. Spend patterns, creatives, landing pages, complaints and account age are all reviewed, and none of them is a browser question.
- It does not hide your IP by itself. Without a proxy the profile goes out from your own address, and the app says so in its first-steps list.
- It does not count what you do inside a console. Only pages opened in the profile are measured; the five action ceilings are guidance you follow yourself, and nothing is ever blocked.
- It does not create or warm up ad accounts. The warm-up ramp is a number on a bar, not activity on your behalf.
- It does not know how old an ad account is. The day counter is the age of the ARMANOS profile, which is all the app can honestly see.
- The engine work is not finished. A few readings are still corrected from the page rather than in C++; the remaining list lives in our sources and is closed build by build.
How to check
Every claim above is one file away. These are the lines that hold it and the stands that break if it stops being true.
- The ad scenario is one record, and the app shows exactly its numbers
- packages/shared/src/index.js (SCENARIOS.ads) · apps/desktop/src/main/main.js (actionLimitsFor, paceInfoFor)
- Ad rules name their host, so nothing fires outside the console it was written for
- apps/desktop/assets/trackers_ads.json · apps/desktop/src/lib/tracker-rules.js (TELEMETRY_BY_SCENARIO)
- Each profile is its own directory, and the proxy password never reaches the command line
- apps/desktop/src/lib/forkEngine.js (profileDir, proxyArg) · apps/desktop/test/proxy-auth-bridge.js
- The account password and the one-time code secret stay on your machine
- apps/desktop/src/lib/profiles.js · apps/desktop/test/login-in-keychain.js · apps/desktop/test/login-stays-local.js
- Folder access hides a profile even from a member who knows its id
- apps/server/src/profiles/profiles.service.ts · apps/server/test/group-access.js
- Two machines cannot hold the same ad profile at the same time
- apps/server/src/profiles/profiles.service.ts (LOCK_TTL_MS) · apps/server/test/profile-lock.js
Next to this
Proxies
The pool, the measured exit country and the loopback bridge that carries the password.
Team
Seats, the five roles and folder access, screen by screen.
Action ceilings
Where the numbers come from, and what the app counts against them.
Agencies
Running many clients out of one workspace.
ARMANOS Browser
The Chromium build that carries the substitution in C++.
Fingerprint tool
The 25 readings, taken from your own browser right now.
Start with one client and two profiles
The Free plan gives you two profiles for good, with no card. macOS 13 and newer on Apple Silicon or Intel, Windows 10 and 11 on 64-bit, Ubuntu 22.04 and newer on 64-bit.