Gemini Watermark Remover API

Send an image, get the cleaned image back — the same pipeline as the web app: it finds the Gemini mark, reverses it losslessly with the alpha map when it can, and falls back to LaMa inpainting only where needed.

Endpoint

POST /api/v1/remove

Send the image as multipart/form-data (field image), as JSON {"image": "<base64 or data URL>"}, or as the raw bytes with Content-Type: image/png / image/jpeg. Options go in the form fields, the JSON body, or the query string. PNG and JPEG, up to 15 MB and 12 megapixels.

Auth: when the server has API_KEYS configured, send X-API-Key: KEY or Authorization: Bearer KEY. CORS is open, so browsers can call it directly — keep keys out of public front-end code.

Examples

curl

curl -X POST "https://app.gemini-logo-remover.workers.dev/api/v1/remove" \
  -H "X-API-Key: YOUR_KEY" \
  -F "image=@gemini-image.png" \
  -o clean.png

JavaScript

const form = new FormData();
form.append("image", file); // File / Blob (PNG or JPEG)

const res = await fetch("https://app.gemini-logo-remover.workers.dev/api/v1/remove", {
  method: "POST",
  headers: { "X-API-Key": "YOUR_KEY" },
  body: form,
});
if (!res.ok) throw new Error((await res.json()).error.message);

const cleanBlob = await res.blob();
console.log(res.headers.get("X-Removal-Method")); // alpha | inpaint | alpha+inpaint | none

Python

import requests

r = requests.post(
    "https://app.gemini-logo-remover.workers.dev/api/v1/remove",
    headers={"X-API-Key": "YOUR_KEY"},
    files={"image": open("gemini-image.png", "rb")},
    timeout=120,
)
r.raise_for_status()
open("clean.png", "wb").write(r.content)
print(r.headers["X-Removal-Method"], r.headers.get("X-Clean"))

Options

NameDefaultMeaning
modeautoauto = find each mark, fit its strength, reverse it losslessly (text under it comes back), check what is left, and inpaint ONLY a leftover or a mark that no scaled alpha overlay explains. alpha = lossless only, never calls the inpaint service (unchanged image + a warning if a mark cannot be reversed). inpaint = skip alpha and inpaint the found slot.
responseimageimage returns the cleaned file; json returns base64 plus a detailed report.
formatpngpng, jpeg, or auto (same as the input).
quality921–100. JPEG output only.
sparklefalseAlso inpaint the small V3 sparkle slot. It cannot be verified, so it is off by default; turning it on can damage text near the corner.
feather120–16 px edge blend for inpainted areas.
full_size—WxH. Send only the bottom-right crop (min(W,480) x min(H,480) px) of a WxH image; the response is the cleaned crop. Used by the Colab notebook.
region—x,y,width,height in pixels. Skips detection and inpaints exactly this box.

Response

By default the body is the cleaned image, with these headers: X-Watermark-Detected, X-Watermark-Slot, X-Detection-Confidence, X-Removal-Method (alpha, inpaint, alpha+inpaint or none), X-Clean, X-Image-Width, X-Image-Height and, if something degraded, X-Warnings. With response=json:

{
  "ok": true,
  "image": { "mimeType": "image/png", "format": "png", "width": 1536, "height": 1536, "base64": "iVBORw0..." },
  "result": {
    "detected": true,
    "slot": "v1",
    "confidence": 0.968,
    "method": "alpha",
    "clean": true,
    "passes": [{ "method": "alpha", "reason": "Reverse alpha blend at V1 legacy", "region": { "x": 1376, "y": 1376, "width": 96, "height": 96 } }],
    "warnings": []
  }
}

Errors

Errors are JSON: {"ok": false, "error": {"code": "...", "message": "..."}}

  • 400 Missing/invalid image or option
  • 401 Missing or invalid API key (only when the server has API_KEYS set)
  • 413 Upload over 15 MB, or image over 12 megapixels
  • 415 Not a PNG or JPEG
  • 422 File could not be decoded
  • 502 The inpaint service failed — retry, or use mode=alpha