← back to blog

Running 200 MetaMask profiles on one machine: no fingerprint collisions

Running 200 MetaMask profiles on one machine: no fingerprint collisions

Running 50 wallets is manageable. Running 200 is an engineering problem. The bottleneck is not RAM or CPU, it is fingerprint isolation: each browser profile that interacts with a dApp or bridge leaves behind a fingerprint composed of canvas hash, WebGL renderer, audio context, installed fonts, navigator properties, screen resolution, and timezone. When two profiles share any of these values, sybil detection systems, and many modern airdrop eligibility checkers, flag them as the same operator. You get slashed allocations or disqualified entirely.

This guide is for operators who are already farming airdrops at scale and have hit that wall. You know how MetaMask works. You have proxies. What you need is a reliable system to isolate 200 browser identities on one physical box without bleed between profiles and without spending the next two weeks debugging canvas collisions. I run a setup like this from Singapore and have tested it across multiple EVM-chain campaigns.

By the end of this guide you will have 200 fully isolated browser profiles, each running MetaMask with a unique seed phrase and assigned to a dedicated proxy, managed via an anti-detect browser’s API so you can script interactions without touching a GUI.


What you need

Hardware - Server or workstation: 64 GB RAM minimum for 200 concurrent profiles (budget for 128 GB if you want headroom). An AMD EPYC or Intel Xeon with 16+ cores is ideal. A Hetzner AX102 bare metal (around EUR 100/month) handles this comfortably. - NVMe SSD with at least 500 GB free. Profile data accumulates fast.

Software - AdsPower anti-detect browser, Team plan. As of May 2026 the Team plan supports up to 1000 profiles at roughly USD 30/month per 100 profiles. It exposes a local REST API on port 50325 which is what we will automate against. - Python 3.11+ with requests, selenium, and web3 libraries. - MetaMask extension CRX file (pinned version, download from the MetaMask GitHub releases page).

Proxies - 200 residential or mobile proxies, one per profile. Static datacenter proxies work for low-scrutiny campaigns, but residential gives better pass rates. I use IPRoyal’s rotating residential pool with sticky sessions of 24h. Budget USD 3-6 per IP per month at 200 IPs. - Proxies must be HTTP or SOCKS5. AdsPower accepts both formats.

Other - 200 unique seed phrases, pre-generated offline and stored encrypted. Do not reuse seeds across campaigns. - A spreadsheet or SQLite database mapping profile ID, wallet address, proxy, and seed phrase. - Ubuntu 22.04 LTS or Debian 12 on the host. The AdsPower Linux client supports both.

Estimated monthly cost for 200 profiles: USD 60-90 for AdsPower + USD 600-1200 for proxies. Infrastructure runs another USD 100-150. Total is around USD 760-1440/month depending on proxy quality and server spec.


Step by step

Step 1: Install AdsPower on Linux

Download the AdsPower Linux AppImage from the AdsPower website, make it executable, and launch it.

chmod +x AdsPower-linux-x64-*.AppImage
./AdsPower-linux-x64-*.AppImage --no-sandbox &

AdsPower starts a local API server at http://localhost:50325. Verify it is running:

curl http://localhost:50325/status
# expected: {"code":0,"msg":"Success"}

If it breaks: if the API returns nothing, AdsPower may not have finished initialising. Wait 10 seconds and retry. On headless servers you need a virtual display, so install and start Xvfb:

sudo apt install xvfb -y
Xvfb :99 -screen 0 1920x1080x24 &
export DISPLAY=:99

Step 2: Prepare your proxy list

Your proxy list should be in a CSV file with the format host,port,username,password,type. Example:

proxy.iproyal.com,12321,user1,pass1,socks5
proxy.iproyal.com,12321,user2,pass2,socks5

Each row maps to one profile. Keep the mapping in a file called profiles.csv alongside your proxy list. You will reference this when creating profiles via the API.

If it breaks: test each proxy independently before bulk-creating profiles. A dead proxy at creation time means the profile has no network isolation.

curl --proxy socks5://user1:[email protected]:12321 https://api.ipify.org

Step 3: Create 200 browser profiles via the AdsPower API

AdsPower’s profile creation endpoint accepts fingerprint parameters. The key ones to randomise per profile are: ua (user agent), screen_resolution, language, time_zone, canvas, webgl, audio, fonts. Setting these to 0 tells AdsPower to randomise them using its own fingerprint database.

import requests
import csv
import time

API = "http://localhost:50325"

with open("profiles.csv") as f:
    rows = list(csv.DictReader(f))

for i, row in enumerate(rows):
    payload = {
        "name": f"wallet_{i+1:03d}",
        "group_id": "0",
        "user_proxy_config": {
            "proxy_type": row["type"],
            "proxy_host": row["host"],
            "proxy_port": row["port"],
            "proxy_user": row["username"],
            "proxy_password": row["password"]
        },
        "fingerprint_config": {
            "automatic_timezone": "1",
            "language": ["en-US", "en"],
            "ua": "0",       # 0 = auto-randomise
            "screen_resolution": "0",
            "canvas": "1",   # 1 = noise injection
            "webgl": "1",
            "audio": "1",
            "fonts": "1"
        }
    }
    r = requests.post(f"{API}/api/v1/user/create", json=payload)
    print(f"Profile {i+1}: {r.json()}")
    time.sleep(0.3)   # rate-limit the API calls

Run this script and wait for all 200 profiles to be created. The API returns a user_id for each profile, save these to your mapping file.

If it breaks: if you get code: 4003 errors, you have hit the plan’s profile limit. Check your AdsPower subscription tier.

Step 4: Install MetaMask into each profile

Rather than clicking through 200 GUIs, use the AdsPower open endpoint to launch a profile, then use Selenium to inject the MetaMask CRX and complete the onboarding flow headlessly. For the MetaMask extension load path, point Selenium to the unpacked extension directory.

import subprocess

def open_profile(user_id):
    r = requests.get(f"{API}/api/v1/browser/start?user_id={user_id}")
    data = r.json()["data"]
    return data["ws"]["selenium"], data["webdriver"]

def close_profile(user_id):
    requests.get(f"{API}/api/v1/browser/stop?user_id={user_id}")

For the MetaMask onboarding automation, the MetaMask developer docs describe the internal page URLs you can navigate to programmatically. Use chrome-extension://<extension_id>/home.html to reach the setup page, then drive the seed import via Selenium find_element on the known input selectors. This is tedious to write from scratch. I keep a reusable script for this in my private tooling repo, but the community at multiaccountops.com/blog/ has posted working MetaMask onboarding scripts you can adapt.

Process profiles in batches of 10 to avoid saturating RAM. Open 10, install and configure MetaMask, close all 10, move to the next batch.

If it breaks: MetaMask’s extension ID changes between versions. After loading the CRX, query the extension ID dynamically via driver.execute_script("return chrome.runtime.id") from within the extension’s background page context.

Step 5: Import seed phrases

Once MetaMask is installed in a profile, navigate to the import flow and paste the corresponding seed phrase. Read seed phrases from an encrypted file at runtime, not from plain text.

from cryptography.fernet import Fernet

key = open("seeds.key","rb").read()
f = Fernet(key)
seeds = f.decrypt(open("seeds.enc","rb").read()).decode().splitlines()

Match seeds to profile index. One seed, one profile, no exceptions.

If it breaks: if MetaMask shows “Invalid seed phrase”, check for trailing whitespace in your seed file. Strip each line before passing it.

Step 6: Verify fingerprint isolation

Before running any campaign, verify that no two profiles share a canvas fingerprint. Use the headless Selenium session to navigate each profile to a fingerprint test page and record the canvas hash.

driver.get("https://browserleaks.com/canvas")
# parse the canvas hash from the page

Collect all 200 canvas hashes and check for duplicates:

from collections import Counter
hashes = [...]  # list of 200 hashes
dupes = [h for h, count in Counter(hashes).items() if count > 1]
print(f"Duplicate canvas hashes: {dupes}")

Any duplicates mean two profiles could be linked. Delete the affected profiles and recreate them. The Electronic Frontier Foundation’s Cover Your Tracks project has good documentation on which fingerprint vectors are most uniquely identifying if you want to understand what the test is measuring.

If it breaks: WebGL fingerprints are harder to spoof on Linux because the underlying GPU driver is shared. If you see WebGL collisions, enable AdsPower’s software WebGL renderer option in the fingerprint config ("webgl_config": {"unmasked_renderer": "randomize"}).

Step 7: Automate profile cycling

For ongoing campaigns, write a task runner that opens profiles in sequence, performs the required on-chain actions via the MetaMask provider API (EIP-1193 is the standard), and closes them. Batch size depends on your RAM. On a 64 GB machine I run 15 profiles at once safely.

import concurrent.futures

def process_profile(user_id, seed, action_fn):
    ws, driver_path = open_profile(user_id)
    # attach Selenium, run action_fn, close
    close_profile(user_id)

with concurrent.futures.ThreadPoolExecutor(max_workers=15) as pool:
    futures = [pool.submit(process_profile, uid, seed, my_action) 
               for uid, seed in profile_seed_pairs]
    for fut in concurrent.futures.as_completed(futures):
        fut.result()

Common pitfalls

Reusing proxies across profiles. One proxy shared by two profiles means the IP is shared. Even if the browser fingerprints are distinct, IP-level clustering will link them. One proxy per profile is the baseline, not an optimisation.

Not pinning the MetaMask version. MetaMask updates auto-install in Chromium-based browsers and can break your Selenium selectors overnight. Pin the CRX version, store it in your repo, and update deliberately.

Letting AdsPower randomise the timezone inconsistently with the proxy location. If a profile uses a US residential proxy but has an Asia/Singapore timezone, that mismatch is a detectable signal. Set automatic_timezone: 1 so AdsPower derives the timezone from the proxy’s geolocation automatically.

Running too many profiles concurrently. Opening 50 profiles at once on a 64 GB machine will cause OOM kills. The Chromium renderer process alone uses 200-400 MB per tab. Measure your actual per-profile RAM usage first (ps aux --sort=-%mem | head -30) and set your concurrency ceiling accordingly.

Storing seed phrases in plain text. Encrypting seeds with Fernet or age before storage takes 20 minutes to set up and prevents a single file read from draining all your wallets.


Scaling this

10x (2000 profiles): you will need multiple machines or a dedicated bare metal server with 512 GB RAM. AdsPower’s Team plan supports it. Proxy cost becomes the dominant expense. Consider tiering proxies by campaign value, residential for high-value campaigns, static datacenter for throwaway interactions.

100x (20,000 profiles): at this point you are running a distributed system. AdsPower’s API design assumes a single-machine orchestrator. You need a message queue (Redis or RabbitMQ) distributing jobs across multiple AdsPower instances on multiple hosts, with a central database tracking profile state. Read more about the infrastructure patterns for this in our multi-wallet infrastructure scaling guide.

1000x (200,000 profiles): this is beyond what a single anti-detect browser platform can handle operationally. Operators at this scale typically build custom Chromium forks with fingerprint injection at the engine level. That is a separate engineering track, not a configuration change. The economics also shift, proxy costs at this scale run into five figures monthly.


Where to go next

If you want a broader comparison of anti-detect browsers beyond AdsPower, including Multilogin and GoLogin, antidetectreview.org/blog/ has independent benchmarks with fingerprint test results across platforms that I refer to when evaluating new tools.


Written by Xavier Fok

disclosure: this article may contain affiliate links. if you buy through them we may earn a commission at no extra cost to you. verdicts are independent of payouts. last reviewed by Xavier Fok on 2026-05-22.

need infra for this today?