How to Use a Watermark Remover API with Python (2026)
Python's rich ecosystem makes it an excellent choice for image processing automation. This guide shows how to integrate a watermark removal API with Python — from a simple synchronous script to an async bulk processor, plus web framework integration examples.
Prerequisites
pip install requests python-dotenv httpx
# .env
WATERMARK_API_KEY=your_api_key_here
WATERMARK_API_URL=https://api.provider.com/v1/images/remove-watermark
Basic Single Image Removal (synchronous)
import os
import requests
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
def remove_watermark(input_path: str, output_path: str) -> None:
"""Remove watermark from a single image via API."""
with open(input_path, 'rb') as f:
response = requests.post(
os.environ['WATERMARK_API_URL'],
headers={'Authorization': f"Bearer {os.environ['WATERMARK_API_KEY']}"},
files={'image': (Path(input_path).name, f, 'image/jpeg')},
data={'output_format': 'png'},
timeout=30
)
response.raise_for_status()
with open(output_path, 'wb') as out:
out.write(response.content)
print(f'✅ Saved: {output_path}')
remove_watermark('input.jpg', 'output.png')
Async Bulk Processing with httpx
import asyncio
import httpx
from pathlib import Path
async def remove_watermark_async(
client: httpx.AsyncClient,
input_path: Path,
output_dir: Path,
semaphore: asyncio.Semaphore
) -> None:
async with semaphore:
with open(input_path, 'rb') as f:
response = await client.post(
os.environ['WATERMARK_API_URL'],
headers={'Authorization': f"Bearer {os.environ['WATERMARK_API_KEY']}"},
files={'image': (input_path.name, f, 'image/jpeg')},
data={'output_format': 'png'},
timeout=30.0
)
response.raise_for_status()
output_path = output_dir / input_path.with_suffix('.png').name
output_path.write_bytes(response.content)
print(f'✅ {input_path.name}')
async def process_batch(input_dir: str, output_dir: str) -> None:
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
images = list(input_path.glob('*.jpg')) + list(input_path.glob('*.png'))
semaphore = asyncio.Semaphore(5) # max 5 concurrent requests
async with httpx.AsyncClient() as client:
tasks = [
remove_watermark_async(client, img, output_path, semaphore)
for img in images
]
results = await asyncio.gather(*tasks, return_exceptions=True)
successes = sum(1 for r in results if not isinstance(r, Exception))
failures = sum(1 for r in results if isinstance(r, Exception))
print(f'
Done. Succeeded: {successes}, Failed: {failures}')
asyncio.run(process_batch('./watermarked', './cleaned'))
Retry Logic with Tenacity
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception
@retry(
stop=stop_after_attempt(4),
wait=wait_exponential(multiplier=1, min=1, max=16),
retry=retry_if_exception(lambda e: '429' in str(e))
)
def remove_watermark_with_retry(input_path, output_path):
return remove_watermark(input_path, output_path)
FastAPI Integration
from fastapi import FastAPI, UploadFile, HTTPException
from fastapi.responses import Response
import httpx
app = FastAPI()
@app.post('/remove-watermark')
async def api_remove_watermark(file: UploadFile) -> Response:
content = await file.read()
async with httpx.AsyncClient(timeout=30.0) as client:
resp = await client.post(
os.environ['WATERMARK_API_URL'],
headers={'Authorization': f"Bearer {os.environ['WATERMARK_API_KEY']}"},
files={'image': (file.filename, content, file.content_type)},
data={'output_format': 'png'}
)
if not resp.is_success:
raise HTTPException(status_code=resp.status_code, detail='Watermark removal failed')
return Response(content=resp.content, media_type='image/png')
Conclusion
Python's requests and httpx libraries make watermark API integration clean and idiomatic. Use httpx with asyncio for bulk jobs to maximize throughput within API rate limits. Add tenacity for production-grade retry handling. For user-facing tools, consider recommending AI Watermark Remover to avoid API costs and privacy concerns entirely.