ProfileDock is a lightweight command-line tool for managing isolated, persistent Chromium profiles. Every profile receives a separate browser data directory, so cookies, sessions, local storage, cache, login state, and browsing data do not leak into another ProfileDock profile.
Current release: 0.8.0
- Create, list, launch, close, and delete browser profiles.
- Keep browser state between launches with Playwright persistent contexts.
- Open an exact number of blank tabs.
- Prevent the same profile from launching twice.
- Close browsers gracefully through a local controller process.
- Use Playwright Chromium or fall back to an installed Chrome or Chromium executable.
- Store ProfileDock data in the operating system's application-data directory.
- Override storage with
--data-rootorPROFILEDOCK_DATA_ROOT.
- Python 3.9 or newer.
- Windows, macOS, or Linux.
- Internet access during the initial dependency installation.
- Google Chrome or access to Playwright's Chromium download service.
Git is optional for running ProfileDock but required when cloning or updating the repository with Git.
Open a terminal in the project directory and run:
python scripts/setup_project.pyThe setup script:
- Creates an isolated
.venvenvironment if one does not exist. - Upgrades pip inside that environment.
- Installs ProfileDock and its test dependencies from
requirements.txt. - Uses installed Google Chrome or installs Playwright Chromium.
- Runs the complete test suite.
The script is safe to run again after pulling updates. It reuses the existing virtual environment.
Setup does not create or remove ProfileDock application data. The data root is resolved when a profiledock command runs.
To skip all browser preparation:
python scripts/setup_project.py --skip-browserUse --skip-browser only when a compatible browser is already available or when you only need to run non-browser functionality.
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m playwright install chromiumIf Playwright's Chromium download is blocked but Chrome or Chromium is installed, omit the final command. ProfileDock tries the installed Chrome channel and then a detected system browser executable.
python3 -m venv .venv
./.venv/bin/python -m pip install --upgrade pip
./.venv/bin/python -m pip install -r requirements.txt
./.venv/bin/python -m playwright install chromiumActivation is optional. You can run ProfileDock directly through the isolated environment.
Windows PowerShell:
.\.venv\Scripts\profiledock.exe --helpmacOS and Linux:
./.venv/bin/profiledock --helpTo activate the environment on Windows PowerShell:
.\.venv\Scripts\Activate.ps1If PowerShell blocks activation, either run the executable directly or temporarily allow local scripts for the current terminal:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\.venv\Scripts\Activate.ps1To activate on macOS or Linux:
source .venv/bin/activateAfter activation, the profiledock command is available directly.
By default, ProfileDock uses %LOCALAPPDATA%\ProfileDock on Windows, ~/Library/Application Support/ProfileDock on macOS, and ${XDG_DATA_HOME:-~/.local/share}/profiledock on Linux.
To use another location for one invocation, place the global option before the command:
profiledock --data-root /path/to/profiledock-data listTo use another location for every command in the current environment, set PROFILEDOCK_DATA_ROOT. The CLI option takes precedence over the environment variable, and the environment variable takes precedence over the platform default.
Create a profile:
profiledock create "Personal"List profiles and copy the generated ID:
profiledock listLaunch the profile and answer the tab-count prompt:
profiledock launch <id>You can provide the tab count without a prompt:
profiledock launch <id> --tabs 5Browse and sign in manually. ProfileDock does not automate login or collect passwords.
Close the browser gracefully:
profiledock close <id>Launch the same ID again to restore its persistent browser state:
profiledock launch <id>Commands that operate on a single profile accept a profile identifier. The identifier can be a full ID, a unique ID prefix, or an exact profile name. Matching is case-sensitive for both IDs and names. If the input matches more than one profile, ProfileDock prints the matching IDs and names and exits without taking action.
profiledock --versionDisplays the current version of ProfileDock.
profiledock create "Profile name"Creates profile metadata and a dedicated browser data directory.
profiledock list
profiledock list --jsonDisplays each profile's ID, name, and status in a formatted table, or outputs JSON with --json.
profiledock show <id-or-name>
profiledock show <id-or-name> --jsonDisplays all safe profile metadata (ID, name, status, created at, data directory, and last launched timestamp). Controller authentication tokens are never displayed.
profiledock rename <id-or-name> "New name"Validates the new non-empty name and renames the profile atomically.
profiledock status
profiledock status <id-or-name>
profiledock status --json
profiledock status <id-or-name> --jsonReports profile status (stopped, starting, running, closing, stale, or error where detectable). When invoked without an identifier, status reports across all profiles.
Exit codes:
ProfileDock uses stable exit codes for scripting compatibility:
| Code | Meaning |
|---|---|
0 |
Success |
1 |
User error (profile not found, validation error, profile already running, etc.) |
2 |
Reserved for system errors (optional, not currently used) |
profiledock launch <id-or-name>
profiledock launch <id-or-name> --tabs 3Starts a persistent browser context with exactly the requested number of about:blank tabs. A running profile cannot be launched a second time.
profiledock close <id-or-name>Requests graceful browser shutdown and removes the profile's running-state file.
If the entire browser is closed manually or exits unexpectedly, the controller detects the closure, exits, and removes its running state. The profile can then be launched again normally.
profiledock delete <id-or-name>Asks for confirmation, then permanently removes the profile metadata and browser data. A running profile must be closed before deletion. The profile directory is quarantined during the metadata update and restored if that update fails.
For non-interactive use:
profiledock delete <id-or-name> --yesprofiledock doctor
profiledock doctor --json
profiledock doctor --repairPerforms comprehensive diagnostic checks across the environment and profile storage.
Diagnostic checks:
python_version: Verifies Python is >= 3.9.writable_data_root: Checks that the application-data directory is writable.metadata_schema: Validates theprofiles.jsonschema (version 1) and contents.metadata_backup_state: Inspects the backup file (profiles.json.bak) for validity.profile_directories_exist: Ensures every configured profile has a correspondingbrowser-datadirectory.profile_paths_under_data_root: Validates that all profile data paths reside safely within the profile root boundary.playwright_package: Checks if theplaywrightPython package is installed.playwright_chromium: Verifies if Playwright Chromium browser executable is installed.system_chrome: Verifies if system Google Chrome or Chromium is available as fallback.browser_availability: Aggregate check verifying that at least one usable browser engine is present.runtime_permissions: Checks read/write permissions on theruntime/directory.stale_running_state: Detects leftoverrunning.jsonstate files from terminated processes.orphan_profile_directories: Identifies folders inprofiles/that are not listed in metadata.version_consistency: Verifies that the runtime version matches installed package metadata.
Repair capabilities (--repair):
- Cleans up stale runtime
running.jsonfiles automatically. - Recovers valid metadata from
profiles.json.bakifprofiles.jsonis missing or corrupted. - Automatically migrates legacy bare-array format metadata to versioned schema.
- Never deletes browser data directories automatically.
- Never reattaches orphan profile directories without manual user confirmation.
Exit codes:
Exits with 0 when all critical checks pass (including with warnings). Exits with 1 if any check fails (FAILED status).
profiledock migrate --from-project <path>
profiledock migrate --from-project <path> --json
profiledock migrate --from-project <path> --remove-source --yesMigrates profiles and browser data from a legacy or another project directory into the active ProfileDock data root.
Migration safety & guarantees:
- Pre-migration backup: It is strongly recommended to create a copy/backup of both the source directory and the destination data root before initiating migration.
- Safety checks: Detects legacy
profiles.jsonandprofiles/, validates metadata schema, and refuses migration if any source profile is currently running. - Conflict detection: Prevents silent overwrite by detecting ID or name conflicts.
- Atomic directory copying: Copies profile directories into temporary destination folders, verifies file integrity, and moves them into place atomically before updating metadata.
- Automatic rollback: Incomplete changes in the destination are rolled back cleanly if copying or validation fails.
- Source preservation: Leaves source files completely untouched by default.
--remove-sourcedeletes source data only after successful migration and explicit confirmation. - Idempotent: Re-running migration safely skips already migrated identical profiles.
ProfileDock resolves one data root for each command and uses this structure:
ProfileDock/
├── metadata/
│ ├── profiles.json
│ └── profiles.lock
├── backups/
│ └── profiles.json.bak
├── profiles/
│ └── <profile-id>/
│ └── browser-data/
├── runtime/
│ └── <profile-id>/
│ ├── running.json
│ └── controller.error
└── logs/
profiles.json contains a versioned metadata document:
{
"schema_version": 1,
"profiles": [
{
"id": "abc123",
"name": "Personal",
"created_at": "2024-01-15T10:30:00+00:00",
"data_dir": "/path/to/profiles/abc123/browser-data",
"last_launched_at": null
}
]
}The metadata document includes:
schema_version: Version of the metadata format (currently 1)profiles: Array of profile objects with required fields:id,name,created_at,data_dir- Optional field:
last_launched_at(ISO-8601 timestamp)
ProfileDock automatically migrates older bare-array format to the versioned document format:
- The old
profiles.jsonis backed up toprofiles.json.bakbefore migration - Migration validates all profile data before accepting the new format
- Invalid data is rejected before any changes are written
ProfileDock implements several safety mechanisms to protect metadata integrity:
Atomic writes: Metadata, backups, and controller state use unique temporary files and atomic replacement. Transient Windows sharing violations are retried within a bounded interval.
Cross-process locking: A lock file (metadata/profiles.lock) coordinates concurrent metadata modifications through an operating-system file lock. Its presence alone does not mean ProfileDock is locked.
Backup recovery: Before each metadata update, the current file is backed up to profiles.json.bak. The profiledock doctor --repair command can restore a valid backup after primary-file corruption.
Duplicate prevention: Profile IDs and data directories must be unique. Duplicate values are rejected before any changes are written.
Path safety: Data directories must exactly match profiles/<id>/browser-data. Symlinks, junctions, reparse points, duplicate paths, and path traversal attempts are rejected.
Managed-directory safety: ProfileDock rejects unsafe managed directories, path-like profile IDs, runtime paths beneath browser-data, and deletion targets that do not exactly match profiles/<id>/browser-data.
Private storage: On POSIX systems, ProfileDock restricts managed directories to the owner and writes metadata, lock, controller-state, and controller-error files with owner-only permissions. Windows access remains governed by the directory's inherited ACLs.
Corruption handling: ProfileDock never overwrites corrupted metadata automatically. If both the primary and backup files are corrupted, manual intervention is required.
profiles.json contains profile metadata only. Chromium stores cookies, local storage, cache, sessions, and login state inside browser-data.
running.json exists only while a profile controller is active. New state files use a versioned local protocol and contain the profile ID, controller PID, start time, loopback port, status, and a random authentication token. State writes are atomic, and the controller accepts a close request only when its token matches. Stale state files are cleaned automatically.
Runtime state, logs, backups, metadata, and browser data are separated. Runtime files are never written inside browser-data.
- Every profile uses a separate Chromium user data directory.
- ProfileDock does not automate authentication or store passwords itself.
- Websites and Chromium may store credentials, cookies, tokens, and browsing history inside
browser-data. - Anyone with access to a profile directory may be able to access its browser state.
- Keep the selected data root private and out of source control.
- Closing a profile does not delete its browsing data.
- Deleting a profile permanently removes its local browser data.
Windows:
.\.venv\Scripts\python.exe -m pytestmacOS and Linux:
./.venv/bin/python -m pytestThe integration test launches a real persistent browser context, verifies the requested tab count, closes it, relaunches it, and confirms that a persistent cookie remains. It uses Playwright Chromium or installed Google Chrome and skips only when neither is available.
Run only fast unit tests:
.\.venv\Scripts\python.exe -m pytest -m "not browser"Run only browser and controller integration tests:
.\.venv\Scripts\python.exe -m pytest -m browserAll JSON output from --json flags is stable and safe for scripting:
list --json and status --json:
Always returns an array of profile objects:
[
{
"id": "abc123",
"name": "Work",
"status": "stopped",
"created_at": "2026-01-01T00:00:00+00:00",
"data_dir": "/path/to/profiles/abc123/browser-data",
"last_launched_at": null
}
]show <profile> --json:
Returns a single profile object with all metadata:
{
"id": "abc123",
"name": "Work",
"status": "running",
"created_at": "2026-01-01T00:00:00+00:00",
"data_dir": "/path/to/profiles/abc123/browser-data",
"last_launched_at": "2026-01-15T12:30:00+00:00"
}doctor --json:
Returns diagnostic checks, repairs performed, and overall health status:
{
"checks": [
{
"id": "python_version",
"status": "ok",
"summary": "Python version is 3.11.0 (>= 3.9 required)."
},
{
"id": "stale_running_state",
"status": "warning",
"summary": "Found 1 stale running.json file(s).",
"action": "Run 'profiledock doctor --repair' to clean stale running-state files."
}
],
"repairs": [
{
"id": "repair_stale_running_state",
"status": "ok",
"summary": "Cleaned up 1 stale running.json file(s)."
}
],
"healthy": true
}migrate --json:
Returns details of migrated, skipped, and failed profiles:
{
"source_root": "/path/to/source",
"destination_root": "/path/to/destination",
"migrated": [
{
"id": "abc123",
"name": "Work",
"status": "migrated",
"message": "successfully migrated"
}
],
"skipped": [],
"failed": [],
"source_removed": false
}Guarantees:
- JSON output is always valid and parseable
- No human prose mixed with JSON
- No sensitive data exposed (tokens, secrets, passwords)
- Field names and types are stable across versions
statusandlistalways return arrays for consistent scripting- Timestamps use ISO-8601 format with a timezone offset when present
If the project was cloned with Git:
git pull
python scripts/setup_project.pyRerunning setup updates the editable installation and executes the tests. Review the current version in pyproject.toml, profiledock.__version__, or the release tag.
Playwright's CDN may be unavailable in some locations. Install Chrome or Chromium and rerun setup. The script detects supported system browsers and avoids the blocked download.
Activate .venv, or run the executable using its full project-local path:
.\.venv\Scripts\profiledock.exe --helpClose it normally:
profiledock close <id>If the browser or controller stopped unexpectedly, run profiledock list. ProfileDock detects dead controller processes and cleans stale running state.
The profile metadata exists but its browser-data directory was moved or deleted. Restore the directory from a backup or delete and recreate the affected profile.
Run profiledock doctor --repair to validate and restore profiles.json.bak. If both files are corrupted, restore from a manual backup. Normal profile commands intentionally refuse to overwrite corrupted metadata automatically.
This is normal. ProfileDock uses an operating-system lock on this file, so an unlocked file may remain on disk safely. Do not use file existence to decide whether a metadata operation is active.
When profiledock launch fails, the CLI now shows a specific error message instead of a generic failure. Common causes and fixes:
Playwright package not installed:
Error: No module named 'playwright'
Rerun project setup with python scripts/setup_project.py, or install Playwright through the active virtual environment.
No supported browser found:
Error: Playwright Chromium: <error>\nGoogle Chrome: <error>\nSystem browser: <error or not found>
Either install Playwright Chromium (playwright install chromium) or install Chrome or Chromium on your system.
Browser process failed to launch: The error message will include Playwright's diagnostic details. Check that the profile data directory exists and is accessible.
Controller startup timed out: The browser took longer than 30 seconds to become ready. Check system resources and close other applications.
Controller process exited unexpectedly: The controller subprocess crashed. Check for system resource constraints or permission issues.
When a controller fails, ProfileDock preserves a diagnostic file at runtime/<id>/controller.error beneath the selected data root. It contains a stable error category, a bounded diagnostic message, and the browser channel attempted when relevant. Diagnostics are limited to 4 KiB, controller tokens are redacted, and the file is automatically cleaned up on the next successful launch.
Profile data is separate from the source project, so decide whether to keep or delete both locations.
List profiles and close every entry marked running:
profiledock list
profiledock close <id>To preserve login state and browser data, copy these items to a secure location:
metadata/
backups/
profiles/
They must be restored together beneath the same data root.
This removes browsers installed by this Playwright environment. It does not remove system Google Chrome.
Windows:
.\.venv\Scripts\python.exe -m playwright uninstallmacOS and Linux:
./.venv/bin/python -m playwright uninstallDeactivate it first if active:
deactivateThen delete the .venv directory. This removes installed Python dependencies but keeps source code and application data. The setup script can recreate it later.
Close all profiles, leave the project directory in your terminal, and delete the profiledock folder using File Explorer, Finder, or your desktop environment's file manager. Moving it to the Recycle Bin or Trash is recommended because it remains recoverable until emptied.
Deleting the source project does not delete ProfileDock application data. Remove the platform data root separately only after closing profiles and confirming that no browser state must be retained.
The default application-data roots are %LOCALAPPDATA%\ProfileDock on Windows, ~/Library/Application Support/ProfileDock on macOS, and ${XDG_DATA_HOME:-~/.local/share}/profiledock on Linux. If PROFILEDOCK_DATA_ROOT or --data-root was used, remove that selected directory instead. Deleting the data root permanently removes every ProfileDock profile, session, cookie, cache, backup, and runtime record stored there.
ProfileDock follows Semantic Versioning. Stable releases use annotated Git tags such as v0.7.3.
ProfileDock is available under the MIT License. See LICENSE for the full terms.