# Demos and architectures URL: https://developers.cloudflare.com/images/demos/ import { ExternalResources, GlossaryTooltip, ResourcesBySelector } from "~/components" Learn how you can use Images within your existing architecture. ## Demos Explore the following demo applications for Images. ## Reference architectures Explore the following reference architectures that use Images: --- # Get started URL: https://developers.cloudflare.com/images/get-started/ In this guide, you will get started with Cloudflare Images and make your first API request. ## Prerequisites Before you make your first API request, ensure that you have a Cloudflare Account ID and an API token. Refer to [Find zone and account IDs](/fundamentals/setup/find-account-and-zone-ids/) for help locating your Account ID and [Create an API token](/fundamentals/api/get-started/create-token/) to learn how to create an access your API token. ## Make your first API request ```bash curl --request POST \ --url https://api.cloudflare.com/client/v4/accounts//images/v1 \ --header 'Authorization: Bearer ' \ --header 'Content-Type: multipart/form-data' \ --form file=@./ ``` ## Enable transformations on your zone You can dynamically optimize images that are stored outside of Cloudflare Images and deliver them using [transformation URLs](/images/transform-images/transform-via-url/). Cloudflare will automatically cache every transformed image on our global network so that you store only the original image at your origin. To enable transformations on your zone: 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. Go to **Images** > **Transformations**. 3. Go to the specific zone where you want to enable transformations. 4. Select **Enable for zone**. This will allow you to optimize and deliver remote images. :::note With **Resize images from any origin** unchecked, only the initial URL passed will be checked. Any redirect returned will be followed, including if it leaves the zone, and the resulting image will be transformed. ::: :::note If you are using transformations in a Worker, you need to include the appropriate logic in your Worker code to prevent resizing images from any origin. Unchecking this option in the dash does not apply to transformation requests coming from Cloudflare Workers. ::: --- # Overview URL: https://developers.cloudflare.com/images/ import { CardGrid, Description, Feature, LinkTitleCard, Plan } from "~/components" Store, transform, optimize, and deliver images at scale Cloudflare Images provides an end-to-end solution designed to help you streamline your image infrastructure from a single API and runs on [Cloudflare's global network](https://www.cloudflare.com/network/). There are two different ways to use Images: - **Efficiently store and deliver images.** You can upload images into Cloudflare Images and dynamically deliver multiple variants of the same original image. - **Optimize images that are stored outside of Images** You can make transformation requests to optimize any publicly available image on the Internet. Cloudflare Images is available on both [Free and Paid plans](/images/pricing/). By default, all users have access to the Images Free plan, which includes limited usage of the transformations feature to optimize images in remote sources. :::note[Image Resizing is now available as transformations] All Image Resizing features are available as transformations with Images. Each unique transformation is billed only once per 30 days. If you are using a legacy plan with Image Resizing, visit the [dashboard](https://dash.cloudflare.com/) to switch to an Imagesplan. ::: *** ## Features Use Cloudflare’s edge network to store your images. Accept uploads directly and securely from your users by generating a one-time token. Add up to 100 variants to specify how images should be resized for various use cases. Control access to your images by using signed URL tokens. *** ## More resources Engage with other users and the Images team on Cloudflare support forum. --- # Pricing URL: https://developers.cloudflare.com/images/pricing/ By default, all users are on the Images Free plan. The Free plan includes access to the transformations feature, which lets you optimize images stored outside of Images, like in R2. The Paid plan allows transformations, as well as access to storage in Images. Pricing is dependent on which features you use. The table below shows which metrics are used for each use case. | Use case | Metrics | Availability | |----------|---------|--------------| | Optimize images stored outside of Images | Images Transformed | Free and Paid plans | | Optimized images that are stored in Cloudflare Images | Images Stored, Images Delivered | Only Paid plans | ## Images Free On the Free plan, you can request up to 5,000 unique transformations each month for free. Once you exceed 5,000 unique transformations: - Existing transformations in cache will continue to be served as expected. - New transformations will return a `9422` error. If your source image is from the same domain where the transformation is served, then you can use the [`onerror` parameter](/images/transform-images/transform-via-url/#onerror) to redirect to the original image. - You will not be charged for exceeding the limits in the Free plan. To request more than 5,000 unique transformations each month, you can purchase an Images Paid plan. ## Images Paid When you purchase an Images Paid plan, you can choose your own storage or add storage in Images. | Metric | Pricing | |--------|---------| | Images Transformed | First 5,000 unique transformations included + $0.50 / 1,000 unique transformations / month | | Images Stored | $5 / 100,000 images stored / month | | Images Delivered | $1 / 100,000 images delivered / month | If you optimize an image stored outside of Images, then you will be billed only for Images Transformed. Alternatively, Images Stored and Images Delivered apply only to images that are stored in your Images bucket. When you optimize an image that is stored in Images, then this counts toward Images Delivered — not Images Transformed. ## Metrics ### Images Transformed A unique transformation is a request to transform an original image based on a set of [supported parameters](/images/transform-images/transform-via-url/#options). This metric is used only when optimizing images that are stored outside of Images. For example, if you transform `thumbnail.jpg` as 100x100, then this counts as 1 unique transformation. If you transform the same `thumbnail.jpg` as 200x200, then this counts as a separate unique transformation. You are billed for the number of unique transformations that are counted during each billing period. Unique transformations are counted over a 30-day sliding window. For example, if you request `width=100/thumbnail.jpg` on June 30, then this counts once for that billing period. If you request the same transformation on July 1, then this will not count as a billable request, since the same transformation was already requested within the last 30 days. The `format` parameter counts as only 1 billable transformation, even if multiple copies of an image are served. In other words, if `width=100,format=auto/thumbnail.jpg` is served to some users as AVIF and to others as WebP, then this counts as 1 unique transformation instead of 2. #### Example A retail website has 1,000 original product images that get served in 5 different sizes each month. This results in 5,000 unique transformations — or a cost of $2.50 per month. ### Images Stored Storage in Images is available only with an Images Paid plan. You can purchase storage in increments of $5 for every 100,000 images stored per month. You can create predefined variants to specify how an image should be resized, such as `thumbnail` as 100x100 and `hero` as 1600x500. Only uploaded images count toward Images Stored; defining variants will not impact your storage limit. ### Images Delivered For images that are stored in Images, you will incur $1 for every 100,000 images delivered per month. This metric does not include transformed images that are stored in remote sources. Every image requested by the browser counts as 1 billable request. #### Example A retail website has a product page that uses Images to serve 10 images. If the page was visited 10,000 times this month, then this results in 100,000 images delivered — or $1.00 in billable usage. --- # Apply blur URL: https://developers.cloudflare.com/images/manage-images/blur-variants/ You can apply blur to image variants by creating a specific variant for this effect first or by editing a previously created variant. Note that you cannot blur an SVG file. Refer to [Resize images](/images/manage-images/create-variants/) for help creating variants. You can also refer to the API to learn how to use blur using flexible variants. To blur an image: 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. Select **Images** > **Variants**. 3. Find the variant you want to blur and select **Edit** > **Customization Options**. 4. Use the slider to adjust the blurring effect. You can use the preview image to see how strong the blurring effect will be. 5. Select **Save**. The image should now display the blurred effect. --- # Browser TTL URL: https://developers.cloudflare.com/images/manage-images/browser-ttl/ Browser TTL controls how long an image stays in a browser's cache and specifically configures the `cache-control` response header. ### Default TTL By default, an image's TTL is set to two days to meet user needs, such as re-uploading an image under the same [Custom ID](/images/upload-images/upload-custom-path/). ## Custom setting You can use two custom settings to control the Browser TTL, an account or a named variant. To adjust how long a browser should keep an image in the cache, set the TTL in seconds, similar to how the `max-age` header is set. The value should be an interval between one hour to one year. ### Browser TTL for an account Setting the Browser TTL per account overrides the default TTL. ```bash title="Example" curl --request PATCH 'https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/config' \ --header "Authorization: Bearer " \ --header "Content-Type: application/json" \ --data '{ "browser_ttl": 31536000 }' ``` When the Browser TTL is set to one year for all images, the response for the `cache-control` header is essentially `public`, `max-age=31536000`, `stale-while-revalidate=7200`. ### Browser TTL for a named variant Setting the Browser TTL for a named variant is a more granular option that overrides all of the above when creating or updating an image variant, specifically the `browser_ttl` option in seconds. ```bash title="Example" curl 'https://api.cloudflare.com/client/v4/accounts//images/v1/variants' \ --header "Authorization: Bearer " \ --header "Content-Type: application/json" \ --data '{ "id":"avatar", "options": { "width":100, "browser_ttl": 86400 } }' ``` When the Browser TTL is set to one day for images requested with this variant, the response for the `cache-control` header is essentially `public`, `max-age=86400`, `stale-while-revalidate=7200`. :::note [Private images](/images/manage-images/serve-images/serve-private-images/) do not respect default or custom TTL settings. The private images cache time is set according to the expiration time and can be as short as one hour. ::: --- # Configure webhooks URL: https://developers.cloudflare.com/images/manage-images/configure-webhooks/ You can set up webhooks to receive notifications about your upload workflow. This will send an HTTP POST request to a specified endpoint when an image either successfully uploads or fails to upload. Currently, webhooks are supported only for [direct creator uploads](/images/upload-images/direct-creator-upload/). To receive notifications for direct creator uploads: 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. Go to **Notifications** > **Destinations**. 3. From the Webhooks card, select **Create**. 4. Enter information for your webhook and select **Save and Test**. The new webhook will appear in the **Webhooks** card and can be attached to notifications. 5. Next, go to **Notifications** > **All Notifications** and select **Add**. 6. Under the list of products, locate **Images** and select **Select**. 7. Give your notification a name and optional description. 8. Under the **Webhooks** field, select the webhook that you recently created. 9. Select **Save**. --- # Delete images URL: https://developers.cloudflare.com/images/manage-images/delete-images/ You can delete an image from the Cloudflare Images storage using the dashboard or the API. ## Delete images via the Cloudflare dashboard 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. Select **Images**. 3. Find the image you want to remove and select **Delete**. 4. (Optional) To delete more than one image, select the checkbox next to the images you want to delete and then **Delete selected**. Your image will be deleted from your account. ## Delete images via the API Make a `DELETE` request to the [delete image endpoint](/api/resources/images/subresources/v1/methods/delete/). `{image_id}` must be fully URL encoded in the API call URL. ```bash curl --request DELETE https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/{image_id} \ --header "Authorization: Bearer " ``` After the image has been deleted, the response returns `"success": true`. --- # Create variants URL: https://developers.cloudflare.com/images/manage-images/create-variants/ Variants let you specify how images should be resized for different use cases. By default, images are served with a `public` variant, but you can create up to 100 variants to fit your needs. Follow these steps to create a variant. :::note Cloudflare Images can deliver SVG files but will not resize them because it is an inherently scalable format. Resize via the Cloudflare dashboard. ::: 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. Select **Images** > **Variants**. 3. Name your variant and select **Add New Variant**. 4. Define variables for your new variant, such as resizing options, type of fit, and specific metadata options. ## Resize via the API Make a `POST` request to [create a variant](/api/resources/images/subresources/v1/subresources/variants/methods/create/). ```bash curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/variants" \ --header "Authorization: Bearer " \ --header "Content-Type: application/json" \ --data '{"id":"","options":{"fit":"scale-down","metadata":"none","width":1366,"height":768},"neverRequireSignedURLs":true} ``` ## Fit options The `Fit` property describes how the width and height dimensions should be interpreted. The chart below describes each of the options. | Fit Options | Behavior | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Scale down | The image is shrunk in size to fully fit within the given width or height, but will not be enlarged. | | Contain | The image is resized (shrunk or enlarged) to be as large as possible within the given width or height while preserving the aspect ratio. | | Cover | The image is resized to exactly fill the entire area specified by width and height and will be cropped if necessary. | | Crop | The image is shrunk and cropped to fit within the area specified by the width and height. The image will not be enlarged. For images smaller than the given dimensions, it is the same as `scale-down`. For images larger than the given dimensions, it is the same as `cover`. | | Pad | The image is resized (shrunk or enlarged) to be as large as possible within the given width or height while preserving the aspect ratio. The extra area is filled with a background color (white by default). | ## Metadata options Variants allow you to choose what to do with your image’s metadata information. From the **Metadata** dropdown, choose: * Strip all metadata * Strip all metadata except copyright * Keep all metadata ## Public access When the **Always allow public access** option is selected, particular variants will always be publicly accessible, even when images are made private through the use of [signed URLs](/images/manage-images/serve-images/serve-private-images). --- # Delete variants URL: https://developers.cloudflare.com/images/manage-images/delete-variants/ You can delete variants via the Images dashboard or API. The only variant you cannot delete is public. :::caution Deleting a variant is a global action that will affect other images that contain that variant. ::: ## Delete variants via the Cloudflare dashboard 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. Select **Images** > **Variants**. 3. Find the variant you want to remove and select **Delete**. ## Delete variants via the API Make a `DELETE` request to the delete variant endpoint. ```bash curl --request DELETE https://api.cloudflare.com/client/v4/account/{account_id}/images/v1/variants/{variant_name} \ --header "Authorization: Bearer " ``` After the variant has been deleted, the response returns `"success": true.` --- # Edit images URL: https://developers.cloudflare.com/images/manage-images/edit-images/ The Edit option provides you available options to modify a specific image. After choosing to edit an image, you can: * Require signed URLs to use with that particular image. * Use a cURL command you can use as an example to access the image. * Use fully-formed URLs for all the variants configured in your account. To edit an image: 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. In **Account Home**, select **Images**. 3. Locate the image you want to modify and select **Edit**. --- # Enable flexible variants URL: https://developers.cloudflare.com/images/manage-images/enable-flexible-variants/ Flexible variants allow you to create variants with dynamic resizing which can provide more options than regular variants allow. This option is not enabled by default. ## Enable flexible variants via the Cloudflare dashboard 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. Select **Images** > **Variants**. 3. Enable **Flexible variants**. ## Enable flexible variants via the API Make a `PATCH` request to the [Update a variant endpoint](/api/resources/images/subresources/v1/subresources/variants/methods/edit/). ```bash curl --request PATCH https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/config \ --header "Authorization: Bearer " \ --header "Content-Type: application/json" \ --data '{"flexible_variants": true}' ``` After activation, you can use [transformation parameters](/images/transform-images/transform-via-url/#options) on any Cloudflare image. For example, `https://imagedelivery.net/{account_hash}/{image_id}/w=400,sharpen=3` Note that flexible variants cannot be used for images that require a [signed delivery URL](/images/manage-images/serve-images/serve-private-images). --- # Export images URL: https://developers.cloudflare.com/images/manage-images/export-images/ Cloudflare Images supports image exports via the Cloudflare dashboard and API which allows you to get the original version of your image. ## Export images via the Cloudflare dashboard 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. Select **Images**. 3. Find the image or images you want to export. 4. To export a single image, select **Export** from its menu. To export several images, select the checkbox next to each image and then select **Export selected**. Your images are downloaded to your machine. ## Export images via the API Make a `GET` request as shown in the example below. `` must be fully URL encoded in the API call URL. `GET accounts//images/v1//blob` --- # Manage uploaded images URL: https://developers.cloudflare.com/images/manage-images/ import { DirectoryListing } from "~/components" --- # Changelog URL: https://developers.cloudflare.com/images/platform/changelog/ import { ProductReleaseNotes } from "~/components"; {/* */} --- # Platform URL: https://developers.cloudflare.com/images/platform/ import { DirectoryListing } from "~/components" --- # Activate Polish URL: https://developers.cloudflare.com/images/polish/activate-polish/ import { Render } from "~/components" Images in the [cache must be purged](/cache/how-to/purge-cache/) or expired before seeing any changes in Polish settings. :::caution Do not activate Polish and [image transformations](/images/transform-images/) simultaneously. Image transformations already apply lossy compression, which makes Polish redundant. ::: 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/) and select the account and domain where you want to activate Polish. 2. Go to **Speed** > **Optimization** > **Image Optimization**. 3. Under **Polish**, select *Lossy* or *Lossless* from the drop-down menu. [*Lossy*](/images/polish/compression/#lossy) gives greater file size savings. 4. (Optional) Select **WebP**. Enable this option if you want to further optimize PNG and JPEG images stored in the origin server, and serve them as WebP files to browsers that support this format. To ensure WebP is not served from cache to a browser without WebP support, disable any WebP conversion utilities at your origin web server when using Polish. --- # Cf-Polished statuses URL: https://developers.cloudflare.com/images/polish/cf-polished-statuses/ If a `Cf-Polished` header is not returned, try [using single-file cache purge](/cache/how-to/purge-cache) to purge the image. The `Cf-Polished` header may also be missing if the origin is sending non-image `Content-Type`, or non-cacheable `Cache-Control`. * `input_too_large`: The input image is too large or complex to process, and needs a lower resolution. Cloudflare recommends using PNG or JPEG images that are less than 4,000 pixels in any dimension, and smaller than 20 MB. * `not_compressed` or `not_needed`: The image was fully optimized at the origin server and no compression was applied. * `webp_bigger`: Polish attempted to convert to WebP, but the WebP image was not better than the original format. Because the WebP version does not exist, the status is set on the JPEG/PNG version of the response. Refer to [the reasons why Polish chooses not to use WebP](/images/polish/no-webp/). * `cannot_optimize` or `internal_error`: The input image is corrupted or incomplete at the origin server. Upload a new version of the image to the origin server. * `format_not_supported`: The input image format is not supported (for example, BMP or TIFF) or the origin server is using additional optimization software that is not compatible with Polish. Try converting the input image to a web-compatible format (like PNG or JPEG) and/or disabling additional optimization software at the origin server. * `vary_header_present`: The origin web server has sent a `Vary` header with a value other than `accept-encoding`. If the origin web server is attempting to support WebP, disable WebP at the origin web server and let Polish perform the WebP conversion. Polish will still work if `accept-encoding` is the only header listed within the `Vary` header. Polish skips image URLs processed by [Cloudflare Images](/images/transform-images/). --- # Cloudflare Polish URL: https://developers.cloudflare.com/images/polish/ import { FeatureTable } from "~/components" Cloudflare Polish is a one-click image optimization product that automatically optimizes images in your site. Polish strips metadata from images and reduces image size through lossy or lossless compression to accelerate the speed of image downloads. When an image is fetched from your origin, our systems automatically optimize it in Cloudflare's cache. Subsequent requests for the same image will get the smaller, faster, optimized version of the image, improving the speed of your website. ![Example of Polish compression's quality.](~/assets/images/images/polish.png) ## Comparison * Polish automatically optimizes all images served from your origin server. It keeps the same image URLs, and does not require changing markup of your pages. * Cloudflare Images API allows you to create new images with resizing, cropping, watermarks, and other processing applied. These images get their own new URLs, and you need to embed them on your pages to take advantage of this service. Images created this way are already optimized, and there is no need to apply Polish to them. ## Availability --- # Polish compression URL: https://developers.cloudflare.com/images/polish/compression/ With Lossless and Lossy modes, Cloudflare attempts to strip as much metadata as possible. However, Cloudflare cannot guarantee stripping all metadata because other factors, such as caching status, might affect which metadata is finally sent in the response. :::caution[Warning] Polish may not be applied to origin responses that contain a `Vary` header. The only accepted `Vary` header is `Vary: Accept-Encoding`. ::: ## Compression options ### Off Polish is disabled and no compression is applied. Disabling Polish does not revert previously polished images to original, until they expire or are purged from the cache. ### Lossless The Lossless option attempts to reduce file sizes without changing any of the image pixels, keeping images identical to the original. It removes most metadata, like EXIF data, and losslessly recompresses image data. JPEG images may be converted to progressive format. On average, lossless compression reduces file sizes by 21 percent compared to unoptimized image files. The Lossless option prevents conversion of JPEG to WebP, because this is always a lossy operation. ### Lossy The Lossy option applies significantly better compression to images than the Lossless option, at a cost of small quality loss. When uncompressed, some of the redundant information from the original image is lost. On average, using Lossy mode reduces file sizes by 48 percent. This option also removes metadata from images. The Lossy option mainly affects JPEG images, but PNG images may also be compressed in a lossy way, or converted to JPEG when this improves compression. ### WebP When enabled, in addition to other optimizations, Polish creates versions of images converted to the WebP format. WebP compression is quite effective on PNG images, reducing file sizes by approximately 26 percent. It may reduce file sizes of JPEG images by around 17 percent, but this [depends on several factors](/images/polish/no-webp/). WebP is supported in all browsers except for Internet Explorer and KaiOS. You can learn more in our [blog post](https://blog.cloudflare.com/a-very-webp-new-year-from-cloudflare/). The WebP version is served only when the `Accept` header from the browser includes WebP, and the WebP image is significantly smaller than the lossy or lossless recompression of the original format: ```txt Accept: image/avif,image/webp,image/*,*/*;q=0.8 ``` Polish only converts standard image formats to the WebP format. If the origin server serves WebP images, Polish will not convert them, and will not optimize them. #### File size, image quality, and WebP Lossy formats like JPEG and WebP are able to generate files of any size, and every image could theoretically be made smaller. However, reduction in file size comes at a cost of reduction in image quality. Reduction of file sizes below each format's optimal size limit causes disproportionally large losses in quality. Re-encoding of files that are already optimized reduces their quality more than it reduces their file size. Cloudflare will not convert from JPEG to WebP when the conversion would make the file bigger, or would reduce image quality by more than it would save in file size. If you choose the Lossless Polish setting, then WebP will be used very rarely. This is due to the fact that, in this mode, WebP is only adequate for PNG images, and cannot improve compression for JPEG images. Although WebP compresses better than JPEG on average, there are exceptions, and in some occasions JPEG compresses better than WebP. Cloudflare tries to detect these cases and keep the JPEG format. If you serve low-quality JPEG images at the origin (quality setting 60 or lower), it may not be beneficial to convert them to WebP. This is because low-quality JPEG images have blocky edges and noise caused by compression, and these distortions increase file size of WebP images. We recommend serving high-quality JPEG images (quality setting between 80 and 90) at your origin server to avoid this issue. If your server or Content Management System (CMS) has a built-in image converter or optimizer, it may interfere with Polish. It does not make sense to apply lossy optimizations twice to images, because quality degradation will be larger than the savings in file size. ## Polish interaction with Image optimization Polish will not be applied to URLs using image transformations. Resized images already have lossy compression applied where possible, so they do not need the optimizations provided by Polish. Use the `format=auto` option to allow use of WebP and AVIF formats. --- # WebP may be skipped URL: https://developers.cloudflare.com/images/polish/no-webp/ Polish avoids converting images to the WebP format when such conversion would increase the file size, or significantly degrade image quality. Polish also optimizes JPEG images, and the WebP format is not always better than a well-optimized JPEG. To enhance the use of WebP in Polish, enable the [Lossy option](/images/polish/compression/#lossy). When you create new JPEG images, save them with a slightly higher quality than usually necessary. We recommend JPEG quality settings between 85 and 95, but not higher. This gives Polish enough headroom for lossy conversion to WebP and optimized JPEG. ## In the **lossless** mode, it is not feasible to convert JPEG to WebP WebP is actually a name for two quite different image formats: WebP-lossless (similar to PNG) and WebP-VP8 (similar to JPEG). When the [Lossless option](/images/polish/compression/#lossless) is enabled, Polish will not perform any optimizations that change image pixels. This allows Polish to convert only between lossless image formats, such as PNG, GIF, and WebP-lossless. JPEG images will not be converted though, because the WebP-VP8 format does not support the conversion from JPEG without quality loss, and the WebP-lossless format does not compress images as heavily as JPEG. In the lossless mode, Polish can still apply lossless optimizations to JPEG images. This is a unique feature of the JPEG format that does not have an equivalent in WebP. ## Low-quality JPEG images do not convert well to WebP When JPEG files are already heavily compressed (for example, saved with a low quality setting like `q=50`, or re-saved many times), the conversion to WebP may not be beneficial, and may actually increase the file size. This is because lossy formats add distortions to images (for example, JPEG makes images blocky and adds noise around sharp edges), and the WebP format can not tell the difference between details of the image it needs to preserve and unwanted distortions caused by a previous compression. This forces WebP to wastefully use bytes on keeping the added noise and blockyness, which increases the file size, and makes compression less beneficial overall. Polish never makes files larger. When we see that the conversion to WebP increases the file size, we skip it, and keep the smaller original file format. ## For some images conversion to WebP can degrade quality too much The WebP format, in its more efficient VP8 mode, always loses some quality when compressing images. This means that the conversion from JPEG always makes WebP images look slightly worse. Polish ensures that file size savings from the conversion outweigh the quality loss. Lossy WebP has a significant limitation: it can only keep one shade of color per 4 pixels. The color information is always stored at half of the image resolution. In high-resolution photos this degradation is rarely noticeable. However, in images with highly saturated colors and sharp edges, this limitation can result in the WebP format having noticeably pixelated or smudged edges. Additionally, the WebP format applies smoothing to images. This feature hides blocky distortions that are a characteristic of low-quality JPEG images, but on the other hand it can cause loss of fine textures and details in high-quality images, making them look airbrushed. Polish tries to avoid degrading images for too little gain. Polish keeps the JPEG format when it has about the same size as WebP, but better quality. ## Sometimes older formats are better than WebP The WebP format has an advantage over JPEG when saving images with soft or blurry content, and when using low quality settings. WebP has fewer advantages when storing high-quality images with fine textures or noise. Polish applies optimizations to JPEG images too, and sometimes well-optimized JPEG is simply better than WebP, and gives a better quality and smaller file size at the same time. We try to detect these cases, and keep the JPEG format when it works better. Sometimes animations with little motion are more efficient as GIF than animated WebP. The WebP format does not support progressive rendering. With [HTTP/2 prioritization](/speed/optimization/protocol/enhanced-http2-prioritization/) enabled, progressive JPEG images may appear to load quicker, even if their file sizes are larger. ## Beware of compression that is not better, only more of the same With a lossy format like JPEG or WebP, it is always possible to take an existing image, save it with a slightly lower quality, and get an image that looks *almost* the same, but has a smaller file size. It is the [heap paradox](https://en.wikipedia.org/wiki/Sorites_paradox): you can remove a grain of sand from a heap, and still have a heap of sand. There is no point when you can not make the heap smaller, except when there is no sand left. It is always possible to make an image with a slightly lower quality, all the way until all the accumulated losses degrade the image beyond recognition. Avoid applying multiple lossy optimization tools to images, before or after Polish. Multiple lossy operations degrade quality disproportionally more than what they save in file sizes. For this reason Polish will not create the smallest possible file sizes. Instead, Polish aims to maximize the quality to file size ratio, to create the smallest possible files while preserving good quality. The quality level we stop at is carefully chosen to minimize visual distortion, while still having a high compression ratio. --- # Reference URL: https://developers.cloudflare.com/images/reference/ import { DirectoryListing } from "~/components"; --- # Security URL: https://developers.cloudflare.com/images/reference/security/ To further ensure the security and efficiency of image optimization services, you can adopt Cloudflare products that safeguard against malicious activities. Cloudflare security products like [Cloudflare WAF](/waf/), [Cloudflare Bot Management](/bots/get-started/bm-subscription/) and [Cloudflare Rate Limiting](/waf/rate-limiting-rules/) can enhance the protection of your image optimization requests against abuse. This proactive approach ensures a reliable and efficient experience for all legitimate users. --- # Troubleshooting URL: https://developers.cloudflare.com/images/reference/troubleshooting/ ## Requests without resizing enabled Does the response have a `Cf-Resized` header? If not, then resizing has not been attempted. Possible causes: * The feature is not enabled in the Cloudflare Dashboard. * There is another Worker running on the same request. Resizing is "forgotten" as soon as one Worker calls another. Do not use Workers scoped to the entire domain `/*`. * Preview in the Editor in Cloudflare Dashboard does not simulate image resizing. You must deploy the Worker and test from another browser tab instead. *** ## Error responses from resizing When resizing fails, the response body contains an error message explaining the reason, as well as the `Cf-Resized` header containing `err=code`: * 9401 — The required arguments in `{cf:image{…}}` options are missing or are invalid. Try again. Refer to [Fetch options](/images/transform-images/transform-via-workers/#fetch-options) for supported arguments. * 9402 — The image was too large or the connection was interrupted. Refer to [Supported formats and limitations](/images/transform-images/) for more information. * 9403 — A [request loop](/images/transform-images/transform-via-workers/#prevent-request-loops) occurred because the image was already resized or the Worker fetched its own URL. Verify your Worker path and image path on the server do not overlap. * 9406 & 9419 — The image URL is a non-HTTPS URL or the URL has spaces or unescaped Unicode. Check your URL and try again. * 9407 — A lookup error occurred with the origin server's domain name. Check your DNS settings and try again. * 9404 — The image does not exist on the origin server or the URL used to resize the image is wrong. Verify the image exists and check the URL. * 9408 — The origin server returned an HTTP 4xx status code and may be denying access to the image. Confirm your image settings and try again. * 9509 — The origin server returned an HTTP 5xx status code. This is most likely a problem with the origin server-side software, not the resizing. * 9412 — The origin server returned a non-image, for example, an HTML page. This usually happens when an invalid URL is specified or server-side software has printed an error or presented a login page. * 9413 — The image exceeds the maximum image area of 100 megapixels. Use a smaller image and try again. * 9420 — The origin server redirected to an invalid URL. Confirm settings at your origin and try again. * 9421 — The origin server redirected too many times. Confirm settings at your origin and try again. * 9422 - The transformation request is rejected because the usage limit was reached. If you need to request more than 5,000 unique transformations, upgrade to an Images Paid plan. * 9432 — The Images Binding is not available using legacy billing. Your account is using the legacy Image Resizing subscription. To bind Images to your Worker, you will need to update your plan to the Images subscription in the dashboard. * 9504, 9505, & 9510 — The origin server could not be contacted because the origin server may be down or overloaded. Try again later. * 9523 — The `/cdn-cgi/image/` resizing service could not perform resizing. This may happen when an image has invalid format. Use correctly formatted image and try again. * 9524 — The `/cdn-cgi/image/` resizing service could not perform resizing. This may happen when an image URL is intercepted by a Worker. As an alternative you can [resize within the Worker](/images/transform-images/transform-via-workers/). This can also happen when using a `pages.dev` URL of a [Cloudflare Pages](/pages/) project. In that case, you can use a [Custom Domain](/pages/configuration/custom-domains/) instead. * 9520 — The image format is not supported. Refer to [Supported formats and limitations](/images/transform-images/) to learn about supported input and output formats. * 9522 — The image exceeded the processing limit. This may happen briefly after purging an entire zone or when files with very large dimensions are requested. If the problem persists, contact support. * 9422, 9424, 9516, 9517, 9518, 9522 & 9523 — Internal errors. Please contact support if you encounter these errors. *** ## Limits * Maximum image size is 100 megapixels (meaning 10.000×10.000 pixels large). Maximum file size is 100 MB. GIF/WebP animations are limited to 50 megapixels total (sum of sizes of all frames). * Image Resizing is not compatible with [Bringing Your Own IPs (BYOIP)](/byoip/). *** ## Authorization and cookies are not supported Image requests to the origin will be anonymized (no cookies, no auth, no custom headers). This is because we have to have one public cache for resized images, and it would be unsafe to share images that are personalized for individual visitors. However, in cases where customers agree to store such images in public cache, Cloudflare supports resizing images through Workers [on authenticated origins](/images/transform-images/transform-via-workers/). *** ## Caching and purging Changes to image dimensions or other resizing options always take effect immediately — no purging necessary. Image requests consists of two parts: running Worker code, and image processing. The Worker code is always executed and uncached. Results of image processing are cached for one hour or longer if origin server's `Cache-Control` header allows. Source image is cached using regular caching rules. Resizing follows redirects internally, so the redirects are cached too. Because responses from Workers themselves are not cached at the edge, purging of *Worker URLs* does nothing. Resized image variants are cached together under their source’s URL. When purging, use the (full-size) source image’s URL, rather than URLs of the Worker that requested resizing. If the origin server sends an `Etag` HTTP header, the resized images will have an `Etag` HTTP header that has a format `cf-:`. You can compare the second part with the `Etag` header of the source image URL to check if the resized image is up to date. --- # Bind to Workers API URL: https://developers.cloudflare.com/images/transform-images/bindings/ A [binding](/workers/runtime-apis/bindings/) connects your [Worker](/workers/) to external resources on the Developer Platform, like [Images](/images/transform-images/transform-via-workers/), [R2 buckets](/r2/buckets/), or [KV Namespaces](/kv/concepts/kv-namespaces/). You can bind the Images API to your Worker to transform, resize, and encode images without requiring them to be accessible through a URL. For example, when you allow Workers to interact with Images, you can: - Transform an image, then upload the output image directly into R2 without serving to the browser. - Optimize an image stored in R2 by passing the blob of bytes representing the image, instead of fetching the public URL for the image. - Resize an image, overlay the output over a second image as a watermark, then resize this output into a final result. Bindings can be configured in the Cloudflare dashboard for your Worker or in the `wrangler.toml` file in your project's directory. ## Setup The Images binding is enabled on a per-Worker basis. You can define variables in the `wrangler.toml` file of your Worker project's directory. These variables are bound to external resources at runtime, and you can then interact with them through this variable. To bind Images to your Worker, add the following to the end of your `wrangler.toml` file: ```txt [images] binding = "IMAGES" # i.e. available in your Worker on env.IMAGES ``` Within your Worker code, you can interact with this binding by using `env.IMAGES`. ## Methods ### `.transform()` - Defines how an image should be optimized and manipulated through [parameters](/images/transform-images/transform-via-workers/#fetch-options) such as `width`, `height`, and `blur`. ### `.draw()` - Allows [drawing an image](/images/transform-images/draw-overlays/) over another image. - The overlaid image can be manipulated using `opacity`, `repeat`, `top`, `left`, `bottom`, and `right`. To apply other parameters, you can pass a child `.transform()` function inside this method. ### `.output()` * Defines the [output format](/images/transform-images/) for the transformed image such as AVIF, WebP, and JPEG. For example, to rotate, resize, and blur an image, then output the image as AVIF: ```js ​​const info = await env.IMAGES.info(stream); // stream contains a valid image, and width/height is available on the info object const response = ( await env.IMAGES.input(stream) .transform({ rotate: 90 }) .transform({ width: 128 }) .transform({ blur: 20 }) .output({ format: "image/avif" }) ).response(); return response; ``` ### `.info()` - Outputs information about the image, such as `format`, `fileSize`, `width`, and `height`. In this example, the transformed image is outputted as a WebP. Responses from the Images binding are not automatically cached. Workers lets you interact directly with the Cache API to customize cache behavior using Workers. You can implement logic in your script to store transformations in Cloudflare’s cache. ## Interact with your Images binding locally The Images API can be used in local development through [Wrangler](/workers/wrangler/install-and-update/), the command-line interface for Workers. Using the Images binding in local development will not incur usage charges. Wrangler supports two different versions of the Images API: - A high-fidelity version that supports all features that are available through the Images API. This is the same version that Cloudflare runs globally in production. - A low-fidelity version that supports only a subset of features, such as resizing and rotation. To test the high-fidelity version of Images, you can run `wrangler dev`: ```txt npx wrangler dev ``` This creates a local-only environment that mirrors the production environment where Cloudflare runs the Images API. You can test your Worker with all available transformation features before deploying to production. To test the low-fidelity version of Images, add the `--experimental-images-local-mode` flag: ```txt npm wrangler dev --experimental-images-local-mode ``` Currently, this version supports only `width`, `height`, `rotate`, and `format`. --- # Control origin access URL: https://developers.cloudflare.com/images/transform-images/control-origin-access/ You can serve resized images without giving access to the original image. Images can be hosted on another server outside of your zone, and the true source of the image can be entirely hidden. The origin server may require authentication to disclose the original image, without needing visitors to be aware of it. Access to the full-size image may be prevented by making it impossible to manipulate resizing parameters. All these behaviors are completely customizable, because they are handled by custom code of a script running [on the edge in a Cloudflare Worker](/images/transform-images/transform-via-workers/). ```js export default { async fetch(request, env, ctx) { // Here you can compute arbitrary imageURL and // resizingOptions from any request data ... return fetch(imageURL, { cf: { image: resizingOptions } }); }, }; ``` This code will be run for every request, but the source code will not be accessible to website visitors. This allows the code to perform security checks and contain secrets required to access the images in a controlled manner. The examples below are only suggestions, and do not have to be followed exactly. You can compute image URLs and resizing options in many other ways. :::caution[Warning] When testing image transformations, make sure you deploy the script and test it from a regular web browser window. The preview in the dashboard does not simulate transformations. ::: ## Hiding the image server ```js export default { async fetch(request, env, ctx) { const resizingOptions = { /* resizing options will be demonstrated in the next example */ }; const hiddenImageOrigin = "https://secret.example.com/hidden-directory"; const requestURL = new URL(request.url); // Append the request path such as "/assets/image1.jpg" to the hiddenImageOrigin. // You could also process the path to add or remove directories, modify filenames, etc. const imageURL = hiddenImageOrigin + requestURL.path; // This will fetch image from the given URL, but to the website's visitors this // will appear as a response to the original request. Visitor’s browser will // not see this URL. return fetch(imageURL, { cf: { image: resizingOptions } }); }, }; ``` ## Preventing access to full-size images On top of protecting the original image URL, you can also validate that only certain image sizes are allowed: ```js export default { async fetch(request, env, ctx) { const imageURL = … // detail omitted in this example, see the previous example const requestURL = new URL(request.url) const resizingOptions = { width: requestURL.searchParams.get("width"), } // If someone tries to manipulate your image URLs to reveal higher-resolution images, // you can catch that and refuse to serve the request (or enforce a smaller size, etc.) if (resizingOptions.width > 1000) { throw Error("We don’t allow viewing images larger than 1000 pixels wide") } return fetch(imageURL, {cf:{image:resizingOptions}}) },}; ``` ## Avoid image dimensions in URLs You do not have to include actual pixel dimensions in the URL. You can embed sizes in the Worker script, and select the size in some other way — for example, by naming a preset in the URL: ```js export default { async fetch(request, env, ctx) { const requestURL = new URL(request.url); const resizingOptions = {}; // The regex selects the first path component after the "images" // prefix, and the rest of the path (e.g. "/images/first/rest") const match = requestURL.path.match(/images\/([^/]+)\/(.+)/); // You can require the first path component to be one of the // predefined sizes only, and set actual dimensions accordingly. switch (match && match[1]) { case "small": resizingOptions.width = 300; break; case "medium": resizingOptions.width = 600; break; case "large": resizingOptions.width = 900; break; default: throw Error("invalid size"); } // The remainder of the path may be used to locate the original // image, e.g. here "/images/small/image1.jpg" would map to // "https://storage.example.com/bucket/image1.jpg" resized to 300px. const imageURL = "https://storage.example.com/bucket/" + match[2]; return fetch(imageURL, { cf: { image: resizingOptions } }); }, }; ``` ## Authenticated origin Cloudflare image transformations cache resized images to aid performance. Images stored with restricted access are generally not recommended for resizing because sharing images customized for individual visitors is unsafe. However, in cases where the customer agrees to store such images in public cache, Cloudflare supports resizing images through Workers. At the moment, this is supported on authenticated AWS, Azure, Google Cloud, SecureAuth origins and origins behind Cloudflare Access. ```js null {9} // generate signed headers (application specific) const signedHeaders = generatedSignedHeaders(); fetch(private_url, { headers: signedHeaders cf: { image: { format: "auto", "origin-auth": "share-publicly" } } }) ``` When using this code, the following headers are passed through to the origin, and allow your request to be successful: - `Authorization` - `Cookie` - `x-amz-content-sha256` - `x-amz-date` - `x-ms-date` - `x-ms-version` - `x-sa-date` - `cf-access-client-id` - `cf-access-client-secret` For more information, refer to: - [AWS docs](https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html) - [Azure docs](https://docs.microsoft.com/en-us/rest/api/storageservices/List-Containers2#request-headers) - [Google Cloud docs](https://cloud.google.com/storage/docs/aws-simple-migration) - [Cloudflare Zero Trust docs](/cloudflare-one/identity/service-tokens/) - [SecureAuth docs](https://docs.secureauth.com/2104/en/authentication-api-guide.html) --- # Draw overlays and watermarks URL: https://developers.cloudflare.com/images/transform-images/draw-overlays/ You can draw additional images on top of a resized image, with transparency and blending effects. This enables adding of watermarks, logos, signatures, vignettes, and other effects to resized images. This feature is available only in [Workers](/images/transform-images/transform-via-workers/). To draw overlay images, add an array of drawing commands to options of `fetch()` requests. The drawing options are nested in `options.cf.image.draw`, like in the following example: ```js fetch(imageURL, { cf: { image: { width: 800, height: 600, draw: [ { url: 'https://example.com/branding/logo.png', // draw this image bottom: 5, // 5 pixels from the bottom edge right: 5, // 5 pixels from the right edge fit: 'contain', // make it fit within 100x50 area width: 100, height: 50, opacity: 0.8, // 20% transparent }, ], }, }, }); ``` ## Draw options The `draw` property is an array. Overlays are drawn in the order they appear in the array (the last array entry is the topmost layer). Each item in the `draw` array is an object, which can have the following properties: * `url` * Absolute URL of the image file to use for the drawing. It can be any of the supported file formats. For drawing watermarks or non-rectangular overlays, Cloudflare recommends that you use PNG or WebP images. * `width` and `height` * Maximum size of the overlay image, in pixels. It must be an integer. * `fit` and `gravity` * Affects interpretation of `width` and `height`. Same as [for the main image](/images/transform-images/transform-via-workers/#fetch-options). * `opacity` * Floating-point number between `0` (transparent) and `1` (opaque). For example, `opacity: 0.5` makes overlay semitransparent. * `repeat` * If set to `true`, the overlay image will be tiled to cover the entire area. This is useful for stock-photo-like watermarks. * If set to `"x"`, the overlay image will be tiled horizontally only (form a line). * If set to `"y"`, the overlay image will be tiled vertically only (form a line). * `top`, `left`, `bottom`, `right` * Position of the overlay image relative to a given edge. Each property is an offset in pixels. `0` aligns exactly to the edge. For example, `left: 10` positions left side of the overlay 10 pixels from the left edge of the image it is drawn over. `bottom: 0` aligns bottom of the overlay with bottom of the background image. Setting both `left` and `right`, or both `top` and `bottom` is an error. If no position is specified, the image will be centered. * `background` * Background color to add underneath the overlay image. Same as [for the main image](/images/transform-images/transform-via-workers/#fetch-options). * `rotate` * Number of degrees to rotate the overlay image by. Same as [for the main image](/images/transform-images/transform-via-workers/#fetch-options). ## Draw using the Images binding When [interacting with Images through a binding](/images/transform-images/bindings/), the Images API supports a `.draw()` method. The accepted options for the overlaid image are `opacity`, `repeat`, `top`, `left`, `bottom`, and `right`. ```js // Fetch image and watermark const img = await fetch('https://example.com/image.png'); const watermark = await fetch('https://example.com/watermark.png'); const response = await env.IMAGES.input(img.body) .transform({ width: 1024 }) .draw(watermark.body, { "opacity": 0.25, "repeat": true }) .output({ format: "image/avif" }) .response(); return response; ``` To apply [parameters](/images/transform-images/transform-via-workers/) to the overlaid image, you can pass a child `.transform()` function inside the `.draw()` request. In the example below, the watermark is manipulated with `rotate` and `width` before being drawn over the base image with the `opacity` and `rotate` options. ```js // Fetch image and watermark const response = ( await env.IMAGES.input(img.body) .transform({ width: 1024 }) .draw(watermark.body, { "opacity": 0.25, "repeat": true }) .output({ format: "image/avif" }) ).response(); ``` ## Examples ### Stock Photo Watermark ```js image: { draw: [ { url: 'https://example.com/watermark.png', repeat: true, // Tiled over entire image opacity: 0.2, // and subtly blended }, ]; } ``` ### Signature ```js image: { draw: [ { url: 'https://example.com/by-me.png', // Predefined logo/signature bottom: 5, // Positioned near bottom right corner right: 5, }, ]; } ``` ### Centered icon ```js image: { draw: [ { url: 'https://example.com/play-button.png', // Center position is the default }, ]; } ``` ### Combined Multiple operations can be combined in one image: ```js image: { draw: [ { url: 'https://example.com/watermark.png', repeat: true, opacity: 0.2 }, { url: 'https://example.com/play-button.png' }, { url: 'https://example.com/by-me.png', bottom: 5, right: 5 }, ]; } ``` --- # Transform images URL: https://developers.cloudflare.com/images/transform-images/ import { Render } from "~/components" Transformations let you optimize and manipulate images stored outside of the Cloudflare Images product. Transformed images are served from one of your zones on Cloudflare. To transform an image, you must [enable transformations for your zone](/images/get-started/#enable-transformations-on-your-zone). You can transform an image by using a [specially-formatted URL](/images/transform-images/transform-via-url/) or [through Workers](/images/transform-images/transform-via-workers/). ## Supported formats and limitations ### Supported input formats * JPEG * PNG * GIF (including animations) * WebP (including animations) * SVG ### Supported output formats * JPEG * PNG * GIF (including animations) * WebP (including animations) * SVG * AVIF ### Supported features Transformations can: * Resize and generate JPEG and PNG images, and optionally AVIF or WebP. * Save animations as GIF or animated WebP. * Support ICC color profiles in JPEG and PNG images. * Preserve JPEG metadata (metadata of other formats is discarded). * Convert the first frame of GIF/WebP animations to a still image. ### Format limitations Since some image formats require longer computational times than others, Cloudflare has to find a proper balance between the time it takes to generate an image and to transfer it over the Internet. Resizing requests might not be fulfilled with the format the user expects due to these trade-offs Cloudflare has to make. Images differ in size, transformations, codecs and all of these different aspects influence what compression codecs are used. Cloudflare tries to choose the requested codec, but we operate on a best-effort basis and there are limits that our system needs to follow to satisfy all customers. AVIF encoding, in particular, can be an order of magnitude slower than encoding to other formats. Cloudflare will fall back to WebP or JPEG if the image is too large to be encoded quickly. #### Limits per format Hard limits refers to the maximum image size to process. Soft limits refers to the limits existing when the system is overloaded. | File format | Hard limits on the longest side (width or height) | Soft limits on the longest side (width or height) | | ----------- | ------------------------------------------------- | ------------------------------------------------- | | AVIF | 1,200 pixels1 | 640 pixels | | Other | 12,000 pixels | N/A | | WebP | N/A | 2,560 pixels for lossy; 1920 pixels for lossless | 1Hard limit is 1,600 pixels when `format=avif` is explicitly used with [image transformations](/images/transform-images/). All images have to be less than 70 MB. The maximum image area is limited to 100 megapixels (for example, 10,000 x 10,000 pixels large). GIF/WebP animations are limited to a total of 50 megapixels (the sum of sizes of all frames). Animations that exceed this will be passed through unchanged without applying any transformations. Note that GIF is an outdated format and has very inefficient compression. High-resolution animations will be slow to process and will have very large file sizes. For video clips, Cloudflare recommends using [video formats like MP4 and WebM instead](/stream/). :::caution[Important] SVG files are passed through without resizing. This format is inherently scalable and does not need resizing. Cloudflare does not support the HEIC (HEIF) format and does not plan to support it. AVIF format is supported on a best-effort basis. Images that cannot be compressed as AVIF will be served as WebP instead. ::: #### Progressive JPEG While you can use the `format=jpeg` option to generate images in an interlaced progressive JPEG format, we will fallback to the baseline JPEG format for small and large images specified when: * The area calculated by width x height is less than 150 x 150. * The area calculated by width x height is greater than 3000 x 3000. For example, a 50 x 50 tiny image is always formatted by `baseline-jpeg` even if you specify progressive jpeg (`format=jpeg`). --- # Integrate with frameworks URL: https://developers.cloudflare.com/images/transform-images/integrate-with-frameworks/ ## Next.js Image transformations can be used automatically with the Next.js [`` component](https://nextjs.org/docs/api-reference/next/image). To use image transformations, define a global image loader or multiple custom loaders for each `` component. Next.js will request the image with the correct parameters for width and quality. Image transformations will be responsible for caching and serving an optimal format to the client. ### Global Loader To use Images with **all** your app's images, define a global [loaderFile](https://nextjs.org/docs/pages/api-reference/components/image#loaderfile) for your app. Add the following settings to the **next.config.js** file located at the root our your Next.js application. ```ts module.exports = { images: { loader: 'custom', loaderFile: './imageLoader.ts', }, } ``` Next, create the `imageLoader.ts` file in the specified path (relative to the root of your Next.js application). ```ts const normalizeSrc = (src: string) => { return src.startsWith("/") ? src.slice(1) : src; }; export default function cloudflareLoader({ src, width, quality, }: { src: string; width: number; quality?: number }) { if (process.env.NODE_ENV === "development") { return src; } const params = [`width=${width}`]; if (quality) { params.push(`quality=${quality}`); } const paramsString = params.join(","); return `/cdn-cgi/image/${paramsString}/${normalizeSrc(src)}`; } ``` ### Custom Loaders Alternatively, define a loader for each `` component. ```js import Image from 'next/image'; const normalizeSrc = src => { return src.startsWith('/') ? src.slice(1) : src; }; const cloudflareLoader = ({ src, width, quality }) => { if (process.env.NODE_ENV === "development") { return src; } const params = [`width=${width}`]; if (quality) { params.push(`quality=${quality}`); } const paramsString = params.join(','); return `/cdn-cgi/image/${paramsString}/${normalizeSrc(src)}`; }; const MyImage = props => { return ( Picture of the author ); }; ``` :::note For local development, you can enable [Resize images from any origin checkbox](/images/get-started/) for your zone. Then, replace `/cdn-cgi/image/${paramsString}/${normalizeSrc(src)}` with an absolute URL path: `https:///cdn-cgi/image/${paramsString}/${normalizeSrc(src)}` ::: --- # Make responsive images URL: https://developers.cloudflare.com/images/transform-images/make-responsive-images/ You can serve responsive images in two different ways: - Use the HTML `srcset` feature to allow browsers to choose the most optimal image. This is the most reliable solution to serve responsive images. - Use the `width=auto` option to serve the most optimal image based on the available browser and device information. This is a server-side solution that is supported only by Chromium-based browsers. ## Transform with HTML `srcset` The `srcset` [feature of HTML](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images) allows browsers to automatically choose an image that is best suited for user’s screen resolution. `srcset` requires providing multiple resized versions of every image, and with Cloudflare’s image transformations this is an easy task to accomplish. There are two different scenarios where it is useful to use `srcset`: * Images with a fixed size in terms of CSS pixels, but adapting to high-DPI screens (also known as Retina displays). These images take the same amount of space on the page regardless of screen size, but are sharper on high-resolution displays. This is appropriate for icons, thumbnails, and most images on pages with fixed-width layouts. * Responsive images that stretch to fill a certain percentage of the screen (usually full width). This is best for hero images and pages with fluid layouts, including pages using media queries to adapt to various screen sizes. ### `srcset` for high-DPI displays For high-DPI display you need two versions of every image. One for `1x` density, suitable for typical desktop displays (such as HD/1080p monitors or low-end laptops), and one for `2x` high-density displays used by almost all mobile phones, high-end laptops, and 4K desktop displays. Some mobile phones have very high-DPI displays and could use even a `3x` resolution. However, while the jump from `1x` to `2x` is a clear improvement, there are diminishing returns from increasing the resolution further. The difference between `2x` and `3x` is visually insignificant, but `3x` files are two times larger than `2x` files. Assuming you have an image `product.jpg` in the `assets` folder and you want to display it at a size of `960px`, the code is as follows: ```html ``` In the URL path used in this example, the `src` attribute is for images with the usual "1x" density. `/cdn-cgi/image/` is a special path for resizing images. This is followed by `width=960` which resizes the image to have a width of 960 pixels. `/assets/product.jpg` is a URL to the source image on the server. The `srcset` attribute adds another, high-DPI image. The browser will automatically select between the images in the `src` and `srcset`. In this case, specifying `width=1920` (two times 960 pixels) and adding `2x` at the end, informs the browser that this is a double-density image. It will be displayed at the same size as a 960 pixel image, but with double the number of pixels which will make it look twice as sharp on high-DPI displays. Note that it does not make sense to scale images up for use in `srcset`. That would only increase file sizes without improving visual quality. The source images you should use with `srcset` must be high resolution, so that they are only scaled down for `1x` displays, and displayed as-is or also scaled down for `2x` displays. ### `srcset` for responsive images When you want to display an image that takes a certain percentage of the window or screen width, the image should have dimensions that are appropriate for a visitor’s screen size. Screen sizes vary a lot, typically from 320 pixels to 3840 pixels, so there is not a single image size that fits all cases. With `` you can offer the browser several possible sizes and let it choose the most appropriate size automatically. By default, the browser assumes the image will be stretched to the full width of the screen, and will pick a size that is closest to a visitor’s screen size. In the `src` attribute the browser will pick any size that is a good fallback for older browsers that do not understand `srcset`. ```html ``` In the previous case, the number followed by `x` described *screen* density. In this case the number followed by `w` describes the *image* size. There is no need to specify screen density here (`2x`, etc.), because the browser automatically takes it into account and picks a higher-resolution image when necessary. If the image is not displayed at full width of the screen (or browser window), you have two options: * If the image is displayed at full width of a fixed-width column, use the first technique that uses one specific image size. * If it takes a specific percentage of the screen, or stretches to full width only sometimes (using CSS media queries), then add the `sizes` attribute as described below. #### The `sizes` attribute If the image takes 50% of the screen (or window) width: ```html ``` The `vw` unit is a percentage of the viewport (screen or window) width. If the image can have a different size depending on media queries or other CSS properties, such as `max-width`, then specify all the conditions in the `sizes` attribute: ```html ``` In this example, `sizes` says that for screens smaller than 640 pixels the image is displayed at full viewport width; on all larger screens the image stays at 640px. Note that one of the options in `srcset` is 1280 pixels, because an image displayed at 640 CSS pixels may need twice as many image pixels on a high-dpi (`2x`) display. ## WebP images `srcset` is useful for pixel-based formats such as PNG, JPEG, and WebP. It is unnecessary for vector-based SVG images. HTML also [supports the `` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture) that can optionally request an image in the WebP format, but you do not need it. Cloudflare can serve WebP images automatically whenever you use `/cdn-cgi/image/format=auto` URLs in `src` or `srcset`. If you want to use WebP images, but do not need resizing, you have two options: * You can enable the automatic [WebP conversion in Polish](/images/polish/activate-polish/). This will convert all images on the site. * Alternatively, you can change specific image paths on the site to start with `/cdn-cgi/image/format=auto/`. For example, change `https://example.com/assets/hero.jpg` to `https://example.com/cdn-cgi/image/format=auto/assets/hero.jpg`. ## Transform with `width` parameter When setting up a [transformation URL](/images/transform-images/transform-via-url/#width), you can apply the `width=auto` option to serve the most optimal image based on the available information about the user's browser and device. This method can serve multiple sizes from a single URL. Currently, images will be served in one of four sizes: - 1200 (large desktop/monitor) - 960 (desktop) - 768 (tablet) - 320 (mobile) Each width is counted as a separate transformation. For example, if you use `width=auto` and the image is delivered with a width of 320px to one user and 960px to another user, then this counts as two unique transformations. By default, this feature uses information from the user agent, which detects the platform type (for example, iOS or Android) and browser. ### Client hints For more accurate results, you can use client hints to send the user's browser information as request headers. This method currently works only on Chromium-based browsers such as Chrome, Edge, and Opera. You can enable client hints via HTML by adding the following tag in the `` tag of your page before any other elements: ```txt ``` Replace `https://example.com` with your Cloudflare zone where transformations are enabled. Alternatively, you can enable client hints via HTTP by adding the following headers to your HTML page's response: ```txt critical-ch: sec-ch-viewport-width, sec-ch-dpr permissions-policy: ch-dpr=("https://example.com"), ch-viewport-width=("https://example.com") ``` Replace `https://example.com` with your Cloudflare zone where transformations are enabled. --- # Preserve Content Credentials URL: https://developers.cloudflare.com/images/transform-images/preserve-content-credentials/ [Content Credentials](https://contentcredentials.org/) (or C2PA metadata) are a type of metadata that includes the full provenance chain of a digital asset. This provides information about an image's creation, authorship, and editing flow. This data is cryptographically authenticated and can be verified using an [open-source verification service](https://contentcredentials.org/verify). You can preserve Content Credentials when optimizing images stored in remote sources. ## Enable You can configure how Content Credentials are handled for each zone where transformations are served. In the Cloudflare dashboard under **Images** > **Transformations**, navigate to a specific zone and enable the toggle to preserve Content Credentials: ![Enable Preserving Content Credentials in the dashboard](~/assets/images/images/preserve-content-credentials.png) The behavior of this setting is determined by the [`metadata`](/images/transform-images/transform-via-url/#metadata) parameter for each transformation. For example, if a transformation specifies `metadata=copyright`, then the EXIF copyright tag and all Content Credentials will be preserved in the resulting image and all other metadata will be discarded. When Content Credentials are preserved in a transformation, Cloudflare will keep any existing Content Credentials embedded in the source image and automatically append and cryptographically sign additional actions. When this setting is disabled, any existing Content Credentials will always be discarded. --- # Serve images from custom paths URL: https://developers.cloudflare.com/images/transform-images/serve-images-custom-paths/ You can use Transform Rules to rewrite URLs for every image that you transform through Images. This page covers examples for the following scenarios: - Serve images from custom paths - Modify existing URLs to be compatible with transformations in Images - Transform every image requested on your zone with Images To create a rule, log in to the Cloudflare dashboard and select your account and website. Then, go to **Rules** > **Overview** and select **Create rule** next to **URL Rewrite Rules**. ## Before you start Every rule runs before and after the transformation request. If the path for the request matches the path where the original images are stored on your server, this may cause the request to fetch the original image to loop. To direct the request to the origin server, you can check for the string `image-resizing` in the `Via` header: `...and (not (any(http.request.headers["via"][*] contains "image-resizing")))` ## Serve images from custom paths By default, requests to transform images through Images are served from the `/cdn-cgi/image/` path. You can use Transform Rules to rewrite URLs. ### Basic version Free and Pro plans support string matching rules (including wildcard operations) that do not require regular expressions. This example lets you rewrite a request from `example.com/images` to `example.com/cdn-cgi/image/`: ```txt title="Text in Expression Editor" (starts_with(http.request.uri.path, "/images")) and (not (any(http.request.headers["via"][*] contains "image-resizing"))) ``` ```txt title="Text in Path > Rewrite to > Dynamic" concat("/cdn-cgi/image", substring(http.request.uri.path, 7)) ``` ### Advanced version :::note This feature requires a Business or Enterprise plan to enable regex in Transform Rules. Refer to [Cloudflare Transform Rules Availability](/rules/transform/#availability) for more information. ::: There is an advanced version of Transform Rules supporting regular expressions. This example lets you rewrite a request from `example.com/images` to `example.com/cdn-cgi/image/`: ```txt title="Text in Expression Editor" (http.request.uri.path matches "^/images/.*$") and (not (any(http.request.headers["via"][*] contains "image-resizing"))) ``` ```txt title="Text in Path > Rewrite to > Dynamic" regex_replace(http.request.uri.path, "^/images/", "/cdn-cgi/image/") ``` ## Modify existing URLs to be compatible with transformations in Images :::note This feature requires a Business or Enterprise plan to enable regex in Transform Rules. Refer to [Cloudflare Transform Rules Availability](/rules/transform/#availability) for more information. ::: This example lets you rewrite your URL parameters to be compatible with Images: ```txt (http.request.uri matches "^/(.*)\\?width=([0-9]+)&height=([0-9]+)$") ``` ```txt title="Text in Path > Rewrite to > Dynamic" regex_replace( http.request.uri, "^/(.*)\\?width=([0-9]+)&height=([0-9]+)$", "/cdn-cgi/image/width=${2},height=${3}/${1}" ) ``` Leave the **Query** > **Rewrite to** > _Static_ field empty. ## Pass every image requested on your zone through Images :::note This feature requires a Business or Enterprise plan to enable regular expressions in Transform Rules. Refer to [Cloudflare Transform Rules Availability](/rules/transform/#availability) for more information. ::: This example lets you transform every image that is requested on your zone with the `format=auto` option: ```txt (http.request.uri.path.extension matches "(jpg)|(jpeg)|(png)|(gif)") and (not (any(http.request.headers["via"][*] contains "image-resizing"))) ``` ```txt title="Text in Path > Rewrite to > Dynamic" regex_replace(http.request.uri.path, "/(.*)", "/cdn-cgi/image/format=auto/${1}") ``` --- # Transform via URL URL: https://developers.cloudflare.com/images/transform-images/transform-via-url/ import { Render, Tabs, TabItem } from "~/components" You can convert and resize images by requesting them via a specially-formatted URL. This way you do not need to write any code, only change HTML markup of your website to use the new URLs. The format is: ```txt https:///cdn-cgi/image// ``` Here is a breakdown of each part of the URL: * `` * Your domain name on Cloudflare. Unlike other third-party image resizing services, image transformations do not use a separate domain name for an API. Every Cloudflare zone with image transformations enabled can handle resizing itself. In URLs used on your website this part can be omitted, so that URLs start with `/cdn-cgi/image/`. * `/cdn-cgi/image/` * A fixed prefix that identifies that this is a special path handled by Cloudflare's built-in Worker. * `` * A comma-separated list of options such as `width`, `height`, and `quality`. * `` * An absolute path on the origin server, or an absolute URL (starting with `https://` or `http://`), pointing to an image to resize. The path is not URL-encoded, so the resizing URL can be safely constructed by concatenating `/cdn-cgi/image/options` and the original image URL. For example: `/cdn-cgi/image/width=100/https://s3.example.com/bucket/image.png`. Here is an example of an URL with `` set to `width=80,quality=75` and a `` of `uploads/avatar1.jpg`: ```html ``` ## Options You must specify at least one option. Options are comma-separated (spaces are not allowed anywhere). Names of options can be specified in full or abbreviated. ### `anim` ### `background` ### `blur` ### `border` ### `brightness` ### `compression` ### `contrast` ### `dpr` ### `fit` ### `flip` ### `format` ### `gamma` ### `gravity` ### `height` ### `metadata` ### `onerror` ### `quality` ### `rotate` ### `saturation` ### `sharpen` ### `trim` ### `width` ## Recommended image sizes Ideally, image sizes should match exactly the size they are displayed on the page. If the page contains thumbnails with markup such as ``, then images should be resized to `width=200`. If the exact size is not known ahead of time, use the [responsive images technique](/images/manage-images/create-variants/). If you cannot use the `` markup, and have to hardcode specific maximum sizes, Cloudflare recommends the following sizes: * Maximum of 1920 pixels for desktop browsers. * Maximum of 960 pixels for tablets. * Maximum of 640 pixels for mobile phones. Here is an example of markup to configure a maximum size for your image: ```txt /cdn-cgi/image/fit=scale-down,width=1920/ ``` The `fit=scale-down` option ensures that the image will not be enlarged unnecessarily. You can detect device type by enabling the `CF-Device-Type` header [via Cache Rule](/cache/how-to/cache-rules/examples/cache-device-type/). ## Caching Resizing causes the original image to be fetched from the origin server and cached — following the usual rules of HTTP caching, `Cache-Control` header, etc.. Requests for multiple different image sizes are likely to reuse the cached original image, without causing extra transfers from the origin server. :::note If Custom Cache Keys are used for the origin image, the origin image might not be cached and might result in more calls to the origin. ::: Resized images follow the same caching rules as the original image they were resized from, except the minimum cache time is one hour. If you need images to be updated more frequently, add `must-revalidate` to the `Cache-Control` header. Resizing supports cache revalidation, so we recommend serving images with the `Etag` header. Refer to the [Cache docs for more information](/cache/concepts/cache-control/#revalidation). Cloudflare Images does not support purging resized variants individually. URLs starting with `/cdn-cgi/` cannot be purged. However, purging of the original image's URL will also purge all of its resized variants. --- # Define source origin URL: https://developers.cloudflare.com/images/transform-images/sources/ When optimizing remote images, you can specify which origins can be used as the source for transformed images. By default, Cloudflare accepts only source images from the zone where your transformations are served. On this page, you will learn how to define and manage the origins for the source images that you want to optimize. :::note The allowed origins setting applies to requests from Cloudflare Workers. If you use a Worker to optimize remote images via a `fetch()` subrequest, then this setting may conflict with existing logic that handles source images. ::: ## How it works In the Cloudflare dashboard, go to **Images** > **Transformations** and select the zone where you want to serve transformations. To get started, you must have [transformations enabled on your zone](/images/get-started/#enable-transformations-on-your-zone). In **Sources**, you can configure the origins for transformations on your zone. ![Enable allowed origins from the Cloudflare dashboard](~/assets/images/images/allowed-origins.png) ## Allow source images only from allowed origins You can restrict source images to **allowed origins**, which applies transformations only to source images from a defined list. By default, your accepted sources are set to **allowed origins**. Cloudflare will always allow source images from the same zone where your transformations are served. If you request a transformation with a source image from outside your **allowed origins**, then the image will be rejected. For example, if you serve transformations on your zone `a.com` and do not define any additional origins, then `a.com/image.png` can be used as a source image, but `b.com/image.png` will return an error. To define a new origin: 1. From **Sources**, select **Add origin**. 2. Under **Domain**, specify the domain for the source image. Only valid web URLs will be accepted. ![Add the origin for source images in the Cloudflare dashboard](~/assets/images/images/add-origin.png) When you add a root domain, subdomains are not accepted. In other words, if you add `b.com`, then source images from `media.b.com` will be rejected. To support individual subdomains, define an additional origin such as `media.b.com`. If you add only `media.b.com` and not the root domain, then source images from the root domain (`b.com`) and other subdomains (`cdn.b.com`) will be rejected. To support all subdomains, use the `*` wildcard at the beginning of the root domain. For example, `*.b.com` will accept source images from the root domain (like `b.com/image.png`) as well as from subdomains (like `media.b.com/image.png` or `cdn.b.com/image.png`). 3. Optionally, you can specify the **Path** for the source image. If no path is specified, then source images from all paths on this domain are accepted. Cloudflare checks whether the defined path is at the beginning of the source path. If the defined path is not present at the beginning of the path, then the source image will be rejected. For example, if you define an origin with domain `b.com` and path `/themes`, then `b.com/themes/image.png` will be accepted but `b.com/media/themes/image.png` will be rejected. 4. Select **Add**. Your origin will now appear in your list of allowed origins. 5. Select **Save**. These changes will take effect immediately. When you configure **allowed origins**, only the initial URL of the source image is checked. Any redirects, including URLs that leave your zone, will be followed, and the resulting image will be transformed. If you change your accepted sources to **any origin**, then your list of sources will be cleared and reset to default. ## Allow source images from any origin When your accepted sources are set to **any origin**, any publicly available image can be used as the source image for transformations on this zone. **Any origin** is less secure and may allow third parties to serve transformations on your zone. --- # Transform via Workers URL: https://developers.cloudflare.com/images/transform-images/transform-via-workers/ import { Render } from "~/components" Using Cloudflare Workers to transform with a custom URL scheme gives you powerful programmatic control over every image request. Here are a few examples of the flexibility Workers give you: * **Use a custom URL scheme**. Instead of specifying pixel dimensions in image URLs, use preset names such as `thumbnail` and `large`. * **Hide the actual location of the original image**. You can store images in an external S3 bucket or a hidden folder on your server without exposing that information in URLs. * **Implement content negotiation**. This is useful to adapt image sizes, formats and quality dynamically based on the device and condition of the network. The resizing feature is accessed via the [options](/workers/runtime-apis/request/#the-cf-property-requestinitcfproperties) of a `fetch()` [subrequest inside a Worker](/workers/runtime-apis/fetch/). :::note You can use Cloudflare Images to sanitize SVGs but not to resize them. ::: ## Fetch options The `fetch()` function accepts parameters in the second argument inside the `{cf: {image: {…}}}` object. ### `anim` ### `background` ### `blur` ### `border` ### `brightness` ### `compression` ### `contrast` ### `dpr` ### `fit` ### `flip` ### `format` ### `gamma` ### `gravity` ### `height` ### `metadata` ### `onerror` ### `quality` ### `rotate` ### `saturation` ### `sharpen` ### `trim` ### `width` In your worker, where you would fetch the image using `fetch(request)`, add options like in the following example: ```js fetch(imageURL, { cf: { image: { fit: "scale-down", width: 800, height: 600 } } }) ``` These typings are also available in [our Workers TypeScript definitions library](https://github.com/cloudflare/workers-types). ## Configure a Worker Create a new script in the Workers section of the Cloudflare dashboard. Scope your Worker script to a path dedicated to serving assets, such as `/images/*` or `/assets/*`. Only supported image formats can be resized. Attempting to resize any other type of resource (CSS, HTML) will result in an error. :::caution[Warning] Do not set up the Image Resizing worker for the entire zone (`/*`). This will block all non-image requests and make your website inaccessible. ::: It is best to keep the path handled by the Worker separate from the path to original (unresized) images, to avoid request loops caused by the image resizing worker calling itself. For example, store your images in `example.com/originals/` directory, and handle resizing via `example.com/thumbnails/*` path that fetches images from the `/originals/` directory. If source images are stored in a location that is handled by a Worker, you must prevent the Worker from creating an infinite loop. ### Prevent request loops To perform resizing and optimizations, the Worker must be able to fetch the original, unresized image from your origin server. If the path handled by your Worker overlaps with the path where images are stored on your server, it could cause an infinite loop by the Worker trying to request images from itself. You must detect which requests must go directly to the origin server. When the `image-resizing` string is present in the `Via` header, it means that it is a request coming from another Worker and should be directed to the origin server: ```js addEventListener("fetch", event => { // If this request is coming from image resizing worker, // avoid causing an infinite loop by resizing it again: if (/image-resizing/.test(event.request.headers.get("via"))) { return fetch(event.request) } // Now you can safely use image resizing here } ``` ## Lack of preview in the dashboard :::note[Note] Image transformations are not simulated in the preview of in the Workers dashboard editor. ::: The script preview of the Worker editor ignores `fetch()` options, and will always fetch unresized images. To see the effect of image transformations you must deploy the Worker script and use it outside of the editor. ## Error handling When an image cannot be resized — for example, because the image does not exist or the resizing parameters were invalid — the response will have an HTTP status indicating an error (for example, `400`, `404`, or `502`). By default, the error will be forwarded to the browser, but you can decide how to handle errors. For example, you can redirect the browser to the original, unresized image instead: ```js const response = await fetch(imageURL, options) if (response.ok || response.redirected) { // fetch() may respond with status 304 return response } else { return response.redirect(imageURL, 307) } ``` Keep in mind that if the original images on your server are very large, it may be better not to display failing images at all, than to fall back to overly large images that could use too much bandwidth, memory, or break page layout. You can also replace failed images with a placeholder image: ```js const response = await fetch(imageURL, options) if (response.ok || response.redirected) { return response } else { // Change to a URL on your server return fetch("https://img.example.com/blank-placeholder.png") } ``` ## An example worker Assuming you [set up a Worker](/workers/get-started/guide/) on `https://example.com/image-resizing` to handle URLs like `https://example.com/image-resizing?width=80&image=https://example.com/uploads/avatar1.jpg`: ```js /** * Fetch and log a request * @param {Request} request */ export default { async fetch(request) { // Parse request URL to get access to query string let url = new URL(request.url) // Cloudflare-specific options are in the cf object. let options = { cf: { image: {} } } // Copy parameters from query string to request options. // You can implement various different parameters here. if (url.searchParams.has("fit")) options.cf.image.fit = url.searchParams.get("fit") if (url.searchParams.has("width")) options.cf.image.width = url.searchParams.get("width") if (url.searchParams.has("height")) options.cf.image.height = url.searchParams.get("height") if (url.searchParams.has("quality")) options.cf.image.quality = url.searchParams.get("quality") // Your Worker is responsible for automatic format negotiation. Check the Accept header. const accept = request.headers.get("Accept"); if (/image\/avif/.test(accept)) { options.cf.image.format = 'avif'; } else if (/image\/webp/.test(accept)) { options.cf.image.format = 'webp'; } // Get URL of the original (full size) image to resize. // You could adjust the URL here, e.g., prefix it with a fixed address of your server, // so that user-visible URLs are shorter and cleaner. const imageURL = url.searchParams.get("image") if (!imageURL) return new Response('Missing "image" value', { status: 400 }) try { // TODO: Customize validation logic const { hostname, pathname } = new URL(imageURL) // Optionally, only allow URLs with JPEG, PNG, GIF, or WebP file extensions // @see https://developers.cloudflare.com/images/url-format#supported-formats-and-limitations if (!/\.(jpe?g|png|gif|webp)$/i.test(pathname)) { return new Response('Disallowed file extension', { status: 400 }) } // Demo: Only accept "example.com" images if (hostname !== 'example.com') { return new Response('Must use "example.com" source images', { status: 403 }) } } catch (err) { return new Response('Invalid "image" value', { status: 400 }) } // Build a request that passes through request headers const imageRequest = new Request(imageURL, { headers: request.headers }) // Returning fetch() with resizing options will pass through response with the resized image. return fetch(imageRequest, options) } } ``` When testing image resizing, please deploy the script first. Resizing will not be active in the online editor in the dashboard. ## Warning about `cacheKey` Resized images are always cached. They are cached as additional variants under a cache entry for the URL of the full-size source image in the `fetch` subrequest. Do not worry about using many different Workers or many external URLs — they do not influence caching of resized images, and you do not need to do anything for resized images to be cached correctly. If you use the `cacheKey` fetch option to unify caches of multiple different source URLs, you must not add any resizing options to the `cacheKey`, as this will fragment the cache and hurt caching performance. The `cacheKey` option is meant for the full-size source image URL only, not for its resized variants. --- # Accept user-uploaded images URL: https://developers.cloudflare.com/images/upload-images/direct-creator-upload/ The Direct Creator Upload feature in Cloudflare Images lets your users upload images with a one-time upload URL without exposing your API key or token to the client. Using a direct creator upload also eliminates the need for an intermediary storage bucket and the storage/egress costs associated with it. You can set up [webhooks](/images/manage-images/configure-webhooks/) to receive notifications on your direct creator upload workflow. ## Request a one-time upload URL Make a `POST` request to the `direct_upload` endpoint using the example below as reference. :::note The `metadata` included in the request is never shared with end users. ::: ```bash curl --request POST \ https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v2/direct_upload \ --header "Authorization: Bearer " \ --form 'requireSignedURLs=true' \ --form 'metadata={"key":"value"}' ``` After a successful request, you will receive a response similar to the example below. The `id` field is a future image identifier that will be uploaded by a creator. ```json { "result": { "id": "2cdc28f0-017a-49c4-9ed7-87056c83901", "uploadURL": "https://upload.imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q/2cdc28f0-017a-49c4-9ed7-87056c83901" }, "result_info": null, "success": true, "errors": [], "messages": [] } ``` After calling the endpoint, a new draft image record is created, but the image will not appear in the list of images. If you want to check the status of the image record, you can make a request to the one-time upload URL using the `direct_upload` endpoint. ## Check the image record status To check the status of a new draft image record, use the one-time upload URL as shown in the example below. ```bash curl https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/{image_id} \ --header "Authorization: Bearer " ``` After a successful request, you should receive a response similar to the example below. The `draft` field is set to `true` until a creator uploads an image. After an image is uploaded, the draft field is removed. ```json { "result": { "id": "2cdc28f0-017a-49c4-9ed7-87056c83901", "metadata": { "key": "value" }, "uploaded": "2022-01-31T16:39:28.458Z", "requireSignedURLs": true, "variants": [ "https://imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q/2cdc28f0-017a-49c4-9ed7-87056c83901/public", "https://imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q/2cdc28f0-017a-49c4-9ed7-87056c83901/thumbnail" ], "draft": true }, "success": true, "errors": [], "messages": [] } ``` The backend endpoint should return the `uploadURL` property to the client, which uploads the image without needing to pass any authentication information with it. Below is an example of an HTML page that takes a one-time upload URL and uploads any image the user selects. ```html
``` By default, the `uploadURL` expires after 30 minutes if unused. To override this option, add the following argument to the cURL command: ```txt --data '{"expiry":"2021-09-14T16:00:00Z"}' ``` The expiry value must be a minimum of two minutes and maximum of six hours in the future. ## Direct Creator Upload with custom ID You can specify a [custom ID](/images/upload-images/upload-custom-path/) when you first request a one-time upload URL, instead of using the automatically generated ID for your image. Note that images with a custom ID cannot be made private with the [signed URL tokens](/images/manage-images/serve-images/serve-private-images) feature (`--requireSignedURLs=true`). To specify a custom ID, pass a form field with the name ID and corresponding custom ID value as shown in the example below. ```txt --form 'id=this/is/my-customid' ``` --- # Upload via batch API URL: https://developers.cloudflare.com/images/upload-images/images-batch/ The Images batch API lets you make several requests in sequence while bypassing Cloudflare’s global API rate limits. To use the Images batch API, you will need to obtain a batch token and use the token to make several requests. The requests authorized by this batch token are made to a separate endpoint and do not count toward the global API rate limits. Each token is subject to a rate limit of 200 requests per second. You can use multiple tokens if you require higher throughput to the Cloudflare Images API. To obtain a token, you can use the new `images/v1/batch_token` endpoint as shown in the example below. ```bash curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/batch_token" \ --header "Authorization: Bearer " # Response: { "result": { "token": "", "expiresAt": "2023-08-09T15:33:56.273411222Z" }, "success": true, "errors": [], "messages": [] } ``` After getting your token, use it to make requests for: - [Upload an image](/api/resources/images/subresources/v1/methods/create/) - `POST /images/v1` - [Delete an image](/api/resources/images/subresources/v1/methods/delete/) - `DELETE /images/v1/{identifier}` - [Image details](/api/resources/images/subresources/v1/methods/get/) - `GET /images/v1/{identifier}` - [Update image](/api/resources/images/subresources/v1/methods/edit/) - `PATCH /images/v1/{identifier}` - [List images V2](/api/resources/images/subresources/v2/methods/list/) - `GET /images/v2` - [Direct upload V2](/api/resources/images/subresources/v2/subresources/direct_uploads/methods/create/) - `POST /images/v2/direct_upload` These options use a different host and a different path with the same method, request, and response bodies. ```bash title="Request for list images V2 against api.cloudflare.com" curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v2" \ --header "Authorization: Bearer " ``` ```bash title="Example request using a batch token" curl "https://batch.imagedelivery.net/images/v1" \ --header "Authorization: Bearer " ``` --- # Upload images URL: https://developers.cloudflare.com/images/upload-images/ Cloudflare Images allows developers to upload images using different methods, for a wide range of use cases. ## Supported image formats You can upload the following image formats to Cloudflare Images: * PNG * GIF * JPEG * WebP (Cloudflare Images also supports uploading animated WebP files) * SVG :::note Cloudflare Images does not support the HEIC (HEIF) format. ::: ## Dimensions and sizes These are the maximum allowed sizes and dimensions Cloudflare Images supports: * Maximum image dimension is 12,000 pixels. * Maximum image area is limited to 100 megapixels (for example, 10,000×10,000 pixels). * Image metadata is limited to 1024 bytes. * Images have a 10 megabyte (MB) size limit. * Animated GIFs/WebP, including all frames, are limited to 50 megapixels (MP). --- # Upload via URL URL: https://developers.cloudflare.com/images/upload-images/upload-url/ Before you upload an image, check the list of [supported formats and dimensions](/images/upload-images/#supported-image-formats) to confirm your image will be accepted. You can use the Images API to use a URL of an image instead of uploading the data. Make a `POST` request using the example below as reference. Keep in mind that the `--form 'file='` and `--form 'url='` fields are mutually exclusive. :::note The `metadata` included in the request is never shared with end users. ::: ```bash curl --request POST \ https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1 \ --header "Authorization: Bearer " \ --form 'url=https://[user:password@]example.com/' \ --form 'metadata={"key":"value"}' \ --form 'requireSignedURLs=false' ``` After successfully uploading the image, you will receive a response similar to the example below. ```json { "result": { "id": "2cdc28f0-017a-49c4-9ed7-87056c83901", "filename": "image.jpeg", "metadata": { "key": "value" }, "uploaded": "2022-01-31T16:39:28.458Z", "requireSignedURLs": false, "variants": [ "https://imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q/2cdc28f0-017a-49c4-9ed7-87056c83901/public", "https://imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q/2cdc28f0-017a-49c4-9ed7-87056c83901/thumbnail" ] }, "success": true, "errors": [], "messages": [] } ``` If your origin server returns an error while fetching the images, the API response will return a 4xx error. --- # Upload via dashboard URL: https://developers.cloudflare.com/images/upload-images/upload-dashboard/ Before you upload an image, check the list of [supported formats and dimensions](/images/upload-images/#supported-image-formats) to confirm your image will be accepted. To upload an image from the Cloudflare dashboard: 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. Select **Images**. 3. Drag and drop your image into the **Quick Upload** section. Alternatively, you can select **Drop images here** or browse to select your image locally. 4. After the upload finishes, your image appears in the list of files. --- # Upload via custom path URL: https://developers.cloudflare.com/images/upload-images/upload-custom-path/ You can use a custom ID path to upload an image instead of the path automatically generated by Cloudflare Images’ Universal Unique Identifier (UUID). Custom paths support: * Up to 1,024 characters. * Any number of subpaths. * The [UTF-8 encoding standard](https://en.wikipedia.org/wiki/UTF-8) for characters. :::note Images with custom ID paths cannot be made private using [signed URL tokens](/images/manage-images/serve-images/serve-private-images). Additionally, when [serving images](/images/manage-images/serve-images/), any `%` characters present in Custom IDs must be encoded to `%25` in the image delivery URLs. ::: Make a `POST` request using the example below as reference. You can use custom ID paths when you upload via a URL or with a direct file upload. ```bash curl --request POST https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1 \ --header "Authorization: Bearer " \ --form 'url=https://' \ --form 'id=' ``` After successfully uploading the image, you will receive a response similar to the example below. ```json { "result": { "id": "", "filename": "", "uploaded": "2022-04-20T09:51:09.559Z", "requireSignedURLs": false, "variants": ["https://imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q//public"] }, "result_info": null, "success": true, "errors": [], "messages": [] } ``` --- # Upload via a Worker URL: https://developers.cloudflare.com/images/upload-images/upload-file-worker/ You can use a Worker to upload your image to Cloudflare Images. Refer to the example below or refer to the [Workers documentation](/workers/) for more information. ```ts const API_URL = "https://api.cloudflare.com/client/v4/accounts//images/v1"; const TOKEN = ""; const image = await fetch("https://example.com/image.png"); const bytes = await image.bytes(); const formData = new FormData(); formData.append('file', new File([bytes], 'image.png')); const response = await fetch(API_URL, { method: 'POST', headers: { 'Authorization': `Bearer ${TOKEN}`, }, body: formData, }); ``` ## Upload from AI generated images You can use an AI Worker to generate an image and then upload that image to store it in Cloudflare Images. For more information about using Workers AI to generate an image, refer to the [SDXL-Lightning Model](/workers-ai/models/stable-diffusion-xl-lightning). ```ts const API_URL = "https://api.cloudflare.com/client/v4/accounts//images/v1"; const TOKEN = "YOUR_TOKEN_HERE"; const stream = await env.AI.run( "@cf/bytedance/stable-diffusion-xl-lightning", { prompt: YOUR_PROMPT_HERE } ); const bytes = await (new Response(stream)).bytes(); const formData = new FormData(); formData.append('file', new File([bytes], 'image.jpg'); const response = await fetch(API_URL, { method: 'POST', headers: { 'Authorization': `Bearer ${TOKEN}`, }, body: formData, }); ``` --- # Serve images URL: https://developers.cloudflare.com/images/manage-images/serve-images/ import { DirectoryListing } from "~/components" --- # Serve images from custom domains URL: https://developers.cloudflare.com/images/manage-images/serve-images/serve-from-custom-domains/ Image delivery is supported from all customer domains under the same Cloudflare account. To serve images through custom domains, an image URL should be adjusted to the following format: ```txt https://example.com/cdn-cgi/imagedelivery/// ``` Example with a custom domain: ```txt https://example.com/cdn-cgi/imagedelivery/ZWd9g1K7eljCn_KDTu_MWA/083eb7b2-5392-4565-b69e-aff66acddd00/public ``` In this example, ``, `` and `` are the same, but the hostname and prefix path is different: - `example.com`: Cloudflare proxied domain under the same account as the Cloudflare Images. - `/cdn-cgi/imagedelivery`: Path to trigger `cdn-cgi` image proxy. - `ZWd9g1K7eljCn_KDTu_MWA`: The Images account hash. This can be found in the Cloudflare Images Dashboard. - `083eb7b2-5392-4565-b69e-aff66acddd00`: The image ID. - `public`: The variant name. ## Custom paths By default, Images are served from the `/cdn-cgi/imagedelivery/` path. You can use Transform Rules to rewrite URLs and serve images from custom paths. ### Basic version Free and Pro plans support string matching rules (including wildcard operations) that do not require regular expressions. This example lets you rewrite a request from `example.com/images` to `example.com/cdn-cgi/imagedelivery/`. To create a rule: 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account and website. 2. Go to **Rules** > **Overview**. 3. Next to **URL Rewrite Rules**, select **Create rule**. 4. Under **If incoming requests match**, select **Wildcard pattern** and enter the following **Request URL** (update with your own domain): ```txt https://example.com/images/* ``` 5. Under **Then rewrite the path and/or query** > **Path**, enter the following values (using your account hash): - **Target path**: [`/`] `images/*` - **Rewrite to**: [`/`] `cdn-cgi/imagedelivery//${1}` 6. Select **Deploy** when you are done. ### Advanced version :::note This feature requires a Business or Enterprise plan to enable regular expressions in Transform Rules. Refer to Cloudflare [Transform Rules Availability](/rules/transform/#availability) for more information. ::: This example lets you rewrite a request from `example.com/images/some-image-id/w100,h300` to `example.com/cdn-cgi/imagedelivery//some-image-id/width=100,height=300` and assumes Flexible variants feature is turned on. To create a rule: 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account and website. 2. Go to **Rules** > **Overview**. 3. Next to **URL Rewrite Rules**, select **Create rule**. 4. Under **If incoming requests match**, select **Custom filter expression** and then select **Edit expression**. 5. In the text field, enter `(http.request.uri.path matches "^/images/.*$")`. 6. Under **Path**, select **Rewrite to**. 7. Select _Dynamic_ and enter the following in the text field. ```txt regex_replace( http.request.uri.path, "^/images/(.*)\\?w([0-9]+)&h([0-9]+)$", "/cdn-cgi/imagedelivery//${1}/width=${2},height=${3}" ) ``` ## Limitations When using a custom domain, it is not possible to directly set up WAF rules that act on requests hitting the `/cdn-cgi/imagedelivery/` path. If you need to set up WAF rules, you can use a Cloudflare Worker to access your images and a Route using your domain to execute the worker. For an example worker, refer to [Serve private images using signed URL tokens](/images/manage-images/serve-images/serve-private-images/). --- # Serve private images URL: https://developers.cloudflare.com/images/manage-images/serve-images/serve-private-images/ You can serve private images by using signed URL tokens. When an image requires a signed URL, the image cannot be accessed without a token unless it is being requested for a variant set to always allow public access. 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account. 2. Select **Images** > **Keys**. 3. Copy your key and use it to generate an expiring tokenized URL. :::note Private images do not currently support custom paths. ::: The example below uses a Worker that takes in a regular URL without a signed token and returns a tokenized URL that expires after one day. You can, however, set this expiration period to whatever you need, by changing the const `EXPIRATION` value. ```js const KEY = 'YOUR_KEY_FROM_IMAGES_DASHBOARD'; const EXPIRATION = 60 * 60 * 24; // 1 day const bufferToHex = buffer => [...new Uint8Array(buffer)].map(x => x.toString(16).padStart(2, '0')).join(''); async function generateSignedUrl(url) { // `url` is a full imagedelivery.net URL // e.g. https://imagedelivery.net/cheeW4oKsx5ljh8e8BoL2A/bc27a117-9509-446b-8c69-c81bfeac0a01/mobile const encoder = new TextEncoder(); const secretKeyData = encoder.encode(KEY); const key = await crypto.subtle.importKey( 'raw', secretKeyData, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'] ); // Attach the expiration value to the `url` const expiry = Math.floor(Date.now() / 1000) + EXPIRATION; url.searchParams.set('exp', expiry); // `url` now looks like // https://imagedelivery.net/cheeW4oKsx5ljh8e8BoL2A/bc27a117-9509-446b-8c69-c81bfeac0a01/mobile?exp=1631289275 const stringToSign = url.pathname + '?' + url.searchParams.toString(); // for example, /cheeW4oKsx5ljh8e8BoL2A/bc27a117-9509-446b-8c69-c81bfeac0a01/mobile?exp=1631289275 // Generate the signature const mac = await crypto.subtle.sign('HMAC', key, encoder.encode(stringToSign)); const sig = bufferToHex(new Uint8Array(mac).buffer); // And attach it to the `url` url.searchParams.set('sig', sig); return new Response(url); } export default { async fetch(request, env, ctx): Promise { const url = new URL(event.request.url); const imageDeliveryURL = new URL( url.pathname.slice(1).replace('https:/imagedelivery.net', 'https://imagedelivery.net') ); return generateSignedUrl(imageDeliveryURL); }, } satisfies ExportedHandler; ``` --- # Serve uploaded images URL: https://developers.cloudflare.com/images/manage-images/serve-images/serve-uploaded-images/ To serve images uploaded to Cloudflare Images, you must have: * Your Images account hash * Image ID * Variant or flexible variant name Assuming you have at least one image uploaded to Images, you will find the basic URL format from the Images dashboard under Developer Resources. ![Developer Resources section within the Images product form the Cloudflare Dashboard.](~/assets/images/images/image-delivery-url.png) A typical image delivery URL looks similar to the example below. `https://imagedelivery.net///` In the example, you need to replace `` with your Images account hash, along with the `` and ``, to begin serving images. You can select **Preview** next to the image you want to serve to preview the image with an Image URL you can copy. The link will have a fully formed **Images URL** and will look similar to the example below. In this example: * `ZWd9g1K7eljCn_KDTu_MWA` is the Images account hash. * `083eb7b2-5392-4565-b69e-aff66acddd00` is the image ID. You can also use Custom IDs instead of the generated ID. * `public` is the variant name. When a user requests an image, Cloudflare Images chooses the optimal format, which is determined by client headers and the image type. ## Optimize format Cloudflare Images automatically transcodes uploaded PNG, JPEG and GIF files to the more efficient AVIF and WebP formats. This happens whenever the customer browser supports them. If the browser does not support AVIF, Cloudflare Images will fall back to WebP. If there is no support for WebP, then Cloudflare Images will serve compressed files in the original format. Uploaded SVG files are served as [sanitized SVGs](/images/upload-images/). --- # Credentials URL: https://developers.cloudflare.com/images/upload-images/sourcing-kit/credentials/ To migrate images from Amazon S3, Sourcing Kit requires access permissions to your bucket. While you can use any AWS Identity and Access Management (IAM) user credentials with the correct permissions to create a Sourcing Kit source, Cloudflare recommends that you create a user with a narrow set of permissions. To create the correct Sourcing Kit permissions: 1. Log in to your AWS IAM account. 2. Create a policy with the following format (replace `` with the bucket you want to grant access to): ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:Get*", "s3:List*" ], "Resource": [ "arn:aws:s3:::", "arn:aws:s3:::/*" ] } ] } ``` 3. Next, create a new user and attach the created policy to that user. You can now use both the Access Key ID and Secret Access Key to create a new source in Sourcing Kit. Refer to [Enable Sourcing Kit](/images/upload-images/sourcing-kit/enable/) to learn more. --- # Edit sources URL: https://developers.cloudflare.com/images/upload-images/sourcing-kit/edit/ The Sourcing Kit main page has a list of all the import jobs and sources you have defined. This is where you can edit details for your sources or abort running import jobs. ## Source details You can learn more about your sources by selecting the **Sources** tab on the Sourcing Kit dashboard. Use this option to rename or delete your sources. 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login), and select your account. 2. Go to **Images** > **Sourcing Kit**. 3. Select **Sources** and choose the source you want to change. 4. In this page you have the option to rename or delete your source. Select **Rename source** or **Delete source** depending on what you want to do. ## Abort import jobs While Cloudflare Images is still running a job to import images into your account, you can abort it before it finishes. 1. Log in to the [ Cloudflare dashboard](https://dash.cloudflare.com/login), and select your account. 2. Go to **Images** > **Sourcing Kit**. 3. In **Imports** select the import job you want to abort. 4. The next page shows you a summary of the import. Select **Abort**. 5. Confirm that you want to abort your import job by selecting **Abort** on the dialog box. --- # Enable Sourcing Kit URL: https://developers.cloudflare.com/images/upload-images/sourcing-kit/enable/ Enabling Sourcing Kit will set it up with the necessary information to start importing images from your Amazon S3 account. ## Create your first import job 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login), and select your account. 2. Go to **Images** > **Sourcing Kit**. 3. Select **Import images** to create an import job. 4. In **Source name** give your source an appropriate name. 5. In **Amazon S3 bucket information** enter the S3's bucket name where your images are stored. 6. In **Required credentials**, enter your Amazon S3 credentials. This is required to connect Cloudflare Images to your source and import your images. Refer to [Credentials](/images/upload-images/sourcing-kit/credentials/) to learn more about how to set up credentials. 7. Select **Next**. 8. In **Basic rules** define the Amazon S3 path to import your images from, and the path you want to copy your images to in your Cloudflare Images account. This is optional, and you can leave these fields blank. 9. On the same page, in **Overwrite images**, you need to choose what happens when the files in your source change. The recommended action is to copy the new images and overwrite the old ones on your Cloudflare Images account. You can also choose to skip the import, and keep what you already have on your Cloudflare Images account. 10. Select **Next**. 11. Review and confirm the information regarding the import job you created. Select **Import images** to start importing images from your source. Your import job is now created. You can review the job status on the Sourcing Kit main page. It will show you information such as how many objects it found, how many images were imported, and any errors that might have occurred. :::note Sourcing Kit will warn you when you are about to reach the limit for your plan space quota. When you exhaust the space available in your plan, the importing jobs will be aborted. If you see this warning on Sourcing Kit’s main page, select **View plan** to change your plan’s limits. ::: ## Define a new source 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login), and select your account. 2. Go to **Images** > **Sourcing Kit**. 3. Select **Import images** > **Define a new source**. Repeat steps 4-11 in [Create your first import job](#create-your-first-import-job) to finish setting up your new source. ## Define additional import jobs You can have many import jobs from the same or different sources. If you select an existing source to create a new import job, you will not need to enter your credentials again. 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login), and select your account. 2. Go to **Images** > **Sourcing Kit**. 3. Select **Import images**. 4. Choose from one of the sources already configured. Repeat steps 8-11 in [Create your first import job](#create-your-first-import-job) to finish setting up your new import job. ## Next steps Refer to [Edit source details](/images/upload-images/sourcing-kit/edit/) to learn more about editing details for import jobs you have already created, or to learn how to abort running import jobs. --- # Upload via Sourcing Kit URL: https://developers.cloudflare.com/images/upload-images/sourcing-kit/ With Sourcing Kit you can define one or multiple repositories of images to bulk import from Amazon S3. Once you have these set up, you can reuse those sources and import only new images to your Cloudflare Images account. This helps you make sure that only usable images are imported, and skip any other objects or files that might exist in that source. Sourcing Kit also lets you target paths, define prefixes for imported images, and obtain error logs for bulk operations. Sourcing Kit is available in beta. If you have any comments, questions, or bugs to report, contact the Images team on our [Discord channel](https://discord.cloudflare.com). You can also engage with other users and the Images team on the [Cloudflare Community](https://community.cloudflare.com/c/developers/images/63). ## When to use Sourcing Kit Sourcing Kit can be a good choice if the Amazon S3 bucket you are importing consists primarily of images stored using non-archival storage classes, as images stored using [archival storage classes](https://aws.amazon.com/s3/storage-classes/#Archive) will be skipped and need to be imported separately. Specifically: * Images stored using S3 Glacier tiers (not including Glacier Instant Retrieval) will be skipped and logged in the migration log. * Images stored using S3 Intelligent Tiering and placed in Deep Archive tier will be skipped and logged in the migration log. ---