Manually converting images one by one works when you have five files. When you have five hundred, or when new images arrive every day, you need automation. The Morphix API turns image processing into a single HTTP call, which means any script, build tool, or CI/CD pipeline can handle it.
This guide shows you how to set up batch conversion, combine operations, and integrate image processing into your development workflow.
Why Automate Image Conversion?
Manual image processing does not scale. Here are the scenarios where automation pays for itself immediately:
E-commerce catalogs. A product catalog with 500 images needs each image in WebP, AVIF, and JPG, at three sizes (thumbnail, listing, full). That is 4,500 output files. Doing this by hand is not realistic.
Content publishing. A blog or news site that publishes daily needs every uploaded image converted to modern formats, resized for responsive breakpoints, and stripped of metadata. Manual processing creates a bottleneck and introduces inconsistency.
User-generated content. Any platform that accepts image uploads (marketplaces, forums, social apps) needs to normalize images: consistent format, consistent dimensions, metadata removed for privacy.
Build pipelines. Static sites, documentation sites, and web applications that include images in their build process benefit from automated conversion as a build step. Every new image is automatically optimized without developer intervention.
Setting Up Your Environment
You need two things: an API key and a tool that can make HTTP requests.
Get your API key from the Morphix dashboard. Store it in an environment variable:
export MORPHIX_API_KEY="your_key_here"
Choose your tool. The examples in this guide use cURL (for Bash scripts) and Python (for more complex workflows). Any language works, the API is a standard REST endpoint.
Test your setup with a single conversion:
curl -X POST https://morphix.tools/api/v1/convert \
-H "Authorization: Bearer $MORPHIX_API_KEY" \
-F "file=@test.jpg" \
-F "format=webp" \
-F "quality=80" \
--output test.webp
If you get a WebP file back, your setup is working.
Batch Convert a Folder of Images
The most common automation task is converting every image in a directory to a new format.
Bash script:
#!/bin/bash
INPUT_DIR="./images/originals"
OUTPUT_DIR="./images/webp"
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.{jpg,jpeg,png}; do
[ -f "$file" ] || continue
filename=$(basename "${file%.*}")
curl -s -X POST https://morphix.tools/api/v1/convert \
-H "Authorization: Bearer $MORPHIX_API_KEY" \
-F "file=@$file" \
-F "format=webp" \
-F "quality=80" \
--output "$OUTPUT_DIR/$filename.webp"
echo "Converted: $filename.webp"
done
Python script with error handling:
import os
import requests
from pathlib import Path
API_KEY = os.environ["MORPHIX_API_KEY"]
API_URL = "https://morphix.tools/api/v1/convert"
INPUT_DIR = Path("./images/originals")
OUTPUT_DIR = Path("./images/webp")
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
for image_path in INPUT_DIR.glob("*"):
if image_path.suffix.lower() not in (".jpg", ".jpeg", ".png"):
continue
with open(image_path, "rb") as f:
response = requests.post(
API_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
files={"file": f},
data={"format": "webp", "quality": 80},
)
if response.status_code == 200:
output_path = OUTPUT_DIR / f"{image_path.stem}.webp"
output_path.write_bytes(response.content)
print(f"OK: {image_path.name} -> {output_path.name}")
else:
print(f"FAIL: {image_path.name} ({response.status_code})")
Both scripts iterate over every JPG and PNG in the input directory, convert each to WebP at quality 80, and save the result in the output directory.
Resize and Convert in One Call
You can chain operations by making sequential API calls. A common workflow is to convert to WebP and then resize to multiple breakpoints:
import os
import requests
from pathlib import Path
API_KEY = os.environ["MORPHIX_API_KEY"]
BASE_URL = "https://morphix.tools/api/v1"
SIZES = [
{"width": 400, "height": 300, "suffix": "sm"},
{"width": 800, "height": 600, "suffix": "md"},
{"width": 1200, "height": 900, "suffix": "lg"},
]
def process_image(image_path, output_dir):
with open(image_path, "rb") as f:
webp_response = requests.post(
f"{BASE_URL}/convert",
headers={"Authorization": f"Bearer {API_KEY}"},
files={"file": f},
data={"format": "webp", "quality": 80},
)
if webp_response.status_code != 200:
print(f"Convert failed: {image_path.name}")
return
for size in SIZES:
resize_response = requests.post(
f"{BASE_URL}/resize",
headers={"Authorization": f"Bearer {API_KEY}"},
files={"file": ("image.webp", webp_response.content, "image/webp")},
data={"width": size["width"], "height": size["height"]},
)
if resize_response.status_code == 200:
name = f"{image_path.stem}-{size['suffix']}.webp"
(output_dir / name).write_bytes(resize_response.content)
print(f"OK: {name}")
This produces three WebP files per input image: small (400x300), medium (800x600), and large (1200x900).
Integrating with a Build Pipeline
For static sites and web applications, add image conversion as a build step that runs automatically on every deploy.
Makefile example:
.PHONY: images
images:
@echo "Converting images to WebP..."
@./scripts/convert-images.sh
@echo "Done."
build: images
npm run build
GitHub Actions example:
- name: Convert images to WebP
env:
MORPHIX_API_KEY: ${{ secrets.MORPHIX_API_KEY }}
run: |
for file in public/images/originals/*.{jpg,png}; do
[ -f "$file" ] || continue
filename=$(basename "${file%.*}")
curl -s -X POST https://morphix.tools/api/v1/convert \
-H "Authorization: Bearer $MORPHIX_API_KEY" \
-F "file=@$file" \
-F "format=webp" \
-F "quality=80" \
--output "public/images/webp/$filename.webp"
done
Store your API key as a repository secret, never in the code.
Monitoring and Error Handling
Production automation needs error handling. Here are the key patterns:
Retry on 429 (rate limit). Read the X-RateLimit-Reset header and wait before retrying:
import time
def api_call_with_retry(url, headers, files, data, max_retries=3):
for attempt in range(max_retries):
response = requests.post(url, headers=headers, files=files, data=data)
if response.status_code == 429:
reset_time = int(response.headers.get("X-RateLimit-Reset", 0))
wait = max(reset_time - int(time.time()), 1)
print(f"Rate limited. Waiting {wait}s...")
time.sleep(wait)
continue
return response
return response
Log failures. Track which images failed so you can reprocess them without reprocessing the entire batch.
Validate output. Check that the response status is 200 and the content type matches the expected format before saving the file.
Get Your API Key
Create your API key from the Morphix dashboard. No credit card required for the free plan.