Serve WebP to browsers that support it, without changing your URLs or HTML. The extension creates sibling files (photo.jpg.webp) next to every processed image; your webserver swaps them in transparently via Accept-header content negotiation. Browsers that don't support WebP receive the original format.
See CHANGELOG.md for release notes.
TYPO3 v14 introduced native WebP support via $GLOBALS['TYPO3_CONF_VARS']['GFX']['imageFileConversionFormats']. The core mechanism converts processed image output to WebP: the processed file's extension is .webp and the URL changes accordingly (photo.jpg → photo.webp).
This extension solves a different problem:
| Concern | This extension | TYPO3 v14 native |
|---|---|---|
| URL of served image | Unchanged (photo.jpg) |
Changed (photo.webp) |
| HTML / templates | Unchanged | Reference new URL |
| Fallback for non-WebP browsers | Transparent via webserver | Need <picture> or polyfill |
| Requires webserver rewrite rule | Yes | No |
| Works with cached HTML / CDN URLs | Yes | Cache invalidation needed |
Use the core mechanism when you can change URLs. Use this extension when you can't.
WebP is a modern image format that provides superior lossless and lossy compression for images on the web. WebP lossless images are 26% smaller in size compared to PNGs. WebP lossy images are 25–34% smaller than comparable JPEG images at equivalent SSIM quality index.
As of May 2026, WebP is supported by ~95.6% of users globally (caniuse.com/webp, per StatCounter data updated April 2026). The content-negotiation approach in this extension means even browsers without WebP support keep working — they just receive the original JPEG/PNG/GIF.
WebP was released by Google in 2010. It supports both lossy and lossless compression, transparency (an alpha channel at far lower overhead than PNG's), animation, and ICC color profiles. Smaller image payloads improve Core Web Vitals directly — Largest Contentful Paint (LCP) especially benefits when image bytes are reduced without changing rendered dimensions, and a 25–34% bandwidth reduction adds up on image-heavy pages and mobile connections.
| Extension version | TYPO3 | PHP | Status |
|---|---|---|---|
| 14.x | 12.4, 13.4, 14.x | 8.2, 8.3, 8.4 | Current |
| 13.x | 13.4 | 8.2, 8.3 | Legacy |
| 5.x | 12.4 | 8.1, 8.2 | Legacy |
A WebP-capable image converter. The extension supports three:
- ImageMagick or GraphicsMagick (whatever TYPO3 already uses for image manipulation), provided it was compiled with WebP support.
- An external binary such as
cwebp.
Verify your existing setup:
# GraphicsMagick — should return "yes"
gm version | grep WebP
# ImageMagick — should include "webp" in the list
convert -version | grep -i webpIf neither has WebP support, install cwebp and point the extension at it via the parameters configuration.
composer require plan2net/webpThen:
- Activate the extension if your TYPO3 is in non-Composer mode (Composer mode activates it automatically).
- Flush TYPO3 and PHP caches.
- Clear processed files (System → Maintenance → Remove Temporary Assets on TYPO3 v14; Admin Tools → Maintenance on v12/v13).
- Add the webserver rewrite rules.
After a composer update, save the extension settings at least once via the Extension Configuration backend module (System → Settings → Extension Configuration → webp on TYPO3 v14; Admin Tools → Settings → Extension Configuration → webp on v12/v13). TYPO3 only writes default values to LocalConfiguration when you save the settings form, so any new defaults the upgraded version ships won't take effect until you do.
| Setting | Default | Purpose |
|---|---|---|
parameters |
See below | Per-mime-type converter parameters |
mime_types |
image/jpeg,image/png,image/gif |
Source mime types to convert |
convert_all |
1 |
Convert all images, not just _processed_ |
silent |
1 |
Suppress converter stdout/stderr (Linux only) |
hide_webp |
1 |
Hide .webp files in the BE file list |
filter_pattern |
/\.(jpe?g|png|gif)\.webp$/i |
PCRE for which .webp to hide (only when hide_webp) |
exclude_directories |
(empty) | Skip processing for matching paths |
use_system_settings |
1 |
Reuse GFX color profile settings (MagickConverter) |
async |
0 |
Queue conversions for a scheduler worker instead of running them on the page-render path |
async_throttle_ms |
0 |
Random per-conversion sleep (ms) in the worker; 0 disables |
Each entry is mime/type::params, separated by |. The :: is significant — a single colon does not match the parser and silently falls through to the fallback branch.
Default (ImageMagick/GraphicsMagick):
parameters = image/jpeg::-quality 85 -define webp:lossless=false|image/png::-quality 75 -define webp:lossless=true|image/gif::-quality 85 -define webp:lossless=true
Per-mime-type breakdown:
| Mime type | Default parameters |
|---|---|
image/jpeg |
-quality 85 -define webp:lossless=false |
image/png |
-quality 75 -define webp:lossless=true |
image/gif |
-quality 85 -define webp:lossless=true |
Reference:
Warning
Try raising quality before reaching for webp:lossless=true; lossless can produce files larger than the original.
Supply a command string with exactly two %s placeholders for the source and target file:
image/jpeg::/usr/bin/cwebp -jpeg_like %s -o %s|image/png::/usr/bin/cwebp -lossless %s -o %s|image/gif::/usr/bin/gif2webp %s -o %s
See cwebp documentation.
# cat=basic; type=string; label=Supported mime types (comma separated)
mime_types = image/jpeg,image/png,image/gif
Only source files whose mime type is in this comma-separated list are considered for conversion.
# cat=basic; type=boolean; label=Convert all images in local and writable storage and save a copy in Webp format; disable to convert images in the _processed_ folder only
convert_all = 1
When enabled (default), every image in every local + writable storage is saved as a .webp sibling — not just images that TYPO3 has actually processed into _processed_/. To revert to processing-only behaviour, disable the checkbox.
Source-folder siblings are kept in sync with TYPO3's FAL operations: moving an image moves its .webp, deleting removes it, replacing drops the stale .webp so the next render produces a fresh one. When a storage has a recycler, the .webp follows the file into the recycler so restore keeps the pair intact. No configuration needed.
# cat=basic; type=boolean; label=Suppress output (stdout, stderr) from the external converter command
silent = 1
Suppress stdout/stderr from external converters. Linux only.
# cat=basic; type=boolean; label=Hide .webp files in backend file list module
hide_webp = 1
Hides .webp files in the backend file list module. The pattern controlling which .webp files are hidden is filter_pattern.
For a more customised behaviour (e.g. show siblings only to a specific BE group), override $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['defaultFilterCallbacks'] in your own extension — see ext_localconf.php for the registration this extension performs.
# cat=basic; type=string; label=Pattern to filter out files
filter_pattern = /\.(jpe?g|png|gif)\.webp$/i
PCRE pattern matched against the file identifier when hide_webp is enabled. The default matches the sibling-file naming this extension produces (e.g. photo.jpg.webp) without hiding standalone .webp files. Override if you use a custom naming scheme.
Invalid patterns are silently ignored (no files are hidden, no errors raised).
# cat=basic; type=string; label=Exclude processing of images from specific directories (separated by semicolon)
exclude_directories =
Skip processing for images under any of the listed paths (semicolon-separated).
Example: /fileadmin/demo/special;/another-storage/demo/exclusive
# cat=basic; type=boolean; label=Use the system GFX "processor_stripColorProfileCommand"/"processor_stripColorProfileParameters" setting for the MagickConverter converter
use_system_settings = 1
Applies only to MagickConverter. When enabled, the value of $GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_stripColorProfileCommand'] and processor_stripColorProfileParameters is appended to converter arguments automatically — no need to repeat the setting per mime type.
PhpGdConverter and external-binary configurations ignore this flag.
# cat=async; type=boolean; label=Enable asynchronous conversion
async = 0
When enabled, the AfterFileProcessing listener writes a row to tx_webp_queue instead of running the converter inside the request. Conversions then happen out-of-band via the webp:process-queue CLI command, typically registered as a TYPO3 Scheduler task. See Async mode below for setup.
When disabled (default), conversions run synchronously exactly as before.
# cat=async; type=int+; label=Random sleep (ms) between conversions
async_throttle_ms = 0
Pause for a random interval between conversions inside the worker. Value 0 means no pause. Value N > 0 means each pause is random(N/2, N*3/2) milliseconds — modeled on wget --random-wait to avoid lock-step bursts. Useful on tight-CPU servers when a batch of conversions would otherwise saturate the box. Applies to both queue mode and --folder mode.
By default the extension converts images synchronously inside the request that processes the source file. On image-heavy pages or large-fileadmin sites this adds latency to every render. Enabling async = 1 moves the conversion off the render path:
- Set
async = 1in the extension configuration. - Run TYPO3's database analyzer so
tx_webp_queueis created. - Register a TYPO3 Scheduler task: System → Scheduler → Add task → Type: "Process conversion queue (webp)". Pick a frequency that matches your throughput (every minute for busy sites, hourly for low-traffic).
- Make sure the scheduler itself runs — either via
vendor/bin/typo3 scheduler:runin cron, or a daemonized runner.
The listener will now enqueue new conversions; the scheduler task drains the queue in the background. Existing siblings stay; the extension does not retroactively backfill.
Some image folders (notably typo3temp/assets/online_media/ for YouTube/Vimeo preview thumbnails) live outside TYPO3's File Abstraction Layer, so the listener never sees them. The --folder argument bypasses the queue and converts files directly:
vendor/bin/typo3 webp:process-queue --folder=typo3temp/assets/online_media/Register this as a second Scheduler task ("Execute console command") if you want it to run periodically. Paths resolve relative to the public web root and are restricted to it for safety.
The webserver inspects the client's Accept header and rewrites the request to the .webp sibling when both are true:
- the client advertised
image/webpsupport - the sibling exists on disk
Below are examples for nginx and Apache. Adapt them to your stack — these aren't drop-in copies.
Important
Make sure no earlier rule in your config short-circuits the request for the image extensions you target (e.g. a generic static-asset block). If so, move the WebP rules above it or rework the earlier rule.
Add a map directive in the http block:
map $http_accept $webp_suffix {
default "";
"~*webp" ".webp";
}If you front the site with Cloudflare, prefer this variant — Cloudflare caches per response and would otherwise mix WebP and non-WebP variants:
map $http_accept $webpok {
default 0;
"~*webp" 1;
}
map $http_cf_cache_status $iscf {
default 1;
"" 0;
}
map $webpok$iscf $webp_suffix {
11 "";
10 ".webp";
01 "";
00 "";
}Add the location block to your server:
location ~* ^.+\.(png|gif|jpe?g)$ {
add_header Vary "Accept";
add_header Cache-Control "public, no-transform";
try_files $uri$webp_suffix $uri =404;
}location ~* ^.+\.(png|gif|jpe?g)$ {
if ($http_user_agent !~* (Chrome|Firefox|Edge)) {
set $webp_suffix "";
}
…
}The first two directives are already part of TYPO3's default .htaccess template (typo3/sysext/install/Resources/Private/FolderStructureTemplateFiles/root-htaccess); they're shown here for completeness. We assume mod_rewrite.c is enabled.
RewriteEngine On
AddType image/webp .webp
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_FILENAME} (.*)\.(?i:png|gif|jpe?g)$
RewriteCond %{REQUEST_FILENAME}\.webp -f
RewriteRule ^ %{REQUEST_FILENAME}\.webp [L,T=image/webp]
<IfModule mod_headers.c>
<FilesMatch "\.(png|gif|jpe?g)$">
Header append Vary Accept
</FilesMatch>
</IfModule>Some environments — shared hosting (IONOS etc.), Windows Apache, or setups where the rewrite runs before path resolution — return 403/404 with the %{REQUEST_FILENAME} form because Apache can't map the request to a filesystem path at that stage. Two portable alternatives:
RewriteRule ^ %{REQUEST_URI}.webp [L,T=image/webp]or:
RewriteRule ^(.*)$ $1.webp [L,T=image/webp]Substitute either for the RewriteRule ^ %{REQUEST_FILENAME}\.webp … line above.
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{HTTP_USER_AGENT} ^.*(Chrome|Firefox|Edge).*$ [NC]
…Two things to check: that WebP files are actually generated, and that the webserver serves them when the client supports it.
Browse to fileadmin/_processed_ and look for .webp siblings:
csm_foo-bar_4f3d6bb7d0.jpg
csm_foo-bar_4f3d6bb7d0.jpg.webp
With convert_all = 1, you'll also find .webp siblings next to originals in fileadmin/ itself.
Request a JPEG/PNG with an Accept: image/webp header:
curl -H "Accept: image/webp" -I https://example.tld/fileadmin/_processed_/b/2/csm_foo-bar_4f3d6bb7d0.jpg
# expect: Content-Type: image/webpOr open the URL in a browser and check the response headers in the developer tools — despite the .jpg suffix the Content-Type should be image/webp:
Every conversion problem is logged to TYPO3's log (var/log/typo3_*.log by default). Start there.
Common cases:
| Symptom | Likely cause |
|---|---|
No .webp files appear in _processed_/ |
Converter binary lacks WebP support, or mime_types excludes the source |
| Files are bigger than the original | Automatically removed and not retried with the same configuration |
| WebP renders darker / off-colour | $GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_colorspace'] (e.g. sRGB) |
| Apache rewrite returns 403/404 | %{REQUEST_FILENAME} doesn't resolve |
| File still served as JPEG after a successful generation | Webserver rewrite rule missing or shadowed by another rule |
| Sibling left behind after deleting the source | None — that's the bug fixed in 14.0.0; upgrade |
After changing processor_colorspace, clean up any processed files via the Maintenance backend module (System → Maintenance → Remove Temporary Assets on TYPO3 v14; Admin Tools → Maintenance on v12/v13) so the change takes effect on existing images.
- Animated GIFs. The bundled converters produce single-frame WebP output, so a served
.gif.webpis a still image. If you need animations to keep playing, removeimage/giffrommime_typesand thegifgroup from your webserver's rewrite rule. - ImageMagick / GraphicsMagick must be compiled with WebP support. See Requirements.
- Cross-storage FAL moves are not handled. If you move a file between two different storages, the sibling at the source storage is left orphaned. Lazy regeneration handles the target storage on next render. Single-storage moves work correctly.
use_system_settingsonly applies toMagickConverter.PhpGdConverterand external-binary configurations ignore it.
To remove all generated .webp files (e.g. before a converter or quality change):
- System → Maintenance → Remove Temporary Assets (TYPO3 v14) or Admin Tools → Maintenance → Remove Temporary Assets (v12/v13).
- Click Scan temporary files.
- Click the button labelled with the storage path.
The button label only mentions _processed_/, but all processed files in the storage are removed.
The next page render will regenerate .webp siblings using the current configuration.
- Extra CPU. Every processed image is reprocessed for the
.webpsibling. The work happens once per image (results are cached on disk) but adds latency to first-time renders. - Extra disk. WebP siblings are typically 65–75% of the source file size (Google's reference numbers: WebP lossy is 25–34% smaller than JPEG; lossless is 26% smaller than PNG). With
convert_all = 1enabled this applies to every source image, not just processed variants.
- TYPO3 v14 native WebP — see the comparison above. Best fit when you can change URLs.
- Apache
mod_pagespeed/ nginxngx_pagespeed— Google's automatic image-rewriting modules. Equal end-result withpagespeed EnableFilters convert_jpeg_to_webp;plusconvert_to_webp_lossless;, but more involved to set up and operate. - Cloudflare Polish or similar CDN-level image optimisation.
composer install
.Build/bin/phpunit -c phpunit.xml # unit tests
typo3DatabaseDriver=pdo_sqlite \
.Build/bin/phpunit -c phpunit-functional.xml # functional tests
.Build/bin/php-cs-fixer fix --config=php-cs-fixer.config.php --dry-runCI runs the full PHP × TYPO3 matrix on every push and pull request — see .github/workflows/tests.yml.
Inspired by Angela Dudtkowski's cs_webp extension. Thanks Angela.
Thanks to Xavier Perseguers for the Cloudflare hint and to Marcus Förster for simplifying the Apache rewrite rules.
GPL-3.0-or-later — see LICENSE.
Send us a postcard from your favourite place and tell us how much you love TYPO3 and OpenSource:
plan2net GmbH Sieveringerstraße 37 1190 Vienna, Austria

