webflow/webflow-mcp:compress-cms-image
Compress and convert CMS item image fields to webp or avif in a Webflow collection. Prompts for collection ID, item ID, image fields, quality, and target format, then downloads, converts, re-uploads via presigned S3, and publishes the updated item.
npx skills add https://github.com/webflow/webflow-skills --skill webflow-mcp:compress-cms-image
Compress and reformat image fields on a Webflow CMS item to .webp or .avif.
This skill does not support images embedded inside Rich Text fields at this time. Tell the user that limitation before starting and only process CMS fields whose schema type is Image or MultiImage.
ALWAYS use Webflow MCP tools for Webflow operations:
data_sites_tool with action list_sites to discover the site ID when neededdata_cms_tool with action get_collection_details to fetch collection schemasdata_cms_tool with action list_collection_items to fetch the target CMS itemdata_assets_tool with action create_asset to create presigned asset uploadsdata_cms_tool with action update_collection_items to update CMS image fieldsdata_cms_tool with action publish_collection_items to publish the updated itemcontext parameter (15-25 words, third-person perspective)confirm before uploading assets, updating CMS fields, or publishing.Collect all required inputs in one shot when possible:
If the user chose "Specify field names", follow up for comma-separated field slugs. If the user chose "Custom" quality, follow up for the numeric value. Validate custom quality is an integer from 1 to 100.
data_cms_tool with action get_collection_details and the collection ID.type === "Image" or type === "MultiImage".Call data_cms_tool with action list_collection_items to fetch the target item. Use the item ID to identify the item directly when the tool supports it; otherwise filter or search the returned items.
Extract current fieldData for each target field:
url and fileId.url and fileId.Before downloading or uploading anything, show a preview:
Compression Preview
Collection: [collection ID]
Item: [item ID]
Target format: webp
Quality: 85
Fields to process:
- main-image: hero.jpg -> hero.webp
- gallery: 3 images -> webp
Skipped:
- thumbnail: already webp
Type `confirm` to download, convert, upload, update the CMS item, and publish.
Proceed only after the user types confirm.
For each image:
/tmp/:curl -sL "{url}" -o "/tmp/cms_img_{fieldSlug}_{index}.orig"
python3 -c "from PIL import Image" 2>/dev/null || pip3 install Pillow -q
For avif, also try:
pip3 install pillow-avif-plugin -q
python3 - <<'EOF'
from PIL import Image
import os
try:
import pillow_avif
except ImportError:
pass
source = "/tmp/cms_img_{fieldSlug}_{index}.orig"
target = "/tmp/cms_img_{fieldSlug}_{index}.{ext}"
img = Image.open(source)
img.save(target, "{FORMAT}", quality={quality})
orig = os.path.getsize(source)
new = os.path.getsize(target)
print(f"Original: {orig:,} bytes -> {FORMAT}: {new:,} bytes ({(1 - new / orig) * 100:.1f}% smaller)")
EOF
If avif conversion fails, report the error and ask whether to fall back to webp or abort.
md5 -q "/tmp/cms_img_{fieldSlug}_{index}.{ext}"
On Linux:
md5sum "/tmp/cms_img_{fieldSlug}_{index}.{ext}" | cut -d' ' -f1
For each converted file:
site_id. If it is not known from the collection or prior context, call data_sites_tool with action list_sites. If multiple sites are available, ask the user which one owns the collection.data_assets_tool with action create_asset:site_id: the target site IDfile_name: original base name plus the new extension, such as hero.webpfile_hash: the MD5 hex stringuploadUrl: S3 endpointuploadDetails: form fieldsid: new asset IDhostedUrl: CDN URL to use as the CMS source referenceuploadDetails keys to curl fields:xAmzAlgorithm -> X-Amz-AlgorithmxAmzCredential -> X-Amz-CredentialxAmzDate -> X-Amz-DatexAmzSignature -> X-Amz-SignaturesuccessActionStatus -> success_action_statuscontentType -> Content-TypecacheControl -> Cache-Controlacl, bucket, key, and policy as-is-F "file=@/tmp/cms_img_{fieldSlug}_{index}.{ext};type=image/{ext}"Call data_cms_tool with action update_collection_items using only fields that were successfully converted and uploaded.
For Image fields, set:
{
"fieldSlug": {
"fileId": "{newAssetId}",
"url": "{hostedUrl}"
}
}
For MultiImage fields, reconstruct the full image array and replace only successfully processed entries with the new { "fileId", "url" } values. Preserve skipped entries exactly as they were.
After a successful update, call data_cms_tool with action publish_collection_items for the item ID. The CMS may re-process the image and generate its own CDN URL; the hostedUrl from the asset upload is the source reference.
Print a concise summary table:
| Field | Original | Converted | Savings |
|-------|----------|-----------|---------|
| main-image | 118,044 B (JPEG) | 113,260 B (webp) | 4.1% |
Also report:
User prompt:
Compress the main image on this CMS item to webp.
Response flow:
I need the collection ID, item ID, image fields, target format, and quality before compressing the CMS image.
Compression Preview
Collection: 65f...
Item: 66a...
Target format: webp
Quality: 85
Fields to process:
- main-image: blog-hero.jpg -> blog-hero.webp
Type `confirm` to download, convert, upload, update the CMS item, and publish.
Final report:
CMS Image Compression Complete
| Field | Original | Converted | Savings |
|-------|----------|-----------|---------|
| main-image | 842,911 B (JPEG) | 214,330 B (webp) | 74.6% |
Updated and published item 66a...
hero.jpg.webp.Take webflow/webflow-mcp:compress-cms-image from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference pip.
Without those the skill loads but fails at the first command.