# Bulk Image Watermark, Resize & Convert to WebP/AVIF (`fast_data_asap/bulk-image-watermark-resize`) Actor

Bulk watermark, resize and convert product images: text or logo watermark (9 positions or tiled), Amazon/Shopify/Instagram/OG presets, pad or crop, WebP, AVIF, JPG, PNG, metadata stripped. URLs or Google Sheet in, download links out.

- **URL**: https://apify.com/fast_data_asap/bulk-image-watermark-resize.md
- **Developed by:** [Fast Data](https://apify.com/fast_data_asap) (community)
- **Categories:** E-commerce, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 processed images

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Bulk Image Watermark, Resize & Convert (WebP / AVIF / JPG / PNG)

Watermark, resize and convert **hundreds of product and marketing images in one run**. Paste image URLs (or link a Google Sheet), choose a **text or logo watermark**, a **size preset** (Amazon, Shopify, Instagram, Open Graph, square 1000/2000 or custom) and an **output format** (WebP, AVIF, JPG, PNG). You get one row per image with a **public download link**, the new size in pixels and bytes, and how much smaller the file got.

**$2 per 1,000 images ($0.002 each). Failed downloads and unsupported files are free.**

#### What it does

- 🏷️ **Watermark**: your text (font size, color, opacity 0–1, auto-outline for readability) or your **logo PNG** (scaled to a % of the image width), in **9 positions** (top/center/bottom × left/center/right) or **tiled** diagonally over the whole image, with a margin in pixels
- 📐 **Resize presets**: `square-1000`, `square-2000`, `amazon-2000` (forced pure-white background), `shopify-2048`, `instagram-1080`, `og-1200x630`, or `custom` width × height
- ✂️ **Fit modes**: **pad** (whole product visible, fill with a background color or transparent – the marketplace standard), **cover** (fill and crop), **contain** (fit inside, no padding). Optional enlarging of small images
- 🔄 **Convert** to **WebP**, **AVIF**, **JPG** or **PNG** with a quality setting; transparent images are flattened onto your background color for JPG
- 🧹 **Strip metadata** (EXIF, XMP, GPS location, camera data) by default; the color profile is kept so colors stay correct; EXIF rotation is applied to the pixels
- 📄 **Google-Sheets-friendly input**: a list of `{url, name}` objects or a shared Google Sheet / CSV link with `url` and `name` (or `sku`) columns – the name becomes the file name, e.g. `SKU-1001.webp`
- 📦 Results are stored in the run's key-value store with a public URL per image, ready for Shopify/WooCommerce imports, Google Merchant feeds or your CDN

**Who it's for:** e-commerce sellers preparing product images for Amazon, Shopify, WooCommerce, eBay or Etsy; marketing teams branding social and blog images; agencies and photographers protecting previews with a watermark; developers who need image processing in an n8n/Make/Zapier or AI-agent workflow without running their own server.

**Why this actor:** comparable image actors in the Apify Store charge $5–$15 per 1,000 images and usually do only one thing (convert *or* resize *or* watermark). This one does all three in a single pass for **$2 per 1,000**, supports AVIF, takes a Google Sheet as input, and never charges for images that fail.

### Input

| Field | Default | Description |
|---|---|---|
| `imageUrls` | 2 sample images | Direct links to JPG, PNG, WebP, AVIF, GIF (first frame), TIFF or BMP images |
| `images` | – | Optional `[{"url": "...", "name": "SKU-1001"}]`; `name` becomes the file name |
| `sheetCsvUrl` | – | Google Sheet shared as "Anyone with the link can view" (normal link is fine) or any CSV URL, with a `url` column and optional `name`/`sku` column |
| `watermarkType` | `text` | `text`, `logo` or `none` |
| `text` | `© YourBrand.com` | Watermark text (`\n` for a second line) |
| `logoUrl` | – | Logo image URL (PNG with transparency recommended) |
| `position` | `bottom-right` | `top-left`, `top-center`, `top-right`, `center-left`, `center`, `center-right`, `bottom-left`, `bottom-center`, `bottom-right`, `tile` |
| `opacity` | `0.6` | 0–1 |
| `fontSize` | `0` (auto) | Text size in output pixels; auto ≈ 4.5 % of the image size |
| `textColor` | `#FFFFFF` | Hex or color name |
| `margin` | `24` | Distance to the edge in pixels |
| `logoScale` | `20` | Logo width in % of the image width |
| `resizePreset` | `square-1000` | `none`, `square-1000`, `square-2000`, `amazon-2000`, `shopify-2048`, `instagram-1080`, `og-1200x630`, `custom` |
| `width` / `height` | – | For `custom`; one side alone keeps the aspect ratio |
| `fit` | `pad` | `pad`, `cover` or `contain` |
| `backgroundColor` | `#FFFFFF` | Padding color, or `transparent` (WebP/AVIF/PNG) |
| `upscale` | `true` | Enlarge images smaller than the target size |
| `outputFormat` | `webp` | `webp`, `avif`, `jpg`, `png` |
| `quality` | `82` | 1–100 for WebP/AVIF/JPG (WebP 100 = lossless) |
| `stripMetadata` | `true` | Remove EXIF/XMP/GPS |
| `outputPrefix` | – | Prefix for every file name, e.g. `summer-sale` |
| `maxFileSizeMb` | `25` | Larger source files are skipped (free) |

Example – logo watermark, Amazon size, JPG, names from your SKU list:

```json
{
  "images": [
    { "url": "https://example.com/photos/IMG_4711.jpg", "name": "SKU-1001" },
    { "url": "https://example.com/photos/IMG_4712.png", "name": "SKU-1002" }
  ],
  "watermarkType": "logo",
  "logoUrl": "https://example.com/logo.png",
  "position": "bottom-right",
  "opacity": 0.5,
  "logoScale": 15,
  "resizePreset": "amazon-2000",
  "fit": "pad",
  "outputFormat": "jpg",
  "quality": 85
}
```

### Output

One dataset row per image. Real example from a test run with the default input (text watermark, `square-1000`, WebP):

```json
{
  "sourceUrl": "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/fruits.jpg",
  "name": null,
  "fileName": "fruits.webp",
  "url": "https://api.apify.com/v2/key-value-stores/8mF0CqzHxkmNpT8ly/records/fruits.webp?signature=hiRt3ovVTOzujq7Jd8Qy",
  "width": 1000,
  "height": 1000,
  "format": "webp",
  "sizeBytes": 75810,
  "originalSizeBytes": 82429,
  "savedPercent": 8,
  "originalWidth": 512,
  "originalHeight": 480,
  "originalFormat": "jpg",
  "status": "ok",
  "error": null
}
```

A failed image looks like this (not charged):

```json
{ "sourceUrl": "https://example.com/missing.jpg", "fileName": null, "url": null, "status": "error", "error": "HTTP 404 when downloading (image not found)" }
```

| Field | Meaning |
|---|---|
| `url` | Public link to the processed image (works without an Apify token) |
| `fileName` | Key in the run's default key-value store |
| `width`, `height`, `format` | Output image |
| `sizeBytes`, `originalSizeBytes`, `savedPercent` | File size before/after; negative when small images were enlarged |
| `status` | `ok` (charged) or `error` (free) with the reason in `error` |

The dataset's **Overview** view shows a preview thumbnail of every processed image. All files are also listed under the run's key-value store.

### Pricing

Pay per event: **$0.002 per successfully processed image** ($2 per 1,000), plus the small Apify platform start fee. Failed downloads, non-image URLs and files over the size limit cost nothing. Set a maximum cost per run in the run options and the actor stops cleanly when it is reached. 512 MB–1 GB of memory is enough; images up to 80 megapixels are supported.

### Use via API, n8n, Make or AI agents

**API** (synchronous, returns the dataset rows):

```bash
curl -X POST "https://api.apify.com/v2/acts/fast_data_asap~bulk-image-watermark-resize/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"imageUrls":["https://example.com/product.jpg"],"watermarkType":"text","text":"© MyShop","resizePreset":"square-2000","outputFormat":"webp"}'
```

**Python:**

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("fast_data_asap/bulk-image-watermark-resize").call(run_input={
    "sheetCsvUrl": "https://docs.google.com/spreadsheets/d/<your-sheet-id>/edit",
    "watermarkType": "text", "text": "© MyShop", "position": "tile", "opacity": 0.25,
    "resizePreset": "shopify-2048", "outputFormat": "avif",
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["status"], row["fileName"], row["url"])
```

**n8n / Make / Zapier:** use the Apify node/app, action "Run actor", actor `fast_data_asap/bulk-image-watermark-resize`, then map `url` from the dataset items into your shop, CMS or cloud storage.

**MCP (Claude, Cursor, other AI agents):** add `https://mcp.apify.com?tools=fast_data_asap/bulk-image-watermark-resize` as an MCP server and let your agent prepare product images on demand.

### FAQ

**Does AVIF work?** Yes, AVIF encoding is built in (Pillow with libavif). AVIF files are typically 20–50 % smaller than WebP at similar quality but take a bit longer to encode.

**Can I use Google Drive or Dropbox images?** Yes, if the link downloads the file itself (a direct/raw link), not an HTML preview page.

**Will my Google Sheet work?** Share it as "Anyone with the link can view" and paste the normal link; the actor reads it as CSV. Columns named `url` (or `image`, `link`) and `name` (or `sku`, `filename`) are detected automatically.

**How long are the files kept?** Like every Apify run storage: according to your plan's data retention (unnamed storages are typically kept 7 days). Download or copy them to your own storage for permanent use.

**Are my images stored anywhere else?** No. Images are only downloaded into the run's container and saved to your own run's key-value store.

# Actor input Schema

## `imageUrls` (type: `array`):

Direct links to JPG, PNG, WebP, AVIF, GIF, TIFF or BMP images. The output file is named after the URL's file name.

## `images` (type: `array`):

Optional list of {"url": "...", "name": "SKU-123"} objects, e.g. pasted from a spreadsheet. "name" becomes the output file name.

## `sheetCsvUrl` (type: `string`):

A Google Sheet shared as 'Anyone with the link can view' (or any CSV URL) with a 'url' column and an optional 'name' column (also accepted: image, link, sku, filename). Every row is processed.

## `watermarkType` (type: `string`):

Stamp a text or your logo onto every image, or no watermark.

## `text` (type: `string`):

Used when Watermark = Text, e.g. © YourBrand.com. Use \n for a second line.

## `logoUrl` (type: `string`):

Used when Watermark = Logo. Direct link to a PNG with transparent background (WebP/JPG also work).

## `position` (type: `string`):

Where the watermark goes. Tiled repeats it diagonally over the whole image (best protection against image theft).

## `opacity` (type: `number`):

0.1 = barely visible, 1 = fully opaque.

## `fontSize` (type: `integer`):

Text size in output pixels. 0 = automatic (about 4.5% of the image size).

## `textColor` (type: `string`):

Hex code or color name, e.g. #FFFFFF, black, #FF6600. A thin contrasting outline keeps it readable on any background.

## `margin` (type: `integer`):

Distance between the watermark and the image edge, in output pixels.

## `logoScale` (type: `number`):

Logo is scaled to this share of the image width.

## `resizePreset` (type: `string`):

Target size. Fit decides how images with a different aspect ratio are handled.

## `width` (type: `integer`):

Used with preset Custom. Leave one side empty to keep the aspect ratio.

## `height` (type: `integer`):

Used with preset Custom.

## `fit` (type: `string`):

How images with a different aspect ratio fit the target size. Pad keeps the whole product visible (marketplace standard).

## `backgroundColor` (type: `string`):

Padding color, e.g. #FFFFFF or transparent (transparent works with WebP, AVIF and PNG).

## `upscale` (type: `boolean`):

Scale images smaller than the target size up to it. Off = small images keep their size (padded/centered when Fit = Pad).

## `outputFormat` (type: `string`):

WebP is the best default for shops and websites; AVIF is 20–50% smaller still; JPG for marketplaces that need it (Amazon, eBay).

## `quality` (type: `integer`):

For WebP, AVIF and JPG. 75–85 is visually lossless for product photos. WebP 100 = lossless.

## `stripMetadata` (type: `boolean`):

Removes EXIF/XMP incl. GPS location. The color profile is kept so colors stay correct.

## `outputPrefix` (type: `string`):

Optional prefix for every output file name, e.g. summer-sale → summer-sale-fruits.webp.

## `maxFileSizeMb` (type: `integer`):

Larger source images are skipped with status error (free).

## Actor input object example

```json
{
  "imageUrls": [
    "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/fruits.jpg",
    "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/baboon.jpg"
  ],
  "images": [
    {
      "url": "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/fruits.jpg",
      "name": "SKU-1001-fruits"
    }
  ],
  "watermarkType": "text",
  "text": "© YourBrand.com",
  "position": "bottom-right",
  "opacity": 0.6,
  "fontSize": 0,
  "textColor": "#FFFFFF",
  "margin": 24,
  "logoScale": 20,
  "resizePreset": "square-1000",
  "fit": "pad",
  "backgroundColor": "#FFFFFF",
  "upscale": true,
  "outputFormat": "webp",
  "quality": 82,
  "stripMetadata": true,
  "maxFileSizeMb": 25
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `files` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "imageUrls": [
        "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/fruits.jpg",
        "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/baboon.jpg"
    ],
    "watermarkType": "text",
    "text": "© YourBrand.com",
    "resizePreset": "square-1000",
    "outputFormat": "webp"
};

// Run the Actor and wait for it to finish
const run = await client.actor("fast_data_asap/bulk-image-watermark-resize").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "imageUrls": [
        "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/fruits.jpg",
        "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/baboon.jpg",
    ],
    "watermarkType": "text",
    "text": "© YourBrand.com",
    "resizePreset": "square-1000",
    "outputFormat": "webp",
}

# Run the Actor and wait for it to finish
run = client.actor("fast_data_asap/bulk-image-watermark-resize").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "imageUrls": [
    "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/fruits.jpg",
    "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/baboon.jpg"
  ],
  "watermarkType": "text",
  "text": "© YourBrand.com",
  "resizePreset": "square-1000",
  "outputFormat": "webp"
}' |
apify call fast_data_asap/bulk-image-watermark-resize --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fast_data_asap/bulk-image-watermark-resize"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/FiTVDhULLHraHlrxm/builds/UJxUQuHwkPYsdioCK/openapi.json
