Hola! 😀
Have you come across a use case where you wanted to display/share some images(or other file types), stored as Salesforce Files, outside of Salesforce?
Salesforce lets you handle this very effectively using the Content Delivery object; API Name: ContentDistribution.
To expose a file publicly, you can simply create a record on ContentDistribution object with a link to the respective ContentVersion Id.
Once you create a record of ContentDistribution type, there are 2 fields that get auto populated namely; DistributionPublicUrl and ContentDownloadUrl.
Both these fields contains a URL to expose the file as a public resource. If you’re wondering what’s the difference…
DistributionPublicUrl contains the URL of the shared file that can be previewed within a container. And it looks something like this:

This URL let’s you preview and download the file. However, if you wish to use it in a img tag to preview an image type file, it won’t work.
So how do we make it work?
Meet ContentDownloadUrl field.
ContentDownloadUrl contains the URL of the shared file that lets you directly download the file. And you can use this URL in img tag as source(src) to display the file.
Cool, right?
What’s even more cool is ContentDistribution object tracks a bunch of other useful things as well, for example, ViewCount, FirstViewDate, LastViewDate. You can even make the shared file password protected!
You’d also create multiple ContentDistribution records for same file if you want track some stats based on different places where it’s being exposed.
And there is bunch of other stuff you can do with this object, check here.
How to create the ContentDistribution object record?
You can use the ‘Public Link’ quick action on File page, Apex or Flow to do this.
Using Public Link Quick action:

When the link is generated, behind the scenes, a ContentDistribution object record is created.
NOTE: The link that gets generated is the DistributionPublicUrl. So you’d need to query the ContentDownloadUrl separately if you want to use it as ‘source’ URL.
Using Apex:
/* Getting ContentVersion file using ContentDocument Id */
ContentVersion file = [SELECT Id, Title FROM ContentVersion WHERE ContentDocumentId = '<Content Document ID>'].Id;
/* Creating ContentDistribution record */
insert new ContentDistribution(
Name = file.Title,
ContentVersionId = file.Id,
PreferencesAllowViewInBrowser= true
);
Using Flow:

SIDE NOTE: You can also use ContentAsset(Asset files) to expose the file as public resource however, that is slightly more complicated than this approach! 🙂
Hope you find this useful. Catch you in the next one! ✌
Thank you for being an awesome reader! Subscribe to ForcePanda to receive all the latest updates straight to your inbox. 🙂
Once the public URL is generated, I would like to convert the urls to images so that the images can be embedded into email templates. Could you please let me know if that is possible?
LikeLike
You’d embed the images in your email template simply by using tag, no?
Because converting the url back into image doesn’t make sense, unless I’m missing something.
LikeLike
Pingback: From Josh Dayment – Flow iFrame Lightning Web Component – UnofficialSF
Pingback: From Josh Dayment – Flow iFrame Lightning Web Component – UnofficialSF
I need to Fetch ContentDownloadUrl from ContentDistribution in Custom object Field so that I can Add this in the Email Template Please Help me ASAP!! (For That DO I have to Write AfterIntsert Trigger on ContentDocumentLink??) and How to save file DownloadLink URL in Object Custom Field
LikeLike
You can fire an async process that fires when a content doc is created.
LikeLike
sObject type ‘ContentDistribution’ is not supported. I keep getting this error. What to do?
LikeLike
I think you need to enable CRM related permissions for the org/user. I’m not sure which permissions exactly are they.
LikeLike
I am trying to access this via a SOQL query in the context of a guest user. I have enabled Content Deliveries and Public Links can be enabled to let communities users share files managed by libraries (Requires Content Deliveries) but other than that I dont see any other option. Is this accessible to guest users?
LikeLike
Are running the apex in without sharing context?
LikeLike
with sharing context
LikeLike
with sharing context
LikeLike
Sigh! I found the answer here https://salesforce.stackexchange.com/questions/238514/guest-license-users-cannot-access-contentdistribution-object-anymore Guest users cant access this object unless I run the query in without sharing mode. But thanks for your attention and replies.
LikeLike
Glad you found it already.
Yes, you need to run the Apex in “God mode” i.e. without sharing context to access the object. Be careful with it’s usage though.
LikeLike
Pingback: How to derive a direct link to a file from the link to the download page? – GrindSkills
Can this approach be used in the following scenario?
I have authenticated community users uploading their company logo to their account as a file. I want to use that logo in SF CMS so I can display the logo they uploaded along with other public info. I have a field on the account to hold the url for the image source for the cms collection.
LikeLike
Yes, you should be able to do it.
LikeLike
How can i get the preview URL for the content document for authorized user? I understand that we need this object to expose to public. But i want to create a custom page which shows the files and clicking on it should show the file preview.
LikeLike
You can do something of this sort.
https://forcepanda.wordpress.com/2020/08/04/flow-screen-component-salesforce-files-preview/
LikeLike
How do I get the public url and set it to a field from a Salesforce flow? Can this be automatically done on a record creation? We have an existing automation in which a Salesforce Contract record gets made with attachments. I’d like to get the public url of these attachments and store it as a field value.
LikeLike
You have to first create the content distribution record and then use the public distribution url field from that record.
LikeLike
Hi ForcePanda,
I am facing an issue. If I set PreferencesPasswordRequired as true then ContentDownloadURL is not being generated. Any idea why? Or any suggestions to workaround this?
Here’s simple piece of code which I executed in anonymous window –
insert new contentDistribution(
name = ‘testFile’,
contentVersionId = ‘0688M000000LAYJQA4’,
PreferencesAllowViewInBrowser = true,
PreferencesPasswordRequired = true,
ExpiryDate = system.now().addDays(7),
PreferencesExpires=true,
PreferencesAllowOriginalDownload = true,
PreferencesAllowPDFDownload = true
);
Thanks!
LikeLike
Partner users should view images displayed on a formula field that contains ContentDownloadUrl. The image displays correctly in Salesforce, but partner users cannot see it in the Experience cloud site.
I tested using the image address URL (actual image location) in the formula and this is the only way it works for both Salesforce org and the site. The problem is that I have to click on the image to get this URL.
Is there any way to build the actual image location with a flow?
Thanks!
LikeLike