Explore tab empty in Ghost admin interface (explore URLs return 404s)

I recently had the issue with one of my blogs that the “Explore” tab under “Network” in the Ghost admin UI was completely empty. In the logs I saw that all explore URLs are returning 404s. So I decided to set up a Ghost test instance from scratch, using the same tech stack (Traefik, Docker, self-hosted AP) to see if I can reproduce the issue. And I can!

It looks like activitypub itself is set up correctly, but every url /.ghost/activitypub/v1/explore/* is delivering a 404:

activitypub  | 12:40:49.868 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:40:49.876 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' '313a34b8-ee3f-4b8b-9338-49e4ec2fe6df' 200 8ms
activitypub  | 12:40:49.928 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/notifications' '6bc165ba-565a-43ed-a74d-6d79897cbbe2'
activitypub  | 12:40:49.928 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:40:49.940 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/notifications' '6bc165ba-565a-43ed-a74d-6d79897cbbe2' 200 12ms
activitypub  | 12:40:49.995 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/notifications/unread/count' '27100a32-4b55-4ae3-9348-92d6b65cd65c'
activitypub  | 12:40:49.996 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:40:50.005 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/notifications/unread/count' '27100a32-4b55-4ae3-9348-92d6b65cd65c' 200 10ms
activitypub  | 12:40:51.036 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/accounts' '5076fdcf-2fbe-4358-9c6b-60657035f293'
activitypub  | 12:40:51.036 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:40:51.044 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/accounts' '5076fdcf-2fbe-4358-9c6b-60657035f293' 200 8ms
activitypub  | 12:40:51.099 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' '6f362c52-2a6b-46f3-9272-54c6bc2b995b'
activitypub  | 12:40:51.100 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:40:51.107 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' '6f362c52-2a6b-46f3-9272-54c6bc2b995b' 200 8ms
activitypub  | 12:40:51.160 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/feed/reader' '8d4a443e-046e-4a89-9151-223cf3f42f21'
activitypub  | 12:40:51.160 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:40:51.174 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/feed/reader' '8d4a443e-046e-4a89-9151-223cf3f42f21' 200 14ms
activitypub  | 12:40:51.178 ERR activitypub: Error updating interaction counts for post with ID 1: 'post-is-internal'
activitypub  | 12:41:00.428 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/accounts' 'd837db7a-caea-4188-b3ae-b83d2f3cbf10'
activitypub  | 12:41:00.428 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:41:00.436 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/accounts' 'd837db7a-caea-4188-b3ae-b83d2f3cbf10' 200 8ms
activitypub  | 12:41:00.487 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' '76658603-614c-42a4-951f-f1a753ca0970'
activitypub  | 12:41:00.488 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:41:00.496 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' '76658603-614c-42a4-951f-f1a753ca0970' 200 9ms
activitypub  | 12:41:00.548 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/feed/notes' '9cd2cdd6-c129-43ed-ae8d-47194cfdba26'
activitypub  | 12:41:00.548 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:41:00.559 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/feed/notes' '9cd2cdd6-c129-43ed-ae8d-47194cfdba26' 200 11ms
activitypub  | 12:41:00.562 ERR activitypub: Error updating interaction counts for post with ID 2: 'post-is-internal'
activitypub  | 12:41:04.450 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/accounts' '732b3e75-1bd9-4c4e-aed0-7a52b2a46bb1'
activitypub  | 12:41:04.450 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:41:04.458 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/accounts' '732b3e75-1bd9-4c4e-aed0-7a52b2a46bb1' 200 8ms
activitypub  | 12:41:04.510 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' '978f17c5-5902-4785-98c9-9c89ecb18d2b'
activitypub  | 12:41:04.510 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:41:04.519 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' '978f17c5-5902-4785-98c9-9c89ecb18d2b' 200 9ms
activitypub  | 12:41:05.941 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/accounts' '3481f72f-a810-44d3-8692-44d8ae122979'
activitypub  | 12:41:05.942 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:41:05.950 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/accounts' '3481f72f-a810-44d3-8692-44d8ae122979' 200 9ms
activitypub  | 12:41:06.010 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' 'de5abada-fca7-4844-aa16-439e3acefe7b'
activitypub  | 12:41:06.010 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:41:06.017 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' 'de5abada-fca7-4844-aa16-439e3acefe7b' 200 7ms
activitypub  | 12:41:06.982 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/accounts' '5464e595-e7fa-4763-ad0d-7b5d23ba955b'
activitypub  | 12:41:06.983 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:41:06.991 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/accounts' '5464e595-e7fa-4763-ad0d-7b5d23ba955b' 200 9ms
activitypub  | 12:41:07.051 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' '8166856b-6c36-41dd-95f1-1264fb3d2fd1'
activitypub  | 12:41:07.051 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:41:07.058 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/blocks/domains' '8166856b-6c36-41dd-95f1-1264fb3d2fd1' 200 8ms
activitypub  | 12:41:07.108 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/explore/top' '029198af-f3b6-4185-a1b9-7d46b5ada3b7'
activitypub  | 12:41:07.108 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:41:07.115 WRN fedify·federation·http: 'GET' '/.ghost/activitypub/v1/explore/top': 404
activitypub  | 12:41:07.116 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/explore/top' '029198af-f3b6-4185-a1b9-7d46b5ada3b7' 404 7ms
activitypub  | 12:42:06.314 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/explore/tech' 'dfed69d6-71ec-447e-ae93-8528197954ce'
activitypub  | 12:42:06.315 INF activitypub: KnexKvStore: Get key cachedJwks,staticvoid.blog
activitypub  | 12:42:06.321 WRN fedify·federation·http: 'GET' '/.ghost/activitypub/v1/explore/tech': 404
activitypub  | 12:42:06.321 INF activitypub: 'GET' 'staticvoid.blog' 'https://staticvoid.blog/.ghost/activitypub/v1/explore/tech' 'dfed69d6-71ec-447e-ae93-8528197954ce' 404 7ms

The page just remains empty:

I think it worked on one of my old blogs before. Now it does not seem to work at all anymore. Can someone point me into the right direction how to debug this? Or is this maybe expected behaviour because I am using a self-hosted ActivityPub service, instead of ap.ghost.org?

It is indeed because of that.

The Explore data is local, so for a single-user AP instance it won’t make much sense, in my eyes. Essentially, there was a migration last month that added a new table to the MySQL database: account_topics:

There is a job that was added that can be used to populate the information:

It does rely on an external API providing the sites though – so, it’s entirely purpose built for Ghost(Pro). Fair game – they are developing this.

What I have done at Magic Pages was rather simple. I took all site names and URL that are using ActivityPub on my server, fetched their home page and asked a local LLM to categorize them in the Explore topics. That information is then saved in the MySQL table.

Works for Magic Pages with hundreds of sites. But quite honestly, for self-hosted instances that is complete overkill and the Explore view – in it’s current form – is pretty useless, given that it doesn’t connect to other Ghost sites (which then again…also has advantages).

4 Likes

I just set up the self hosted activitypub myself finally and noticed the same. so it sounds like the ghost explore and reader sections is similar to what you would see in the federated timeline of a mastodon instance

1 Like

Thank you so, so, much! That explains it all perfectly. That means that the “Explore” section is not really relevant for self-hosted installations that are also using a self-hosted AP instances. Some more documentation would definitely help to explain it better.

I think I had the wrong impression of the ActivityPub service. I thought that it was kind of feature complete and “all batteries included” to have your own independent Ghost blog that has everything it needs to federate. With that in mind, I did not expect that the “Explore” view would depend on some form of external service or API to not have a blank page.

Of course it makes complete sense for Ghost Pro in a product sense and solves a lot of problems that were outlined in the last Changelog post. Maybe it would make sense to not display certain entries in the UI if one is using their own AP service. That way that would be less confusing. :thinking:

1 Like

same here, though in its current form it does enable quite a bit of interaction capabilities to the fediverse from a central point. for a restaurant ghost instance i manage this will allow them to be followed and seen by anyone using an activitypub service like mastodon, bluesky, and others, and they can have it all in one spot in ghost without having to sign up for another service. pretty awesome stuff.

1 Like

Maybe it would make sense to not display certain entries in the UI if one is using their own AP service.

yep - we’ll work on updating this so it makes more sense for self hosted AP instances too

1 Like