---
title: Performance & caching
description: How Ultimate Watermark balances quality and speed — GD memory limits, the OTF cache, batch processing for large libraries, and CDN compatibility.
---
# Performance & caching
Watermarking is image processing — and image processing is heavy. This page explains how Ultimate Watermark manages memory, when it caches, and how to handle libraries with thousands of images.
## Memory & file limits
When GD is active, Ultimate Watermark raises memory before each watermark pass (`GDWatermarkProcessor.php:21`):
```
ini_set( 'memory_limit', '256M' );
```
It also limits to safe sizes (`GDWatermarkProcessor.php:26–32`):
| Limit | Value | What happens at the limit |
| --- | --- | --- |
| **Max image dimension** | 15 000 px per side | Larger images are skipped with a notice. |
| **Max file size** | 50 MB | Files above this size are skipped. |
For Imagick, no explicit limits — Imagick obeys your `policy.xml` and PHP `memory_limit`.
> If you're processing 8K photos or RAW exports, increase `memory_limit` to 512M and run the bulk apply during off-hours. Or use OTF (Pro) so the heavy lift only happens once per visitor request.
## The on-the-fly (OTF) cache PRO
When Pro's OTF display is enabled, watermarked output is **cached on disk** to avoid re-rendering on every page load.
### Cache location
```
wp-content/uploads/ultimate-watermark-frontend-cache/wm_.ext
```
(`FrontendWatermarkManager.php:28,407–418`).
The `` hash includes:
- The original file path.
- The watermark template ID.
- The original file's **mtime** — so when you replace an image on disk, the cache invalidates automatically.
- The watermark template's settings hash — so when you edit the watermark, all cached images regenerate on next access.
(`FrontendWatermarkManager.php:330–335`)
### Cache lifetime
There is **no TTL**. Files live forever; cache hits are by file existence (`FrontendWatermarkManager.php:337–338`).
### Clearing the cache
From the admin: **Watermark → Settings → Pro → Clear OTF cache** (or AJAX action `ulwm_pro_clear_frontend_cache` — `FrontendWatermarkManager.php:41,480–496`).
Or delete the folder manually:
```bash
rm -rf wp-content/uploads/ultimate-watermark-frontend-cache/
```
The next visitor regenerates each cached file on-demand.
## Background batch processing PRO
For libraries with thousands of images, processing them inline (during a bulk-action click) blocks the admin UI. Pro adds a background batch:
- A **`batch` post type** schedules work via `wp_schedule_single_event` (`BatchManager.php:76–78`).
- The batch handler (`BatchPostType.php:34`) processes a chunk on the next WP-Cron run.
- **Chunk size**: 10 images per pass (`BatchManager.php:110–112`).
- **WooCommerce batch size**: 5 products per pass (`EcommerceManager.php:335–339`).
- **Pro admin list batching**: 20 posts per page (`ProAdminManager.php:1266–1272,1311–1317`).
> If WP-Cron is broken, batches stall. See [Troubleshooting → WP-Cron](/troubleshooting#wp-cron-isnt-running) for fixing real-cron.
## Apply / un-apply existing media
The free media-library bulk action (`MediaLibraryIntegration.php:81–105`) processes selected items **synchronously**. For 50–100 items this is fine. For thousands, use Pro's batch.
| Volume | Best path |
| --- | --- |
| 1–100 | Free bulk action. |
| 100–1000 | Free bulk action in chunks of ~50, or Pro batch. |
| 1000+ | Pro batch (overnight). |
## CDN compatibility
If you serve images via a CDN (Cloudflare, BunnyCDN, KeyCDN):
- **Burned-in watermarks** (the default): the watermark is part of the file. CDNs cache the watermarked file once and serve it normally. ✅
- **OTF watermarks** (Pro): the watermarked file lives at `/wp-content/uploads/ultimate-watermark-frontend-cache/` — a regular path. CDNs cache it like any other static asset. ✅
> When you edit a watermark template, **purge** the CDN cache for the `ultimate-watermark-frontend-cache/` folder so visitors get the updated version.
## Responsive images
When Pro OTF is active, Ultimate Watermark **strips `srcset`** from `
` tags (`FrontendWatermarkManager.php:220–223,255–262`). The single OTF-rendered image is served instead.
Trade-off: simpler rendering, but visitors on small screens download the full resolution. To re-enable `srcset`, register your own `the_content` filter at a higher priority that re-injects the responsive markup after Ultimate Watermark runs.
## Image library choice
| Scenario | Recommendation |
| --- | --- |
| Mostly JPEG / PNG, modest sizes | GD is fine. |
| TIFF / BMP / SVG sources | Imagick required. |
| Very-large images (8K+) | Imagick + `policy.xml` tuning. |
| Shared hosting with low memory | GD + reduce max image size. |
The plugin auto-picks Imagick when available, GD otherwise (`LibraryDetector.php:47–60`).
## Tuning checklist
For larger sites, this order resolves 95 % of performance issues:
1. **Real cron**: switch from WP-Cron to system cron (see [Troubleshooting](/troubleshooting#wp-cron-isnt-running)).
2. **Disable** unused image subsizes in your theme — fewer subsizes = fewer watermark passes.
3. **Limit watermark to `full` + `large`** in the watermark's Rules → Image size.
4. **Use percentage offsets** so positions scale across subsizes.
5. **Increase PHP `memory_limit`** to 512M if you process > 4K images.
6. **Pro: enable OTF cache** so the heavy lift happens once per visitor session.
## Logs / activity
The plugin creates a database table `{$wpdb->prefix}ultimate_watermark_logs` (`Activator.php:46–56`), but the current build doesn't write to it (it's reserved for future). If you need an audit log, hook `ultimate_watermark_saved` (post-save) and write to your own table or an external log service.
## Where to go next
- 🖼️ [Watermarks](/watermarks) — per-template options.
- 🎯 [Conditional rules](/conditional-rules) — limit applications to fewer images.
- ⚙️ [Global settings](/settings) — backups, OTF cache toggle.
- 💎 [Pro features](/features) — full Pro module catalog.