Dokümantasyon

GetWebP CLI JSON Output Reference

Machine-readable output schemas for every GetWebP CLI command.

GetWebP CLI JSON Output Reference

Machine-readable output schemas for every GetWebP CLI command. Use --json on any command to emit structured JSON on stdout (human messages go to stderr).

See also: Commands Reference | Exit Codes | CI Integration


Overview#

Every JSON response follows a common envelope:

interface BaseResponse {
  success: boolean       // true if the operation completed without errors
  status?: string        // "success" | "error" | "partial"
  error?: string         // machine-readable error code (on failure)
  message?: string       // human-readable description (on failure or partial)
  data?: object          // command-specific payload (auth, status, logout)
  upgrade?: UpgradeHint  // present on Free plan (convert only)
}
 
interface UpgradeHint {
  url: string               // "https://getwebp.com/pricing"
  activateCommand: string   // "getwebp auth <your-key>"
}

Key conventions:

  • JSON is always a single line terminated by \n (no pretty-printing).
  • Warnings and progress messages are written to stderr, never mixed into the JSON stream.
  • Every command exits with a numeric exit code regardless of --json.

getwebp convert --json#

The convert command outputs a single summary object after all files have been processed. It is not a streaming event format.

Schema#

// Full success or partial failure (some files errored)
interface ConvertResponse {
  success: boolean        // true only when ALL files succeeded
  status: "success" | "error"
  total: number           // total files attempted
  successCount: number    // files converted successfully
  failedCount: number     // files that errored
  results: FileResult[]   // per-file details
  upgrade?: UpgradeHint   // present when plan is "free" and results.length > 0
}
 
// Free plan limit reached (skipped > 0)
interface ConvertPartialResponse {
  success: true
  status: "partial"
  message: string         // human-readable summary with upgrade CTA
  data: {
    processed: number     // files actually converted
    skipped: number       // files skipped due to Free plan limit
  }
  upgrade: UpgradeHint
}

FileResult union#

Each element in the results array is one of three shapes:

// Successfully converted
interface SuccessResult {
  file: string            // input file path
  originalSize: number    // bytes
  newSize: number         // bytes
  savedRatio: number      // 0 to 1 (negative if WebP is larger)
  saved: string           // human-friendly percentage, e.g. "35.0%"
  status: "success"
}
 
// Conversion failed
interface ErrorResult {
  file: string
  status: "error"
  error: string           // e.g. "Decode failed: Unsupported format"
}
 
// Skipped (--skip-existing or WebP self-overwrite)
interface SkipResult {
  file: string
  status: "skipped"
  reason: "existing"
}

Note: The saved field (string) is added to success results only in JSON output. It is derived from savedRatio as (savedRatio * 100).toFixed(1) + "%".

Examples#

All files succeed (Starter/Pro plan):

{
  "success": true,
  "status": "success",
  "total": 3,
  "successCount": 3,
  "failedCount": 0,
  "results": [
    { "file": "photos/hero.jpg", "originalSize": 204800, "newSize": 133120, "savedRatio": 0.35, "saved": "35.0%", "status": "success" },
    { "file": "photos/logo.png", "originalSize": 51200, "newSize": 20480, "savedRatio": 0.6, "saved": "60.0%", "status": "success" },
    { "file": "photos/banner.bmp", "originalSize": 921600, "newSize": 184320, "savedRatio": 0.8, "saved": "80.0%", "status": "success" }
  ]
}

Mixed success and failure:

{
  "success": false,
  "status": "error",
  "total": 2,
  "successCount": 1,
  "failedCount": 1,
  "results": [
    { "file": "photo.jpg", "originalSize": 204800, "newSize": 133120, "savedRatio": 0.35, "saved": "35.0%", "status": "success" },
    { "file": "corrupt.png", "status": "error", "error": "Decode failed: Invalid PNG header" }
  ]
}

Free plan with skipped files (limit reached):

{
  "success": true,
  "status": "partial",
  "message": "Processed 10 images. Free plan limit reached (5 remaining). Upgrade at getwebp.com/pricing, then run: getwebp auth <your-key>",
  "data": {
    "processed": 10,
    "skipped": 5
  },
  "upgrade": {
    "url": "https://getwebp.com/pricing",
    "activateCommand": "getwebp auth <your-key>"
  }
}

Free plan, all files processed (under limit):

{
  "success": true,
  "status": "success",
  "total": 3,
  "successCount": 3,
  "failedCount": 0,
  "results": [
    { "file": "a.jpg", "originalSize": 102400, "newSize": 71680, "savedRatio": 0.3, "saved": "30.0%", "status": "success" }
  ],
  "upgrade": {
    "url": "https://getwebp.com/pricing",
    "activateCommand": "getwebp auth <your-key>"
  }
}

On the Free plan, the upgrade object is always present when at least one file was processed, even if the file limit was not reached.

Missing input path:

{
  "success": false,
  "status": "error",
  "error": "missing_input",
  "message": "Please specify an input path"
}

getwebp auth --json#

Schema#

// Success
interface AuthSuccessResponse {
  success: true
  data: {
    message: string   // e.g. "Activated — Starter plan unlocked"
  }
}
 
// Failure
interface AuthErrorResponse {
  success: false
  status: "error"
  error: "unknown_error"
  message: string         // server-provided error description
}

Examples#

Successful activation:

{
  "success": true,
  "data": {
    "message": "Activated — Starter plan unlocked"
  }
}

Failed activation:

{
  "success": false,
  "status": "error",
  "error": "unknown_error",
  "message": "Invalid license key"
}

getwebp status --json#

The shape of the data object varies depending on the license state.

Schema#

// Free plan (never activated)
interface StatusFreeResponse {
  success: true
  data: {
    version: string       // e.g. "1.0.1"
    mode: "free"
  }
}
 
// Active license, online (full status from server)
interface StatusOnlineResponse {
  success: true
  data: {
    version: string
    mode: "starter" | "pro"
    licenseKeySuffix: string    // last 4 characters, e.g. "A1B2"
    expiresAt: string           // ISO 8601, e.g. "2027-04-01T00:00:00.000Z"
    devicesUsed: number
    devicesLimit: number
  }
}
 
// Active license, server cache (server returned data with cached flag)
interface StatusCachedResponse {
  success: true
  data: {
    version: string
    mode: "starter" | "pro"
    licenseKeySuffix: string
    expiresAt: string
    cached: true                // indicates data is from local cache
  }
}
 
// Token exists but server unreachable and no status cache (JWT-only fallback)
interface StatusOfflineResponse {
  success: true
  data: {
    version: string
    mode: "pro"
    cached: true
    expiresAt?: string          // ISO 8601 (from JWT exp claim)
  }
}

Note on cached: The cached field is only present (and set to true) when the data comes from a local cache rather than a live server response. When the server responds successfully, cached is omitted and devicesUsed/devicesLimit are included instead.

Examples#

Free plan:

{
  "success": true,
  "data": {
    "version": "1.0.1",
    "mode": "free"
  }
}

Active Starter license (online):

{
  "success": true,
  "data": {
    "version": "1.0.1",
    "mode": "starter",
    "licenseKeySuffix": "A1B2",
    "expiresAt": "2027-04-01T00:00:00.000Z",
    "devicesUsed": 1,
    "devicesLimit": 3
  }
}

Cached status (offline):

{
  "success": true,
  "data": {
    "version": "1.0.1",
    "mode": "pro",
    "licenseKeySuffix": "X9Z7",
    "expiresAt": "2027-04-01T00:00:00.000Z",
    "cached": true
  }
}

JWT-only fallback (offline, no status cache):

{
  "success": true,
  "data": {
    "version": "1.0.1",
    "mode": "pro",
    "cached": true,
    "expiresAt": "2027-04-01T00:00:00.000Z"
  }
}

getwebp logout --json#

When --json is used, the interactive confirmation prompt is automatically skipped (same behavior as --force).

Schema#

// Success
interface LogoutSuccessResponse {
  success: true
  data: {
    message: "Device unbound. Switched to Free plan."
  }
}
 
// Failure
interface LogoutErrorResponse {
  success: false
  status: "error"
  error: string       // machine-readable code (see table below)
  message: string     // human-readable description
}

Error codes#

error valuemessageRetryable
network_unreachableCannot reach server. Retry later or unbind via dashboard.Yes
not_activatedNo active license on this device.No
device_not_foundDevice not found. It may have already been unbound.No
invalid_tokenToken is invalid or expired.No
OtherPassed through from serverVaries

Examples#

Successful logout:

{
  "success": true,
  "data": {
    "message": "Device unbound. Switched to Free plan."
  }
}

Network failure:

{
  "success": false,
  "status": "error",
  "error": "network_unreachable",
  "message": "Cannot reach server. Retry later or unbind via dashboard."
}

No active license:

{
  "success": false,
  "status": "error",
  "error": "not_activated",
  "message": "No active license on this device."
}

Error Codes Summary#

All machine-readable error codes across commands:

CodeCommandsMeaningRetryable
missing_inputconvertNo input path specifiedNo
unknown_errorauthUnclassified activation failureVaries
network_unreachablelogoutCannot reach API serverYes
not_activatedlogoutNo active license on deviceNo
device_not_foundlogoutDevice already unboundNo
invalid_tokenlogoutToken expired or revokedNo

jq Recipes#

Common pipelines for CI scripts and automation.

Convert command#

# Check if all conversions succeeded
getwebp convert ./images --json | jq '.success'
 
# Get total bytes saved
getwebp convert ./images --json | jq '[.results[] | select(.status == "success") | (.originalSize - .newSize)] | add'
 
# List failed files
getwebp convert ./images --json | jq '[.results[] | select(.status == "error") | .file]'
 
# Get average compression ratio
getwebp convert ./images --json | jq '[.results[] | select(.status == "success") | .savedRatio] | add / length'
 
# Exit with error if any file failed
getwebp convert ./images --json | jq -e '.success' > /dev/null
 
# Check if Free plan limit was hit
getwebp convert ./images --json | jq 'select(.status == "partial") | .data.skipped'
 
# Extract file names and sizes as CSV
getwebp convert ./images --json | jq -r '.results[] | select(.status == "success") | [.file, .originalSize, .newSize, .saved] | @csv'

Status command#

# Get current plan
getwebp status --json | jq -r '.data.mode'
 
# Check if license is active (not free)
getwebp status --json | jq '.data.mode != "free"'
 
# Get expiry date
getwebp status --json | jq -r '.data.expiresAt // "N/A"'
 
# Check device usage
getwebp status --json | jq '"\(.data.devicesUsed // "?") / \(.data.devicesLimit // "?")"'
 
# Check if status is cached (offline)
getwebp status --json | jq '.data.cached // false'

Auth and logout#

# Activate and check result
getwebp auth XXXX-XXXX-XXXX-XXXX --json | jq -e '.success'
 
# Logout (--json skips confirmation automatically)
getwebp logout --json | jq -e '.success'

CI pipeline pattern#

#!/usr/bin/env bash
set -euo pipefail
 
result=$(getwebp convert ./src/images -o ./dist/images -q 85 --json)
 
success=$(echo "$result" | jq -r '.success')
if [ "$success" != "true" ]; then
  echo "Conversion failed:" >&2
  echo "$result" | jq -r '.results[] | select(.status == "error") | "  \(.file): \(.error)"' >&2
  exit 1
fi
 
total=$(echo "$result" | jq -r '.total')
saved=$(echo "$result" | jq '[.results[] | select(.status == "success") | (.originalSize - .newSize)] | add')
echo "Converted $total images, saved $saved bytes total"

Stderr Warnings#

Regardless of --json, the CLI may emit warnings to stderr. These are not part of the JSON output and should not be parsed as JSON. Examples:

warn: Free plan: max 10 files, 3s delay between each.
warn: No --output specified: converted files will be written next to source files.
warn: Conflict: a.png, a.jpg all map to a.webp — only the last processed will survive

To suppress warnings in scripts, redirect stderr:

getwebp convert ./images --json 2>/dev/null

AI Agent Integration#

For LLMs and AI agents consuming GetWebP output:

  1. Always use --json to get structured output on stdout.
  2. Parse the top-level success field first to determine the overall result.
  3. Check status for finer granularity: "success", "error", or "partial".
  4. When status is "partial", the upgrade object contains the URL and CLI command to guide the user toward upgrading.
  5. Per-file errors are in results[].error -- these are human-readable strings, not error codes.
  6. Combine --json with exit codes for robust error handling: exit code 0 = full success, 2 = partial failure.