Personas

  1. The core idea
    1. Python
    2. Node
  2. Choosing ids
  3. Canvas and WebGL (optional bridge)
  4. What’s deterministic per seed

A persona is the complete, self-consistent fingerprint ChromiumFish presents: user-agent, Client Hints, WebGL vendor/renderer string, fonts, audio, screen metrics, and more. Every persona is derived deterministically from a single string, the persona_seed. Any stable string works as the id: a numeric string is used as-is, and any other string is hashed to a stable persona, so different strings give different personas. Omit it and you get the build’s default persona.

All of this is produced in the browser engine itself, not by JavaScript patches injected at runtime. The SDK passes the seed through to the build and nothing more.

The core idea

One seed produces one coherent fingerprint, and the same seed always produces the same one.

  • Same seed, same persona. Re-running with persona_seed="alpha-7" reproduces the exact same persona every time. That is what you want for cross-session continuity: the site sees a returning visitor, not a new device on every request.
  • Different seed, uncorrelated persona. Change the seed and the surfaces change together, consistently. On non-Mac builds the per-seed audio offset differs between seeds, so two personas don’t share an audio hash.

Python

from chromiumfish.sync_api import Chromiumfish

# Account A: always this identity
with Chromiumfish(persona_seed="alice") as browser:
    ...

# Account B: a different, uncorrelated identity
with Chromiumfish(persona_seed="bob") as browser:
    ...

Node

import { ChromiumFish } from "chromiumfish";

const a = await ChromiumFish({ personaSeed: "alice" });
// ... use a ...
await a.close();

const b = await ChromiumFish({ personaSeed: "bob" });
// ... use b ...
await b.close();

Choosing ids

  • Use a stable id per account or profile. Any string works, so the account’s own id is often all you need. The same id always rebuilds the same persona.
  • Rotate ids for anonymity. For one-off scrapes you don’t want linked together, use a fresh random string each run.
  • Keep network and persona aligned. A persona’s locale and timezone should match its exit IP. Pair ids with proxies deliberately, and let timezone="auto" resolve the egress IP’s zone if you don’t want to set it by hand.

Because the id is just a string, the account id itself can be the persona id. There’s no separate seed table to keep:

from chromiumfish.sync_api import Chromiumfish

def scrape(account_id: str):
    with Chromiumfish(persona_seed=account_id) as browser:
        page = browser.new_page()
        page.goto("https://example.com/account")
        return page.title()

A persona spoofs the browser fingerprint, not your network identity. IP reputation, TLS, and behaviour still matter. For high-friction targets, combine a persona with a clean residential proxy and human-like interaction.

Canvas and WebGL (optional bridge)

The WebGL vendor/renderer string is part of the persona and reports a real D3D11/ANGLE GPU, with no Apple or Metal leakage. The pixels are a separate matter.

By default, canvas and WebGL pixel reads (toDataURL, getImageData, readPixels, measureText) pass through clean. On a headless Linux build that means SwiftShader’s software output. There is no in-engine canvas noise and no per-seed canvas isolation, so two seeds can produce the same canvas hash.

If you need those reads to look like a real GPU, ChromiumFish supports an optional canvas-bridge: a separate render service running on a Windows machine. When the build is pointed at the bridge (two command-line flags passed through the SDK’s args list), those reads are answered by the real Windows renderer instead of local SwiftShader. See Canvas & WebGL bridge for the full setup.

What’s deterministic per seed

Surface Behaviour
User-Agent + Client Hints Coherent desktop persona, consistent across UA and high-entropy hints
WebGL vendor/renderer string Reports a real D3D11/ANGLE GPU string; no Apple/Metal leakage
Canvas / WebGL pixels Pass through clean by default; hardened only when the optional canvas-bridge is configured (see above)
Audio Per-seed offset on non-Mac builds, below perceptual threshold
Fonts Windows font set present; host fonts hidden

Back to top

An independent fork of Chromium. Not affiliated with or endorsed by Google.

This site uses Just the Docs, a documentation theme for Jekyll.