CI Integration
Automate image optimization in your CI/CD pipeline with GetWebP CLI.
CI Integration
Automate image optimization in your CI/CD pipeline with GetWebP CLI. This guide provides copy-paste-ready workflows for GitHub Actions and GitLab CI, with best practices for license management, structured output, and error handling.
See also: Commands Reference | JSON Output | Exit Codes | Getting Started
Table of Contents#
- Prerequisites
- Installation in CI
- License Key in CI
- GitHub Actions
- GitLab CI
- Best Practices
- Exit Codes in CI
- Parsing JSON Output
- Troubleshooting
Prerequisites#
- A GetWebP Starter or Pro license key (purchase at getwebp.com/pricing). The Free plan works but is limited to 10 files per run with a 3-second delay per file.
- Images in your repository or build artifacts to convert.
jqinstalled in your CI environment (pre-installed on GitHub Actions runners and most GitLab runners).
Installation in CI#
Option A: Download the Binary (Recommended)#
Download a pre-built binary from getwebp.com/download. This approach has no runtime dependencies and starts instantly.
# Linux x64 (most CI runners)
curl -fsSL -o getwebp https://getwebp.com/download/getwebp-linux-x64
chmod +x getwebp
sudo mv getwebp /usr/local/bin/Option B: Install via npm#
Requires Node.js >= 18 in the runner image.
npm install -g getwebpLicense Key in CI#
Store your license key as a CI secret -- never hardcode it in workflow files.
GitHub Actions#
- Go to Settings > Secrets and variables > Actions in your repository.
- Click New repository secret.
- Name:
GETWEBP_LICENSE_KEY, Value: your license key (e.g.XXXX-XXXX-XXXX-XXXX).
GitLab CI#
- Go to Settings > CI/CD > Variables in your project.
- Click Add variable.
- Key:
GETWEBP_LICENSE_KEY, Value: your license key. - Enable Mask variable to hide it from job logs.
Activating the License#
Run getwebp auth at the start of each pipeline job. The activation binds to a device fingerprint -- CI runners generate a new fingerprint per job, so each run consumes and releases a device slot.
getwebp auth "$GETWEBP_LICENSE_KEY" --jsonTip: If activation fails with exit code
3, verify the key is correct and that you have not exceeded your device limit. Manage devices at getwebp.com/dashboard.
GitHub Actions#
Complete Workflow#
Save this as .github/workflows/optimize-images.yml:
name: Optimize Images
on:
push:
branches: [main]
paths:
- "src/images/**"
pull_request:
paths:
- "src/images/**"
jobs:
optimize:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install GetWebP CLI
run: |
curl -fsSL -o getwebp https://getwebp.com/download/getwebp-linux-x64
chmod +x getwebp
sudo mv getwebp /usr/local/bin/
getwebp --version
- name: Activate license
if: ${{ secrets.GETWEBP_LICENSE_KEY != '' }}
run: getwebp auth "$GETWEBP_LICENSE_KEY" --json
env:
GETWEBP_LICENSE_KEY: ${{ secrets.GETWEBP_LICENSE_KEY }}
- name: Convert images to WebP
id: convert
run: |
getwebp convert ./src/images \
-o ./dist/images \
-q 85 \
-r \
--skip-existing \
--json > conversion.json
# Print summary
echo "### Image Optimization Results" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
total=$(jq -r '.total // 0' conversion.json)
success=$(jq -r '.successCount // 0' conversion.json)
failed=$(jq -r '.failedCount // 0' conversion.json)
echo "- **Total:** $total" >> "$GITHUB_STEP_SUMMARY"
echo "- **Succeeded:** $success" >> "$GITHUB_STEP_SUMMARY"
echo "- **Failed:** $failed" >> "$GITHUB_STEP_SUMMARY"
- name: Upload converted images
uses: actions/upload-artifact@v4
with:
name: optimized-images
path: dist/images/
- name: Fail on conversion errors
run: |
success=$(jq -r '.success' conversion.json)
if [ "$success" != "true" ]; then
echo "::error::Some images failed to convert"
jq -r '.results[] | select(.status == "error") | "::error file=\(.file)::\(.error)"' conversion.json
exit 1
fiMinimal Workflow (Free Plan)#
No license key required. Limited to 10 files per run.
name: Optimize Images (Free)
on:
push:
branches: [main]
paths:
- "src/images/**"
jobs:
optimize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install GetWebP CLI
run: |
curl -fsSL -o getwebp https://getwebp.com/download/getwebp-linux-x64
chmod +x getwebp
sudo mv getwebp /usr/local/bin/
- name: Convert images
run: getwebp convert ./src/images -o ./dist/images --skip-existing --json
- uses: actions/upload-artifact@v4
with:
name: optimized-images
path: dist/images/Commit Converted Images Back to the Repository#
If you want the pipeline to commit WebP files back into the repository:
- name: Convert and commit
run: |
getwebp convert ./src/images -r --skip-existing --json > /dev/null
if git diff --quiet; then
echo "No new images to commit."
else
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add "*.webp"
git commit -m "chore: optimize images to WebP"
git push
fiGitLab CI#
Complete Pipeline#
Save this as .gitlab-ci.yml (or add the job to your existing file):
optimize-images:
stage: build
image: ubuntu:22.04
variables:
GETWEBP_LICENSE_KEY: $GETWEBP_LICENSE_KEY
before_script:
- apt-get update -qq && apt-get install -y -qq curl jq > /dev/null
- curl -fsSL -o /usr/local/bin/getwebp https://getwebp.com/download/getwebp-linux-x64
- chmod +x /usr/local/bin/getwebp
- getwebp --version
- |
if [ -n "$GETWEBP_LICENSE_KEY" ]; then
getwebp auth "$GETWEBP_LICENSE_KEY" --json
fi
script:
- |
getwebp convert ./src/images \
-o ./dist/images \
-q 85 \
-r \
--skip-existing \
--json > conversion.json
code=$?
total=$(jq -r '.total // 0' conversion.json)
success_count=$(jq -r '.successCount // 0' conversion.json)
failed_count=$(jq -r '.failedCount // 0' conversion.json)
echo "Converted $success_count / $total images ($failed_count failed)"
if [ "$code" -ne 0 ]; then
jq -r '.results[] | select(.status == "error") | "\(.file): \(.error)"' conversion.json
exit $code
fi
artifacts:
paths:
- dist/images/
expire_in: 1 week
rules:
- changes:
- "src/images/**"Using npm Instead of Binary Download#
optimize-images:
stage: build
image: node:20-slim
before_script:
- npm install -g getwebp
- |
if [ -n "$GETWEBP_LICENSE_KEY" ]; then
getwebp auth "$GETWEBP_LICENSE_KEY" --json
fi
script:
- getwebp convert ./src/images -o ./dist/images -r --skip-existing --json
artifacts:
paths:
- dist/images/
expire_in: 1 weekBest Practices#
Use --skip-existing#
Always pass --skip-existing in CI. It skips files that already have a .webp counterpart at the output path, making incremental builds fast and avoiding redundant work.
getwebp convert ./images -o ./dist -r --skip-existingUse --json for Machine-Readable Output#
The --json flag outputs structured JSON on stdout while keeping human-readable messages on stderr. This makes it safe to pipe into jq or save to a file for post-processing.
getwebp convert ./images --json > results.jsonSee JSON Output for the full schema.
Use --dry-run for Validation#
Preview which files would be converted without writing anything. Useful for PR checks that validate image formats without producing artifacts.
getwebp convert ./images -r --dry-run --jsonPin the CLI Version#
For reproducible builds, pin the CLI version by downloading a specific release rather than always fetching the latest:
GETWEBP_VERSION="1.0.1"
curl -fsSL -o getwebp "https://getwebp.com/download/getwebp-linux-x64?v=${GETWEBP_VERSION}"Parallel Processing#
On Starter/Pro plans, GetWebP automatically uses all available CPU cores minus one. You can tune this with --concurrency:
# Use 4 workers (useful for memory-constrained CI runners)
getwebp convert ./images -r --concurrency 4 --jsonExit Codes in CI#
GetWebP CLI returns semantic exit codes that map directly to CI pipeline decisions:
| Exit Code | Meaning | CI Action |
|---|---|---|
0 | All files converted successfully | Continue pipeline |
1 | General error (bad arguments, activation failure) | Fail the job |
2 | Partial failure (some files succeeded, some failed) | Warn or fail (your choice) |
3 | License / auth error | Fail the job; check secrets |
4 | Network error (API unreachable) | Retry the job |
Handling Exit Codes in a Shell Script#
#!/usr/bin/env bash
set -uo pipefail
getwebp convert ./images -o ./dist --json > results.json
code=$?
case $code in
0)
echo "All images converted successfully."
;;
2)
echo "Warning: some files failed. Review results.json." >&2
# Decide: exit 0 to continue or exit 1 to fail
jq -r '.results[] | select(.status == "error") | "\(.file): \(.error)"' results.json >&2
exit 1
;;
3)
echo "License error. Verify GETWEBP_LICENSE_KEY is set correctly." >&2
exit 1
;;
4)
echo "Network error. The GetWebP API may be temporarily unavailable." >&2
exit 1
;;
*)
echo "getwebp exited with code $code" >&2
exit 1
;;
esacRetry on Network Errors#
MAX_RETRIES=3
DELAY=10
for attempt in $(seq 1 $MAX_RETRIES); do
getwebp convert ./images -o ./dist --skip-existing --json > results.json
code=$?
if [ $code -eq 0 ]; then
echo "Success on attempt $attempt."
break
elif [ $code -eq 4 ] && [ $attempt -lt $MAX_RETRIES ]; then
echo "Network error. Retrying in ${DELAY}s (attempt $attempt/$MAX_RETRIES)..." >&2
sleep $DELAY
DELAY=$((DELAY * 2))
else
echo "Failed with exit code $code on attempt $attempt." >&2
exit $code
fi
doneSee Exit Codes for detailed descriptions of every exit code.
Parsing JSON Output#
Use jq to extract information from --json output for CI reporting and decisions.
Check Overall Success#
getwebp convert ./images --json | jq -e '.success' > /dev/nullThe -e flag causes jq to exit with code 1 when the result is false, which pairs well with set -e in shell scripts.
Extract Failed Files#
jq -r '.results[] | select(.status == "error") | "\(.file): \(.error)"' results.jsonCalculate Total Bytes Saved#
jq '[.results[] | select(.status == "success") | (.originalSize - .newSize)] | add' results.jsonExport Metrics as CSV#
jq -r '.results[] | select(.status == "success") | [.file, .originalSize, .newSize, .saved] | @csv' results.jsonDetect Free Plan Limit#
status=$(jq -r '.status' results.json)
if [ "$status" = "partial" ]; then
echo "Free plan file limit reached. Upgrade at https://getwebp.com/pricing"
exit 1
fiSee JSON Output for the complete schema and additional jq recipes.
Troubleshooting#
"Permission denied" when running the binary#
The downloaded binary needs execute permission:
chmod +x getwebpLicense activation fails in CI#
- Verify the
GETWEBP_LICENSE_KEYsecret is set and not empty. - Check that the key has available device slots at getwebp.com/dashboard.
- Activation requires outbound HTTPS access. Ensure the runner can reach
api.getwebp.com.
"Network error" (exit code 4)#
- The GetWebP API may be temporarily unavailable. Add a retry loop (see Retry on Network Errors).
- Check firewall rules on self-hosted runners: outbound HTTPS to
api.getwebp.commust be allowed.
JSON output is empty or malformed#
- Make sure you redirect stderr separately:
getwebp convert ./images --json > results.json 2>errors.log. - Warnings and progress messages go to stderr and should not be mixed with the JSON stream.
Free plan is too slow for CI#
The Free plan adds a 3-second delay per file and limits each run to 10 files. For CI pipelines, a Starter or Pro license removes these restrictions and enables parallel processing. See getwebp.com/pricing.