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
savedfield (string) is added to success results only in JSON output. It is derived fromsavedRatioas(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
upgradeobject 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: Thecachedfield is only present (and set totrue) when the data comes from a local cache rather than a live server response. When the server responds successfully,cachedis omitted anddevicesUsed/devicesLimitare 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 value | message | Retryable |
|---|---|---|
network_unreachable | Cannot reach server. Retry later or unbind via dashboard. | Yes |
not_activated | No active license on this device. | No |
device_not_found | Device not found. It may have already been unbound. | No |
invalid_token | Token is invalid or expired. | No |
| Other | Passed through from server | Varies |
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:
| Code | Commands | Meaning | Retryable |
|---|---|---|---|
missing_input | convert | No input path specified | No |
unknown_error | auth | Unclassified activation failure | Varies |
network_unreachable | logout | Cannot reach API server | Yes |
not_activated | logout | No active license on device | No |
device_not_found | logout | Device already unbound | No |
invalid_token | logout | Token expired or revoked | No |
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/nullAI Agent Integration#
For LLMs and AI agents consuming GetWebP output:
- Always use
--jsonto get structured output on stdout. - Parse the top-level
successfield first to determine the overall result. - Check
statusfor finer granularity:"success","error", or"partial". - When
statusis"partial", theupgradeobject contains the URL and CLI command to guide the user toward upgrading. - Per-file errors are in
results[].error-- these are human-readable strings, not error codes. - Combine
--jsonwith exit codes for robust error handling: exit code0= full success,2= partial failure.