Is it possible to disable JSdelivr CDN?

Is it possible to use Ghost without loading any third party services? This includes JSDELIVR. We do not want to load a CDN. Privacy Badger by the Electronic Frontier Foundation flags JSDELIVR as a potential tracker on our site even though we disabled memebership signups, the portal and we deleted all code in our theme that is related to search functionality.

We are self-hosting Ghost and we use a modified version of the journal theme. Until recently it was possible to use Ghost without loading any external sources. As mentioned in the beginning, we disabled the signup portal and we have no code in our theme that relates to search functionality. In consequence we expected no CDN would be injected. This was not the case. But in Ghost version 5.4.0 it was still possible to disable UNPKG CDN by deleting these lines in the configuration file (versions/5.4.0/core/shared/config/defaults.json):

"sodoSearch": {
    "url": "",
    "version": "1.0.0"

Since Ghost version 5.5.0 UNPKG has been replaced with JSDELIVR. We tried to proceed the same way and we removed sodoSearch from the configuration file (versions/5.7.0/core/shared/config/defaults.json):

"sodoSearch": {
    "url": "{version}/umd/sodo-search.min.js",
    "styles": "{version}/umd/main.css",
    "version": "1.1"

However doing so did break our Ghost installation. I.e.: code injection in the site header stopped to work.

This indicates to us that JSDELIVR is not only used for Membership features and search functionality (as indicated in the privacy declaration of ghost: Ghost/ at main · TryGhost/Ghost · GitHub), but that other important features of a ghost installation now rely on JSDELIVR as well.

For the time being we downgraded our Ghost installations to version 5.4.0. For us and for some of our customers it is not an option to use a CDN that gets flagged by the EFF as a potential tracker. We do have customers who don’t want to use extternal sources at all and who require us to host all fonts, scripts, libraries, etc. locally.

We would very much like to keep using Ghost because we think it is great software! Is there any way to use Ghost without loading JSDELIVR and without breaking core functionality like code injection?

jsDelivr hosts the JavaScript libraries used by your site. Moreover, it doesn’t set any cookies—you can check yourself using Developer tools in your browser or read their Privacy Policy—so isn’t a privacy concern.

Indeed, in my experience, these privacy checking sites are often unreliable and give false or misleading reports with a view to selling a package. It’s straightforward to see what your sites does from your own browser.

If you do want to remove jsDelvr, you’ll have to host the resources yourself, and routinely maintain them, so they are up-to-date (running older code is a potential security risk.)

updated based on Hannah’s feedback

At this time, it’s not possible to fully disable search, but you should be able to self-host, or hackily disable it.

In your config.production.json (note: unless absolutely necessary, you shouldn’t modify the installed version of ghost, including the defaults.json config file), add the following:

"sodoSearch": {
  "url": "/assets/sodo-xxx.js",
  "styles": "/assets/sodo-xxx.css"

If you want to hackily not even load the script, you can try making both URLs empty - though I haven’t tried it and that might not work.

The same thing applies to portal, but instead of sodoSearch, you’ll use portal

  • Note: If you’re using memberships, even if you’re not using the portal FAB, you might need to load the script still - otherwise if your theme or newsletters link to any portal pages, they won’t work.
  • I know this doesn’t apply to you, but just a word of caution :slight_smile:

Hey! Thanks a lot for your quick response and thanks for pointing us in the right direction.

Just to clarify: it is not the case the we have a problem with CDN’s in general. As soon as someone wants to implement membership features, newsletter, etc. we always recommend to stick with the standard installation and don’t temper with the configuration.

It is good though to have the choice though and there are some people who do like Ghost as a publishing platform because it is so easy to quickly build a good looking website, but who don’t want to use it as a way to earn revenue (no memberships, no portal, etc.), but rather as a simple blog or portfolio page - and in this context we have been asked if it was possible to stop loading any external sources.

We know that updates are important and we are aware about security risks when running old code…

Thank you for pointing us in the right direction!

We did make a mistake - we did try to download the sources, host them locally but instead of loading them via the defaults.json configuration file we tried to integrate them in the theme. Still learning…

Just to confirm: both approaches work - when we host the code locally everything works fine, but also the hacky approach (empty url’s) in the defaults.json file does not break the site.

And yes - we are aware, as soon as we want to use the membership feature (which in general is a great feature), we might have to reintegrate the scripts. Thanks again!

This is not quite right, the config “url” not “scriptUrl”:

"sodoSearch": {
  "url": "/assets/sodo-xxx.js",
  "styles": "/assets/sodo-xxx.css"

Additionally you can disable the feature entirely by passing a false or empty url:

"sodoSearch": {
   "url": false

:warning: these changes should always go in your config.[environment].json as mentioned by Vikas - modifying default.json will require you to re-make the change on every upgrade.

Thanks a lot for your feedback. We’ve implemented the required changes in the config.[environment].json and eveything works as we want it to. Thank you.

1 Like

I’m curious as to why, when I add the below code…

…to my config.development.json like so…

  "url": "",
  "server": {
    "port": 2392,
    "host": ""
  "database": {
    "client": "sqlite3",
    "connection": {
      "filename": "/home/ghostpub/MAIN/content/data/ghost-local.db"
  "mail": {
    "transport": "Direct"
  "logging": {
    "transports": [
  "sodoSearch": {
    "url": false
  "process": "local",
  "paths": {
    "contentPath": "/home/ghostpub/MAIN/content"

…this entire block disappears, instead of just the sodo-search line…

<script defer src="" data-key="e175038f22e70858d91bf59224" data-styles="" data-sodo-search="" crossorigin="anonymous"></script>
<script defer src="[/public/cards.min.js?v=35e87b3f7b]("></script>
<link rel="stylesheet" type="text/css" href="[/public/cards.min.css?v=35e87b3f7b](">

I’ve tried it on several of my sites (on version 5.15.0) including one with Casper v5.3.1

This breaks {{ghost_head}} helper as it expects this config value to be a string and will crash if it isn’t.

Using a blank space to completely disable the loading the script in the config file works fine like this:

  "sodoSearch": {
    "url": " ",
    "styles": " "

You might also want to hide the search icon, so add this to the site header in code injection

.gh-search { display: none; }
1 Like

Thank you @UnrealDavid this worked for me.

Just in case, it’s all on the docs:

On the last paragraphs you can see sodosearch and portal variables to play.

When disable sodo-search it will disbale ghost head on single post as well. It’s the bug.

Looks like this whole thread relates to the self-hosted version of Ghost. Is there a way to completely disable the loading of the sodo-search.js script in a hosted Ghost Pro? I don’t use search in my blog and would like to save some Lighthouse/PageSpeed points by disabling script loading.

1 Like

bumping the thread, I am looking to do similar to @yetithefoot.

Lighthouse/PageSpeed Mobile checks claims I can get a potential 2-second improvement if I disable sodo-search + stripe.
I would like to at least disable them for the home.hbs, if possible.

(I am on Ghost pro as well, so the above options are not accessible for me)

Yes. You’d need a custom theme that doesn’t call ghost_head.

1 Like

jsDelivr hosts the JavaScript libraries used by your site. Moreover, it doesn’t set any cookies—you can check yourself using Developer tools in your browser or read their Privacy Policy —so isn’t a privacy concern.

It leaks your IP which already is enough to qualify as privacy concern. Furthermore they may be behind a service like Cloudflare in which case the IP is not only leaked to jsdeliver but potentially other services.

Also: even if jsdeliver has best intention in mind, as there has been many incidents in the past such as modified npm modules Ledger web3 hack, this is not only a privacy concern but also relevant for security.

I install that stuff into content/public/

I’ve made a new package for that: