Cloudflare Images has a lot of issues

I’m a huge fan of the various Cloudflare offerings, and have been impressed time after time with the innovations and solutions offered by CF. This writeup therefore pains me, as I usually don’t have anything negative to say about CF, but after some months in production, and a severe lack of any meaningful reply from the CF Images team addressing any of these concerns (you won’t find a single official response in any of the linked community posts), I find it necessary to inform about some aspects of CF Images that I frankly find both surprising, concerning and disappointing. I will update this list when issues have been addressed.

Update 2022-03-15: The CF Team added a fix for “6. “Direct Creator Upload” is essentially useless” the 15th of February
Update 2022-03-16: The CF Team added a fix for “2. No way to track how many images has been served”, though I’m not certain when. This was brought to my attention by Discord user k8s (thanks!) on the CF Developers Discord

Issues

1. Incredibly confusing and nonsensical pricing in a CF context

Links: “Cloudflare Images Now Available to Everyone”, “AWS’s Egregious Egress”, “Bandwidth Alliance”, Community post 1, Community post 2, Community post 3, Community post 4

CF has a track record of creating services that both work incredibly well, in addition to being supremely cost-effective. Furthermore, they seem to be on a mission to eliminate egress fees with the “Bandwidth Alliance”, while also making direct statements towards AWS for their “Egregious Egress”, and in the product announcement for CF Images they write this (emphasis mine):

Egress cost is the cost of getting your data out of a storage provider. The most common case being when you serve an image from storage you pay for the bits transmitted. And you end up paying every, single time that same image is displayed.

The thing is, with CF Images you do end up paying every, single time that same image is displayed, as the pricing clearly states literally 2 paragraphs later (emphasis mine):

You pay $5/month for every 100,000 stored images and $1 per 100,000 delivered images

To add insult to injury, one can only assume that requests hitting the CDN also counts, as it’s still a “delivered image”, and they nowhere mention that this isn’t the case. Not only this, but since you pay per image instead of for bandwidth, you will end up paying more for small images (eg. 50kB = $0.20 per GB) than you would using AWS.

2. No way to track how many images has been served

Update 2022-03-16: The CF Team added information about images served to the CF Images dashboard, though I’m not certain when. This was brought to my attention by Discord user k8s (thanks!) on the CF Developers Discord

Links: Community post 1 (by me), Community post 2, Community post 3

You’re given a clear overview of how many images you have uploaded, but unlike with eg. CF Workers, there is no way to tell how many requests have been made, other than the line item when the invoice arrives. The one tool you have to get some information about this, is setting up usage notifications/alerts at certain thresholds, but this quickly becomes spammy if you want fine-grained information.

3. No way to retrieve original image

Links: Community Post, “AWS’s Egregious Egress”

The heading says it all. There is currently no way at all to retrieve the original and unmodified file, meaning you also have no way to migrate to another platform if you want. In the CF post “AWS’s Egregious Egress” linked above, they write this:

The only rationale we can reasonably come up with for AWS’s egress pricing: locking customers into their cloud, and making it prohibitively expensive to get customer data back out. So much for being customer-first.

Since there is no way to retrieve the original image from CF Images, customers are completely locked into their cloud. Even worse than AWS, where it’s “prohibitively expensive” to get your data, it’s actually impossible to get data back out from CF Images.

4. Missing CORS header on the served images

Links: Community post 1, Community post 2, Community Post 3

All images served through CF Images for some reason lack a CORS header, meaning that you cannot do things like using them on a canvas, in a WebGL context, or an anchor tag with the download attribute. This seems like a strange oversight.

In cases where you are serving images to only your own domain, Images can now be served directly from your custom domain. https://my.domain/cdn-cgi/imagedelivery/ where PATH is the path you usually use on imagedelivery.net.

https://developers.cloudflare.com/images/cloudflare-images/serve-images#serving-images-from-custom-domains

If you need to serve images to other or unknown domains, you will need to bypass this yourself with something like a CF Worker.

5. Lack of dynamic resizing, only 20 “variants” allowed

Links: Community post

For whatever reason, CF Images is limited to 20 “variants”, ie. size + mode of resizing, and there is no option to have more, nor is there an option to enable query-based resizing parameters. This might make sense for applications where you know all sizes in advance, but CF Images also supports what they call “Direct creator uploads”, which are one-time URL’s you can create, that allows your user to directly upload to CF Images without needing to pipe it through your server. This is all well and good, but requires you to do any custom or user-defined cropping on the client side, and you’ll lose image information permanently when uploading the already cropped image to CF Images. This means that the user can’t decide to later change the crop without re-uploading the image, which is both impractical and a waste of space and bandwidth.

6. “Direct Creator Upload” is essentially useless

Update 2022-03-15: The CF Team added a fix for this the 15th of February 2022

Links: Direct Creator Upload in the docs, Community post (by me), Community post 2 (by me)

To expand on the “Direct creator upload” mentioned above, I haven’t actually found out how to use it in a single meaningful way, while I’d really like to. The flow goes like this:

  1. Request a one-time upload URL from the CF API and return it to the user
    • This contains an id and an uploadURL
  2. The user uploads an image with the given uploadURL

This works great, but while this technically does the job of allowing a user to make an upload directly to CF Images, there is no way to know whether or not the upload succeeded, nor what the final id and the resulting image URL is, without being told by and blindly trusting the client.

There are no webhooks for CF Images (like for CF Stream), so my first instinct to work around this was to store the id received from the CF API in the server-side request, and have the user ping the server when their upload was complete. I could then use the CF API once again to fetch the image using the original id and verify that the image was indeed uploaded successfully. This, unfortunately, does not work, as the id from the CF API differs from the final id of the uploaded image.

I’m sure I’ve severely misunderstood something, but I’d very much like to know how somebody would use this is a production setting, where you cannot trust the client, and need to be able to track usage, as well as have the possibility to delete user data.

7. Size limit of 10MB, with no option to increase it

This one seems arbitrarily low, as you’d want the highest quality you could get when resizing images. In the HN thread for the product launch, it’s mentioned that this is a starting default, and that they can support larger sizes. Hopefully this will be changed to something like 25MB at some point.

8. No way to perform batch deletions of images

Links: Community post (by me)

There is currently no way to delete more than 1 image at a time using the CF API, requiring you to build your own solution for this, making sure that you stay under the CF API rate limit of 1,200 requests per 5 minutes - which goes for your entire applications usage of the CF API.

9. You’re left to patch some of these things yourself

By using a simple CF Worker you can get proper CORS-headers, and actual caching of images. Doing this, you will both get expected functionality (CORS-headers), as well as reduced cost by the images being properly cached.

Thing is, you’re using a CF service to do this, doing something that by itself shouldn’t be necessary, but more importantly - if the cost can be reduced by doing this yourself, one would assume that the cost could be even further reduced if this was implemented by CF.

Conclusion

So, is CF Images a bad product? No, by no means, but given all of the above issues, it seems both incomplete and rushed. I have not even the slightest ounce of insight into what kind of administrative and architectural processes goes into making a product of this complexity and scale, so I’m in no position to say if these are things that can or even should be fixed. Also, given that the product is at an early stage, it’s subject to a lot of change and improvements.

I do wish they called it a beta, though, and I do wish that CF really put their money where their mouth is, and actually made CF Images more affordable than AWS, and provided a way to retrieve the original images to prevent vendor lock-in - especially with their very public criticism of their competitor for these very same reasons.

Lastly, I hope that this list very quickly becomes outdated, and that I soon can edit all of them with descriptions of how they’ve been solved or addressed by the CF team.

Thanks and further discussion

Thank you for reading this! I would love to hear your thoughts and ideas too. Join the discussion on Hacker News, or feel free to email me at <firstname>@klungo.no, or DM me on Twitter