Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/pinchtab/pinchtab/llms.txt

Use this file to discover all available pages before exploring further.

Profiles are browser user data directories that store persistent browser state including cookies, local storage, browsing history, and extensions.

Overview

A profile contains:
  • Cookies and session data
  • Local storage and IndexedDB
  • Browsing history
  • Cached resources
  • Saved passwords (if enabled)
  • Extensions and settings
Profiles are identified by hash-based IDs: prof_XXXXXXXX derived from profile name

Profile Types

Named Profiles (Persistent)

Created explicitly and persist across instance restarts:
# Create named profile
pinchtab profile create work

# Use with instance
pinchtab instance start --profileId work
Stored in: ~/.pinchtab/profiles/prof_XXXXXXXX/

Temporary Profiles (Auto-Generated)

Created automatically when instance starts without a profile:
# Instance creates temp profile
pinchtab instance start
# Uses: "instance-temp-abc123"
Temporary profiles are deleted when the instance stops. Use named profiles for persistent state.

Creating Profiles

Basic Profile

# CLI
pinchtab profile create my-profile

# API
curl -X POST http://localhost:9867/profiles \
  -H "Content-Type: application/json" \
  -d '{"name": "my-profile"}'
Response:
{
  "status": "created",
  "id": "prof_9f86d081",
  "name": "my-profile"
}

With Metadata

curl -X POST http://localhost:9867/profiles \
  -d '{
    "name": "alice-work",
    "description": "Alice's work account",
    "useWhen": "Production automation tasks"
  }'

Profile Structure

~/.pinchtab/profiles/prof_9f86d081/
├── Default/
│   ├── Preferences          # Chrome settings
│   ├── Cookies             # HTTP cookies
│   ├── Cookies-journal
│   ├── History             # Browsing history
│   ├── Local Storage/
│   ├── Session Storage/
│   ├── Cache/              # Resource cache
│   ├── Code Cache/
│   └── ...
├── profile.json            # PinchTab metadata
└── .pinchtab-state/        # Instance state
// Source: internal/profiles/profiles.go:293-295
// Profile directory creation:
if err := os.MkdirAll(filepath.Join(dest, "Default"), 0755); err != nil {
    return err
}

Listing Profiles

# CLI
pinchtab profiles

# API
curl http://localhost:9867/profiles | jq .
Response:
[
  {
    "id": "prof_278be873",
    "name": "work",
    "path": "/home/user/.pinchtab/profiles/prof_278be873",
    "pathExists": true,
    "created": "2026-03-01T05:21:38.274Z",
    "diskUsage": 5242880,
    "sizeMB": 5.0,
    "running": false,
    "temporary": false,
    "source": "created",
    "accountEmail": "alice@example.com",
    "accountName": "Alice",
    "hasAccount": true,
    "description": "Work account profile",
    "useWhen": "Production tasks"
  }
]
The API excludes temporary profiles by default. Only named profiles are returned.

Account Detection

PinchTab automatically detects logged-in accounts:
// Source: internal/profiles/identity.go:9-24
// Reads from:
// - Default/Preferences (account_info)
// - Local State (profile.info_cache)
//
// Extracts:
// - Email address
// - Account name
// - Chrome profile name
func readChromeProfileIdentity(profileRoot string) (string, string, string, bool) {
    chromeProfileName, lsEmail, lsName, lsHas := readLocalStateIdentity(...)
    prefsEmail, prefsName, prefsHas := readPreferencesIdentity(...)
    // ...
}
Example Detection:
{
  "accountEmail": "alice@example.com",
  "accountName": "Alice Cooper",
  "chromeProfileName": "Profile 1",
  "hasAccount": true
}

Using Profiles with Instances

By Profile ID

curl -X POST http://localhost:9867/instances/start \
  -d '{"profileId": "prof_278be873"}'

By Profile Name

curl -X POST http://localhost:9867/instances/start \
  -d '{"profileId": "work"}'
PinchTab resolves both profile IDs and names automatically

Profile Operations

Import Existing Profile

Import a Chrome profile from another location:
pinchtab profile import my-chrome ~/.config/google-chrome/Default
// Source: internal/profiles/profiles.go:223-264
// Validates source directory has Chrome data:
if _, err := os.Stat(filepath.Join(sourcePath, "Default")); err != nil {
    return fmt.Errorf("source doesn't look like a Chrome user data dir")
}

// Copies entire directory:
if err := copyDir(sourcePath, dest); err != nil {
    return fmt.Errorf("copy failed: %w", err)
}

Reset Profile

Clear cookies and cache while keeping profile:
pinchtab profile reset work
Removes:
  • Cookies and cookies journal
  • Session storage
  • Cache directories
  • Browsing history
  • Temporary files
Preserves:
  • Profile metadata
  • Extensions
  • Bookmarks
  • Settings
// Source: internal/profiles/profiles.go:329-357
nukeDirs := []string{
    "Default/Sessions",
    "Default/Session Storage",
    "Default/Cache",
    "Default/Code Cache",
    // ...
}
nukeFiles := []string{
    "Default/Cookies",
    "Default/History",
    // ...
}

Delete Profile

# CLI
pinchtab profile delete work

# API
curl -X DELETE http://localhost:9867/profiles/work
Deletion is permanent and removes all profile data including cookies, history, and saved state.

Update Metadata

curl -X PATCH http://localhost:9867/profiles/work \
  -d '{
    "description": "Updated description",
    "useWhen": "New use case"
  }'

Common Workflows

Separate User Accounts

# Create profiles for each user
pinchtab profile create alice
pinchtab profile create bob

# Start instances with different profiles
INST_ALICE=$(curl -s -X POST http://localhost:9867/instances/start \
  -d '{"profileId":"alice"}' | jq -r .id)

INST_BOB=$(curl -s -X POST http://localhost:9867/instances/start \
  -d '{"profileId":"bob"}' | jq -r .id)

# Each instance has isolated cookies and sessions
1

Create profiles

One profile per user account
2

Start instances

Each instance uses a different profile
3

Login once

Credentials persist in profile
4

Reuse sessions

Restart instances with same profiles

Login Once, Use Everywhere

# Create persistent profile
pinchtab profile create work

# Start instance and login
INST=$(curl -s -X POST http://localhost:9867/instances/start \
  -d '{"profileId":"work"}' | jq -r .id)

# Navigate and login (manual or automated)
curl -X POST http://localhost:9867/instances/$INST/tabs/open \
  -d '{"url":"https://app.example.com/login"}'

# ... perform login ...

# Stop instance (profile preserved)
curl -X POST http://localhost:9867/instances/$INST/stop

# Later: Start new instance with same profile
# Already logged in!
INST2=$(curl -s -X POST http://localhost:9867/instances/start \
  -d '{"profileId":"work"}' | jq -r .id)

Development vs Production

# Dev profile (visible browser)
pinchtab profile create dev
pinchtab instance start --profileId dev --mode headed

# Production profile (headless)
pinchtab profile create prod  
pinchtab instance start --profileId prod --mode headless

Profile Security

Path Validation

Profiles are validated to prevent path traversal attacks:
// Source: internal/profiles/profiles.go:26-37
func ValidateProfileName(name string) error {
    if name == "" {
        return fmt.Errorf("profile name cannot be empty")
    }
    if strings.Contains(name, "..") {
        return fmt.Errorf("profile name cannot contain '..'")
    }
    if strings.ContainsAny(name, "/\\") {
        return fmt.Errorf("profile name cannot contain '/' or '\\'")
    }
    return nil
}

Safe Profile Names

Valid:
  • work
  • alice-dev
  • prod_profile_1
  • test2026
Invalid:
  • ../etc/passwd (path traversal)
  • work/prod (contains slash)
  • ..profile (starts with ..)

Profile Disk Usage

Profiles can grow large over time:
// Source: internal/profiles/profiles.go:389-402
func dirSizeMB(path string) float64 {
    var total int64
    _ = filepath.WalkDir(path, func(_ string, entry fs.DirEntry, err error) error {
        if err != nil || entry.IsDir() {
            return nil
        }
        info, err := entry.Info()
        if err == nil {
            total += info.Size()
        }
        return nil
    })
    return float64(total) / (1024 * 1024)
}

Monitor Usage

# View profile sizes
curl http://localhost:9867/profiles | jq '.[] | {name, sizeMB}'

Reduce Size

# Reset profile (clears cache/cookies)
pinchtab profile reset work

# Or delete unused profiles
pinchtab profile delete old-profile

Profile Metadata

Metadata is stored in profile.json:
{
  "id": "prof_278be873",
  "name": "work",
  "description": "Work account profile",
  "useWhen": "Production automation tasks"
}
// Source: internal/profiles/identity.go:103-109
func writeProfileMeta(profileDir string, meta ProfileMeta) error {
    data, err := json.MarshalIndent(meta, "", "  ")
    if err != nil {
        return err
    }
    return os.WriteFile(filepath.Join(profileDir, "profile.json"), data, 0644)
}

Best Practices

Use Named Profiles for Production

# Good: Persistent profile
pinchtab profile create prod
pinchtab instance start --profileId prod

# Bad: Temporary profile (lost on stop)
pinchtab instance start

Organize Profiles by Purpose

pinchtab profile create dev-testing
pinchtab profile create staging-qa
pinchtab profile create prod-automation
pinchtab profile create demo-account

Regular Cleanup

# List profiles sorted by size
curl http://localhost:9867/profiles | \
  jq 'sort_by(.sizeMB) | reverse | .[] | {name, sizeMB}'

# Reset large profiles
pinchtab profile reset dev-testing

# Delete unused profiles
pinchtab profile delete old-temp

Backup Important Profiles

# Find profile path
PROF_PATH=$(curl -s http://localhost:9867/profiles | \
  jq -r '.[] | select(.name=="work") | .path')

# Backup
tar -czf work-profile-backup.tar.gz "$PROF_PATH"

# Restore
tar -xzf work-profile-backup.tar.gz -C ~/.pinchtab/profiles/

Troubleshooting

Profile Not Found

# List all profiles
pinchtab profiles

# Check if name is correct
curl http://localhost:9867/profiles | jq '.[] | .name'

Corrupted Profile

# Reset profile to clean state
pinchtab profile reset problematic-profile

# Or delete and recreate
pinchtab profile delete problematic-profile
pinchtab profile create problematic-profile

Profile Already in Use

# Check running instances
curl http://localhost:9867/instances | \
  jq '.[] | {id, profileName, status}'

# Stop instance using the profile
pinchtab instance stop inst_XXXXXXXX

Next Steps

Browser Instances

Launch instances with profiles

Multi-Instance Guide

Manage login sessions and cookies

Profile API

Complete API reference

AI Agent Integration

Simulate multiple users