Sign in

Spectral Web Services

@cathy.spectralwebservices.com.ap.brid.gy
7 followers 0 following 224 posts

Let our team handle the technology, while you focus on creating. Ghost CMS experts. 🌉 bridged from www.spectralwebservices.com on the fediverse by fed.brid.gy

PostsRepliesMedia
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 14h
🚨 WDYBTW: Check your JWKS handling now: Ghost rotates signing keys What did you break this week, week of 2026-09-24 www.spectralwebservices.com/blog/wd…
spectralwebservices.com
🚨 WDYBTW: Check your JWKS handling now: Ghost rotates signing keys
What did you break this week, week of 2026-09-24
001
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 15h
🚨 WDYBTW: Check comment widgets reading post.excerpt from Members API What did you break this week, week of 2026-09-17 www.spectralwebservices.com/blog/wd…
spectralwebservices.com
🚨 WDYBTW: Check comment widgets reading post.excerpt from Members API
What did you break this week, week of 2026-09-17
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 30/09/2026
Today: Stood up a Turnstile-protected sign-up form for Ghost. Turned off free memberships to block the attackers from hitting the API directly, of course. But that meant no send-magic-links endpoint, so THEN I stood up a whole token service to send my own magic links, only creating Ghost users […]
spectralwebservices.com
Original post on spectralwebservices.com
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 29/09/2026
I am going to be the queen of embed-card-workaround things DataWrapper, Flourish, LinkedIn, custom image layouts, and did I mention it all syndicates to Apple News? www.spectralwebservices.com/blog/i-…
spectralwebservices.com
I am going to be the queen of embed-card-workaround things
DataWrapper, Flourish, LinkedIn, custom image layouts, and did I mention it all syndicates to Apple News?
012
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 29/09/2026
So... is the Mailgun flex plan gone? I asked about it over here: forum.ghost.org/t/sept-2026-mailgun… and got no replies. I still have one. I think lots of self-hosters do, but if it isn't possible to sign up and cancel to get on it, that changes the math on getting a small […]
spectralwebservices.com
Original post on spectralwebservices.com
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 24/09/2026
Today: Password protected pages for Ghost. Should I roll it out to the toolbox? Anyone interested?
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 23/09/2026
Tap tap tap. Is this thing on? I published a post and got this note. No more full text on the Fediverse. www.spectralwebservices.com/blog/ta…
spectralwebservices.com
Tap tap tap. Is this thing on?
Testing some new functionality.
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 23/09/2026
Random thought of the evening. My self-hosted Ghost posts to ActivityPub via webhook. There's a proxy I control in the middle of that. I control the proxy. Hmm... I think my self-hosted Ghost might just start publishing notes instead of full articles...
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 22/09/2026
Little Green Light <-> Ghost integration. Working? Now we watch the money come in...
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 12/09/2026
What embeds do you wish worked in Ghost newsletters and Activity Pub but don't? :)
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 08/09/2026
"A slow sort of country!" said the Queen. "Now, here, you see, it takes all the running you can do, to keep in the same place. If you want to get somewhere else, you must run at least twice as fast as that!" (Lewis Carroll) Feels a propos at the moment. Trying to speed up db queries faster than […]
spectralwebservices.com
Original post on spectralwebservices.com
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 07/09/2026
Making #contentFor and block deduplicate a page with tag-based content sections
spectralwebservices.com
Avoiding duplicates on complicated homepages
Many themes have a big hero section up top, followed by some later sections with posts that are selected based on their tags. (Examples include Ghost official theme Headline, plus nearly every theme in the "News" section of the theme directory.) Inevitably the client doesn't want duplicates between the top section and the lower sections, and wants lots of control over the top section. This is where things get complicated. Here's a better way to avoid duplicates than I've seen in many themes. ## Keeping hero posts out of the tag sections further down a Ghost homepage The obvious fix is to exclude the hero's post ids in each section's `filter`. The catch is how `{{#get}}` resolves the placeholders inside its filter string. It looks them up against the current Handlebars context only, with its own simple path lookup. Inside a `{{#foreach}}` over tags, the context is the tag, so `{{slug}}` works, but anything computed elsewhere on the page is out of reach. There is no `../` allowed in filters. And even if you solve the `../` with nested partials (more below), having to nest everything within the `#get` that produces the hero section can get messy and confusing fast. ### The pieces Three things make it work, and they have to nest in a particular way. **1. The hero records its post ids with`contentFor`.** Ghost has the `contentFor` and `block` pair, which many themes use to get information "up" to `default.hbs` from within a template. But here, we turn things around a bit. The hero partial writes the ids into a named block, and it writes them as a complete filter clause. {{!-- partials/hero.hbs --}} {{!-- This part sets the "hero_posts_filter" block. It renders nothing here. --}} {{#if posts}}{{#contentFor "hero_posts_filter"}}+id:-[{{#foreach posts limit="3"}}{{#unless @first}},{{/unless}}{{id}}{{/foreach}}]{{/contentFor}}{{/if}} {{!-- This is the actual loop that handles the cards in the hero section --}} <section class="hero"> {{#foreach posts limit="3"}} {{> post-card}} {{/foreach}} </section> My hero has three posts, retrieved with a {{#get}} request not shown in this snippet. (It might be filtered by tag, or featured status, or publication date, or some combination. Whatever we're using, we're inside that context. If the hero renders nothing, the block resolves to an empty string and the filter is unchanged. That's important for part 2, below. **2. The template reads the block back as a partial parameter.** `block` is a normal helper, so it works as a subexpression in a partial call. Hash parameters on a partial become properties of the partial's context, which is exactly where `{{#get}}` looks. The hero has to appear earlier in the template than the sections so the block is filled before it is read: {{!-- home.hbs --}} {{> hero}} {{#get "tags" filter="slug:[{{@custom.section_tags}}]" limit="10"}} {{#foreach tags}} {{> tag-section extra_filter=(block "hero_posts_filter")}} {{/foreach}} {{/get}} **3. The tag-section partial reconstitutes the filter.** Because the partial was called with the tag as context, `{{slug}}` and `{{extra_filter}}` are both plain properties of `this`, and the filter can use them side by side. Inside the `get`, the context switches to the posts, so the tag's own fields need `../`: {{!-- partials/tag-section.hbs --}} {{#get "posts" filter="primary_tag:{{slug}}{{extra_filter}}" include="tags,authors" limit="4"}} {{#if posts}} <section class="tag-section"> <h2>{{../name}}</h2> {{#foreach posts}} {{> post-card}} {{/foreach}} <a href="{{../url}}">More {{../name}}</a> </section> {{/if}} {{/get}} ### Why the nesting is the whole trick, and the best trick The nested partials are required. Don't simplify. The partial call turns the block value into a context property, so the `#get` can use it for filtering. * * * ## So what about duplicates between tag sections? Easiest fix, and visible above: I'm filtering by primary tag, not tag. That's a guaranteed no duplicates between tag sections, since a post has exactly one primary tag. A more complicated fix would require passing in the ids of the first tag section into the second tag section. It _is_ possible to write this sort of recursion into Ghost, but that's more complexity than I needed here. * * * Hey, before you go... If your finances allow you to keep this tea-drinking ghost and the freelancer behind her supplied with our hot beverage of choice, we'd both appreciate it! Buy me a tea ☕️
010
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 06/09/2026
Finally got organized about feedback: spectralwebservices.featurebase.app
spectralwebservices.featurebase.app
Feedback - Spectral Web Services
Give Spectral Web Services feedback on how they could improve their product.
001
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 06/09/2026
When you build a landing page and sidebar menu for half a dozen tools, it's hard to get it too wrong. When you then grow to 23 tools, things can get a leeeeeetle out of hand. Launching a revised interface for the Spectral Web Services toolbox app. Hoping it's more navigable, or at least that […]
spectralwebservices.com
Original post on spectralwebservices.com
100
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 05/09/2026
Yesterday. Ordered take-out, received Mexican food without chips. Tonight. Ordered Italian, including our fav sauteed broccoli and garlic. Received steamed broccoli. Might have to give up and cook tomorrow. Bah.
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 05/09/2026
Earlier this week, Haunts picked up some French strings, and along with it, new date localization support. (More complicated than one might wish, since it's both parsing incoming dates in weird formats AND writing them out in multiple formats for display, and there's a mix of python and js, so […]
spectralwebservices.com
Original post on spectralwebservices.com
100
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 03/09/2026
It all started with a client problem.
spectralwebservices.com
I accidentally built an image library for Ghost
I was chatting with a staff member from a newsroom moving from WP to Ghost. She said something off-hand about not having found the Ghost image library yet, and that was when she realized there wasn't one. Her face fell. It was clear that she thought this was a major disaster. That they'd failed to ask if there was an image library, because why wouldn't there be? That they wouldn't have chosen to move to Ghost, knowing this. Yikes. We'd been working on moving this site for a while. The content was moved, with multiple rounds of revisions for hard-to-move bits, manual editing, and a bunch of code. I'd implemented advanced search, a republish tracker, and a bunch of other customizations. Oh, and did I mention the Paypal integration, and a sync with Little Green Light? A _lot_ of work had gone into this site. While trying to save the day, I suggested that she could search with the new advanced search widget (since we'd already indexed her content), and while it didn't exclusively search captions, the search did include captions, and maybe it'd be a good stopgap. We tried it, and it sort of worked, but of course the caption probably doesn't tell you that a picture is of a cornfield specifically, and their alt text (which would have made cornfields searchable) was spotty at best. I thought about that a little more, and why _not_ have an index with just the image data? If you're already handling all the content parsing and sync for post content, what's capturing a few image urls, captions, and alt text? I got from that to a first working version pretty quickly: An early version of the image library tool Loading content into Algolia also gave me a chance to add a couple extra fields, so that the team could track photographer and some searchable notes ("cornfield"). And you can see the leading edge of what can eventually be a folder organization system for photos. Those of you who've had small children in your lives in the last few decades probably remember "If you give a mouse a cookie", in which a small request for a cookie spirals out of control. I got to the screenshot above in a couple hours, since almost everything I needed already existed in my advanced search package. And then things got a little out of control. First off, my site's been online for years, and like most Ghost users, when I need an image, I upload it again. And again. Sometimes even more than once per post. So, for the tool to be useful for existing sites, some deduplication was necessary. Here's the dedupe tool in action, using file names to propose likely duplicates. There's also a manual option to select images and mark them as the same. Deduplication of images The dedupe tool doesn't do anything to the images on Ghost, but it collapses their appearance on the main image library page, making scanning through the images and updating metadata much more reasonable. Of course, at the point where you have an image library with searchable captions and alt text, then you notice that you are missing a lot of alt text. So it'd be nice if the tool would let you fix it, right? So I built that. It wouldn't have been all that complicated, except that I had just collapsed all those duplicates, so that made the dashboard look great and at the cost of everything being slightly more complex under the hood. And although some types of images in Ghost (i.e. in the image card) can have alt text, others cannot. (Looking at you, product card!) And of course, I'm parsing Lexical, because parsing html is lossy. (The Apple News integration work pays off in unexpected ways. I'm now really good at parsing Lexical.) And back to different cards with images. Having only a copy button for images wasn't really enough, because what if you wanted the image in a product card, or header, or whatever? So the button needed a dropdown. That's right, the copy button doesn't just copy the image. It puts a whole Ghost card on the clipboard, so that you can paste in the image with caption and alt text already populated. Want your image in a sign up card? No problem. And somewhere in there, the cards got too complicated, so now there are separate modes (with different card fields visible) for using, fixing accessibility, or organizing photos. Oh, and the user might want to load the images into Image Library first, rather than waiting for the sync to add the metadata. So I added an upload button (stolen from the popup builder for Ghost). And of course, having an image manager with all the images on the site makes it pretty easy to see what images are not loading. So then I added an image replacer, for the situation where an embedded logo on dozens of posts that was hotloading from a partner's website could be replaced when it went AWOL. And yeah. That's how it went. Image from If You Give a Mouse a Cookie, by Laura Numeroff, illustrated by Felicia Bond. If you'd like to try out the Image Library, you can find it (and a ton of other useful tools) over at the Spectral Web Services toolbox. Image Library — search every image you’ve published to Ghost | SWS ToolsEvery image in your Ghost posts and pages, searchable by caption, alt text and filename. Credit the photographer, fill in missing alt text, replace an image everywhere it ran, and paste a ready-made image card back into the editor.Spectral Web Services
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 02/09/2026
Guess what I'm doing today?
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 02/09/2026
Time to update some Ghost navigation menus to use the new icons!
110
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 30/08/2026
Those of you who's parented probably remember "If you give a mouse a cookie", in which a small request spirals out of control. I had an epiphany on Friday that I wasn't "too far" from a functional image library for Ghost, which I kicked out pretty quickly. But then I wanted it to make fixing alt […]
spectralwebservices.com
Original post on spectralwebservices.com
101
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 30/08/2026
Of course, if you already have half a dozen copies of some images, getting alt text on them is annoying. So then we need a dedupe. (Doesn't remove anything from your blog, just cleans up your image library view.)
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 29/08/2026
Yeah, it turns out that an image library is most of the way to an alt text fixing tool... But first, I need to be able to deduplicate images, the direct result of NOT having a media library. Sigh.
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 29/08/2026
And then, having gotten to that point, it occurs to me that an image library is a good start on a tool to fix alt text on images.... and...
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 28/08/2026
Sneak peek.
211
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 24/08/2026
Up to mischief, like usual...
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 23/08/2026
Did a little mucking around and cut query times by 50-70%. As my kids would say: Haunts pages go brrrr. (Joins. Too many joins...)
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 23/08/2026
The goal is always hands-off and it just works, but...
spectralwebservices.com
Troubleshooting Haunts feeds
Haunts checks out all your local haunts each day, to see what's new, what's changed, and occasionally what's been cancelled. This will ideally happen without any help from you or me. When you visit your Haunts dashboard, you'll hopefully see row after row of ✅. This means Haunts ran, found events, and everything is good. Nothing to see here (although if you want to see what it found, just click the title). Occasionally, you might see a ⚠️ symbol. That means something went wrong, although it's often just an internet hiccup that resolves on rerun. If you beat me to it, feel free to hit the refresh button, which often resolves the problem. Otherwise, I'll investigate in the morning while drinking my ☕. The spot that can most use your attention is any feed marked as ❓. These are sources that didn't give an error, but didn't give any events either. These are the hardest to deal with. Is the source broken, or is it just off-season for whatever this source. I added a number of feeds this summer for school boards and small colleges. There were spring events, so I'm fairly optimistic there will be fall events once the students return, but they've been ❓all summer. If you see a venue that definitely has events in the next two months, but is still ❓, please flag it for me. It's really hard for my automations to tell the difference between "website got rearranged and the wizard needs a re-run" _vs_. "no student art shows until late fall". If you notice you're missing events, here's how you can help: 1. Visit the website and make sure there really are events at that source. 2. If there are, copy the website url and drop it into the wizard. 3. Let the wizard run and create a new haunt. Wait ~2 minutes while the events are retrieved. (The hourglass next to the event will disappear when done.) 4. If your new haunt has events, then you can remove the old haunt, and the problem is solved. 5. Problem not solved? Look for the 🚩button to tell me I need to take a look. ## What's new with Haunts? * Added a "mini" embed that sits nicely in your sidebar. Find the embed code in your 'setup' tab. * Improved settings for the newsletter-ready copy and paste block in the 'export' tab. If you send a weekly newsletter, this thing should save you some time! (And if you need a different format, please let me know!) * Added a button to make it easier to report a feed problem. * Added more grouping for recurring events, making it easier to feature/hide/edit every occurrence at once. * Added the ability to block an unwanted image (i.e. Zoom or Instagram logos getting used as event images). * Added geolocation labels – if you'd like your events categorized by city/county/state/country, we can do that now! (Paid feature.) * Added some new layout options, including week view. Find these under 'setup'. * Fixed WP Events Calendar ingestion to get the full window, not just the first 30 events. * Added the ability to recognize and ingest several additional calendar types in use in school, music venues, and more. * Added yet another Google calendar detection pattern. * Added an "ask your own AI" option for building scrapers. If you try the wizard and it fails, give it a shot. I'm having good results with Claude. * * * As always, I'm super interested in your feedback. What's working well, and where is Haunts coming up short? And a final request: Would you please tell your network about Haunts? https://gethaunts.com would be a good URL to share.
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 19/08/2026
And do you really want to let them be responsible for getting the word out?
spectralwebservices.com
Why are all the events only on social media??
Why am I so interested in hyperlocal events calendars lately? It probably has something to do with Haunts. Haunts — the community events calendar for publishersEvery event in town, on your site automagically. One embed, an RSS feed, and a weekend roundup that writes its own boring half.Haunts One of the interesting things on building automated calendars is that some communities have a high number of event producers whose only means of distribution seems to be social media. No calendar on the website. "Follow us on ___" is how they want their audience to learn if they're putting something on. Does this work? I mean, if your whole audience is on that platform, and the platform reliably shows your events to your whole audience, then I guess so. As soon as that's not true, things break down. Fast. [I'm especially perplexed by a few places that seem to post their events on Instagram. As images. How does that even work?] As I'm collecting events from all the local sources I can find, to build automated Haunts calendars for local newsrooms, I keep running into the only-on-social, and specifically, the only-on-Facebook problem. Putting event information into Facebook is a one way workflow. The information goes in, but it doesn't come back out. Facebook does not provide a useable API for getting events out in any sort of generic way that doesn't involve having administrative access to the site hosting the event. Yes, there's a page that will show all the events in a region, but there's no bot access. All the _secrets_ of these _public events_ are Facebook's alone. Sorry, am I ranting? Yeah, ok, I was ranting. There are companies out there that sell Facebook events data, which they're pretty clearly scraping. Some specifically sell runs on residential IPs, because even if your request looks human-shaped, it had better not be coming from a data center IP address, or Facebook will block it. It's cheap enough to use one of these to grab a handful of events once. It's just not economical to use one of these services to scan all the events in all the regions with Haunts calendars every night. I compare Haunts calendars to some of the big calendar providers pretty regularly. (The ones with an extra 0 at the end of the monthly price, specifically. That doesn't narrow it down much, does it?) They do have social media events. It's super clear that those events originate on Facebook, and in fact, they link back to it. I suspect these companies are scraping, or they've got a separate deal with FB for events data that isn't available through the regular API. I could buy scraper services, but this is a big added cost for a platform that's really not trying to do much more than cover costs. I have "social media events" listed on the top Haunts tier, but I'm not sure I can actually afford to provide them even if all of the price bump goes to buying social data. I could build a scraper. If it gets my residential IP blocked by Meta and the teens in my household lose their social media access, I'm not sure that's actually bad thing. 🤷‍♀️ ### Could Haunts be the source of truth? I looked at whether I could set up Haunts to be the source of truth, which would push your events to FB _and_ offer a readable, usable format for sites publishing calendars. The short answer was nope. Facebook does have a page about how to apply to integrate with them, which allows posting events via their API. I was briefly excited, until I read the note on that page says that applications are _paused due to COVID-19_. Everything I can find says that they've got a small handful of big company partners, and that's it. No small developer route. **TL;DR: Putting data into Facebook is for humans and big companies only, and so is getting it back out.** * * * ## What I wish event organizers would do If you want your events on Facebook, great. It makes sense to put events in front of your audience, and maybe you don't care that Meta controls what your audience sees and you're totally at their mercy. But, if you are posting events on Facebook, please don't only post them there. You're shutting out that local newsroom that would really like to share information about your events but can't without hours of human labor every week. Social media should not be the only "source of truth" for your events. Please, please, please put them somewhere else, too. One option to consider might be listing events on EventBrite as the primary "source of truth". EventBrite has the ability to create Facebook events, and Haunts can ingest data from EventBrite without issues. Last year, I'd have 100% told you to do that. This year, I'm eye-ing that Bending Spoons acquisition, and not sure I want to tell anyone to add EventBrite to their stack, out of fear that next year's offering may be markedly worse than this year's. [See what happened with Harvest as an example.] So, please. A Google calendar? A plugin that manages events on your website? An RSS or ICS feed that your website might already support? Literally anything except Facebook-only? Please? /rant over. Back to building.
001
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 12/08/2026
Events calendars are sooo much fun. Build a consumer for a particular feed type. Get it working (including discovering that it lies about which timezone it is in, and other fun). Ingest some events. Discover that cancellations are not working. Fix. Discover that... Fix... repeat. For 30+ content […]
spectralwebservices.com
Original post on spectralwebservices.com
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 11/08/2026
Building in public: Wrote a scraper for the rec center. Did the ingest: 600 events. Adjusted settings to category filter (I didn't want every single time the ice rink was open). Wiped and reran: 300 events. Discovered that recurring events weren't set up right, so it was 300 separate events, not […]
spectralwebservices.com
Original post on spectralwebservices.com
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 05/08/2026
Heads up for Airtable users: Bending Spoons just bought them. When Bending Spoons bought Harvest, lots of small freelancers and agencies experienced 5x renewal prices, on a month's notice. I'd be looking at what my other options were, if I had Airtable in my stack. (My annual plan would have […]
spectralwebservices.com
Original post on spectralwebservices.com
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 04/08/2026
The illustrator who used to make my ghosts quit taking work, and it's killing me.
spectralwebservices.com
I really need to find a new illustrator
I really really don't like using AI to generate images. I'd rather pay an artist. But the awesome illustrator who made the ghosts that are all over this site isn't taking work any more (_sob_), and I don't currently have an Adobe subscription (making my .ai files useless anyway), and all I needed was to remove the pink background. Here's how it went. Source image. Cute, but pink. Very pink. So pink it's off-brand."I need the pink background removed." Look closely. That is NOT a transparent background. That's a bad grey checkerboard. Me: Is that transparent? (I'd already downloaded it and knew the answer.) Gemini: No, that image has a **checkerboard pattern baked into the image itself** rather than an actual transparent background (alpha channel). If you try to place that image over a colored background or graphic, the grey-and-white grid pattern will show up as part of the picture. Here is the image with a **true transparent PNG background** so you can easily place it anywhere: (there was no image) Me: That's a blank image. Gemini offered me a choice of two responses. One was an explanation of how it wasn't a blank image. (It still was.) The other was this: I mean, that's almost cute. I've had AI mangle my mascot worse than this. But... I didn't ask it to change the face. I just wanted the pink gone, remember? Me: A (that's the image above) is closer, but I want the image not changed - leave the Ghost's face alone. Gemini: What, are we playing "spot the five differences" today? Me: no. go back to the original image. Remove the pink background. Replace with white or transparent. Change nothing else. Good grief. Thank you. * * * Illustrator referrals would be appreciated right about now.
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 01/08/2026
I’ve been calling my new events calendar embed “Calendar caddie” and picturing my usual ghost in a tam hat somehow schlepping calendar events (an illustration that presently exists only in my head). But… maybe I should really name it Haunts? As in… places you hang out? Decisions, decisions.
100
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 27/07/2026
Fixed a bug with SWS advanced search that could cause search indexes to get stuck in a misconfigured state. If you're seeing duplicate posts in search results, clicking "Reset to defaults" should fix you, and it shouldn't be possible to get into that state again. :)
001
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 21/07/2026
Got too many tags? Maybe way too many tags? I got you.
spectralwebservices.com
Introducing the Tags Wrangler
Yes, it's another post about tools as add-ons for Ghost. If you haven't checked out https://tools.spectralwebservices.com yet, maybe you should? It happens every few months. Some site (usually migrating from WP) with 20 tags on every post, many of those tags used once on the whole site. It's a mess. You can definitely clean this up with gctools, but if you don't already have a whole Node environment up and running, that's a pain, and you still have to figure out which tags get merged. Introducing the Tag Wrangler. Now you can merge and tidy up your tags with a friendly GUI. The video also demostrates how to use the Bulk Actions tool, formerly a standalone tool called Phantom Admin. It provides a more post-focused view and is also great for finding and reorganizing your posts, without the painful infinite scroll that can happen in the Ghost dashboard when you get to a few tens of thousands of posts. What's missing from these tools? Feedback welcome! ⚠️ Important! With great power comes great responsibility. Back up your content before you use these bulk tools. Go to /ghost > settings > import/export > export and choose the content export option.
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 18/07/2026
Got questions on our embeddable calendar? We have answers?
spectralwebservices.com
Calendar Caddie FAQ
_What? You haven't tried Calendar Caddie yet? Come on over to_ https://tools.spectralwebservices.com/_to get started!_ Calendar Caddie is a community events calendar app, built primarily for Ghost sites. It prioritizes using automation to obtain events, saving you time. #### Does it only work on Ghost? Ghost is my target market, but you can actually embed it anywhere you can embed html & javascript. For example, check out Stumptown Savings' calendar. That's Beehiiv. Small caveat: If you want to upload images for your calendar events, that requires Ghost (at least for now). You can put your images somewhere else and paste in links, or perhaps your feed items already have images (ideal). #### Can I take public submissions? Yes. Put the submissions embed on a separate page on your site, and configure Caddie (enable submissions and paste the link to that submissions page) to show the submit button. #### I get to approve public submissions, right? Definitely. Nothing goes live until you approve it. #### I have an event creator with a lot of events! Do they need to submit each one? If you trust them, the fastest and most-automated way to get the events into Caddie would be for them to create a calendar (i.e. a free Google Calendar) and give you the address of its public feed. Then their events could appear on your site, no approvals or manual work needed! #### Can I use Calendar Caddie for my own events only? Does it have to be a __community__ calendar? Sure! You can either manually create your events, or create a public calendar using any tool you like (i.e. Google calendar) and add its feed to Caddie. I generally think maintaining a calendar outside of Caddie is slightly easier than making Caddie the source of truth, but you can do either, and for a small number of events, it really doesn't matter. #### Why isn't the wizard working? I can see events on the website. Sometimes what looks to a human like a perfectly good list of events is actually a hand-built page with no structure that automation can read. [Note to the owners of these types of pages: If my automation can't read it, neither can Google's web crawler, and you're missing out on traffic as a result.] You can try the AI import tool (under "Custom" events) and paste in the contents of the page. It won't live update, but at least you'll get a static copy of their events. Caddie's current automated event retrieval doesn't use AI to parse page contents (exception: applying categories and deduplicating events). It relies on the site having a machine-readable structure. If AI whole page parsing is something you want, let's talk. It won't be a Caddie Lite/free offering, because it would require having an LLM check the page every night and assess whether any events listed had updates would be slow and token-intensive.
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 17/07/2026
Yep, nothing like dog-fooding to find ALL the bugs, missing features, annoyances, and rough edges.
010
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 14/07/2026
Sell access to Ghost-hosted content to university libraries, without making thousands of accounts or fussing with PII data.
spectralwebservices.com
Institutional access to Ghost now included with SWS Tools!
This is a Core+ feature for subscribers to Spectral Web Services Tools. Now available as part of your Spectral Web Services Tools subscription: IP-based institutional access! This is a great option for Ghost site owners who want to sell access to paywalled content to academic/university libraries, large companies, and other larger clients, where individual accounts are not needed or desirable. ## What to know: The institutional access is done by accessing Ghost as a paid user, and serving those paid-user results to anyone whose IP address matches a set of whitelisted IPs. Visitors from the institutional customer do not get separate accounts. They connect through their institution's proxy (from anywhere, if the institution has it set up that way), or by being at the institution and on their network. Ghost has no information about the institutional visitors. This is often desirable for universities, who won't want to share student data with you, while still wanting their students to get access. Because Ghost doesn't have institutional user data, the default setup does not support newsletter sign-ups. [But let me know if you need to make that possible. I've done it, it just isn't my default.] If your site uses Ghost's native comments, be aware that institutional visitors won't be able to comment (although comments can still be visible on the site if desired). Non-institutional users continue to access your site exactly as they do now. Nothing changes for them, and we don't proxy their requests. Institutional access services go through Cloudflare. We don't see user-noticeable changes in load time by adding the institutional access. Your site will still look great and load well! Your site management dashboard (_not part of Ghost_) gives you the ability to add or remove IP addresses, as well as (somewhat basic) logging of which institutions are visiting and what pages they're accessing. ## How it to get started: 🔮 Note: It isn't possible to set up this service through the tools website, since it the "first use" part needs some individualized setup. _Budget a business day or three_ to get it up and running on first use, after which you'll be able to onboard your own new customers. _First use:_ * Sign up for a tools subscription at the "Core" or higher tier. * Email Cathy with the desired subdomain to be used for institutional customers. (i.e. https://access.yourdomain.tld) * Add a couple of DNS records (with the directions we send you) * Create a Ghost user with complimentary access to the paywalled content. (Whatever tier you want to sell.) * Share your IP address, so that we can set you up for a test view. * Most sites need a small amount of proxy customization. We can take care of the following for you, or if your configuration needs are more expensive, we'll let you know if an additional setup fee is needed. Here's a list of common needs: * Hide account management buttons (theme-specific) * Add a visual indicator that institutional access is on (if desired). * Disable Portal and Outpost scripts for institutional users, since member management isn't relevant here. * Rewrite urls for Ghost's native search (default) or SWS search (on request) so that results correctly link to the institutional access site _For each new institutional subscription:_ * You handle billing for your institutional clients. (Most universities will want an invoice, forms, etc.) * Your institutional client tells you what IP ranges need access, and you enter those in your dashboard. If it's an academic library, ask them what proxy system they use for journals, and encourage them to use it for accessing your site. We have multiple institutional clients-of-clients using EZProxy, which works well and is easy to set up, but any proxy access system is fine. For other organizations, you could list their whole IP block, but it's often easier to manage a single proxy IP if they have one for other types of access already. * Your tell your institutional clients to access your site via the subdomain. They make some entries for it in their catalog and/or proxy system.
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 09/07/2026
A little code injection you can use to talk to your inbound social media visitors
spectralwebservices.com
Tell your Facebook Visitors to SIGN UP already!
Sometimes, you just need to tell your visitors to sign up already instead of stalking you on socials. Without bugging everyone else. Here's the result, with thanks to WBR Independent for letting me steal the screenshot. The following code can go into your code injection footer. Feel free to adjust wording, colors, eand so on. <script> const urlParams = new URLSearchParams(window.location.search); const utmCode = urlParams.get('fbclid'); if (utmCode) { const div = document.createElement('div'); div.className = 'facebook-visitor'; div.innerHTML = ` <div class="facebook-inner"> Hello Facebook Visitor, let’s make this relationship personal. Don’t miss another story! <a href="#/portal/">Subscribe today.</a> </div> `; document.body.insertBefore(div, document.body.firstChild); } </script> <style> .facebook-visitor { padding: 10px; color: white; background-color: #4C50E9; font-style: bold; font-weight: bold; font-family: merriweather; width: 100%; font-size: 15px; } .facebook-inner { max-width: min(95vw, 800px); margin-left: auto; margin-right: auto; } .facebook-visitor a { color: white; text-decoration: underline; } </style> Happy Ghosting!
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 06/07/2026
Get categories on your posts, so your members can filter for just what they want.
spectralwebservices.com
Calendar Caddie part 2: Categories
To make your events filterable by category, you'll need some categories! I recommend clicking the color splot next to each one and setting a dark color, which will be used in dark form for the filter buttons and in faded form for decorating your event tiles. You can use the rules to avoid AI usage. The keywords category looks for text that matches your keywords. The "Pinned source-native categories" will match an ICS feed that has categories. If you have a source already categorizing events, mapping to your category names can save time and improve accuracy! If AI categorization is enabled, and no rule matches, your event will be submitted to AI for categorization. The AI can only choose from your categories (or choose not to categorize), so having a fuller set of categories may improve your results. ### Update: Categories now have types! ✨ Giving your categories a "type" will allow visitors to filter for multiple categories at once, for example, if they want to see kid-friendly events that are free. Note: AI categorization is cached, so if you've added or edited a bunch of categories and want yours reset, just shoot me an email.
100
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 25/06/2026
Hey friends, if you ever notice me talking about building an alternate payment flow in Stripe that ALSO works with Ghost and doesn't break on edge cases (upgrade/downgrade/pro-ration/duplicate user emails/etc/etc)? Talk me out of it? Please?
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 23/06/2026
Nice numbers! I'd love to see an article about those optimization, if you think there's things other Ghost sites can learn from? I think you're not loading several of the heavier packages that Ghost sites typically run?
020
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 22/06/2026
How to get your site's calendar populated and looking great!
spectralwebservices.com
Calendar Caddie part 1 (adding a source)
Want to get started with Calendar Caddie? Head on over to https://tools.spectralwebservices.com . ### How do I (the curator) get sources onto my calendar? * Our goal is to make calendar generation automatic. We want to read sources of community events and get them onto your calendar with minimal or no intervention on your part, _once configured_. But to do that, we have to find the sources! * You hopefully already know (or can do some research) to find out who puts on events in your area that you're interested in including. * Once you have some momentum and a well-filled calendar, remaining sources will (hopefully) start asking _you_ to include them. Thus, our initial goal is to get the calendar looking like a useful resource, to encourage additional sources to want to be included and to be cooperative in making their events accessible to Caddie, if they are not currently. * Some sources may be initially difficult or impossible. Start with the easy ones. ## Adding a source Use the auto tool! With luck, it will identify the source for you! ### What if the auto-tool can't identify and configure my source? * Sometimes, the human-visible calendar is not the best source (i.e. if a human built it by hand as unformatted – but pretty – text). If it's a high-value and high volume source, a little internet research to see where else their events appear may be worthwhile. Are the events also listed somewhere else? For example, are these events also in Ticketmaster, or a Meetup group, or Eventbrite? * If it's a low volume source, is it worth just adding their events by hand? If a source has two events per year, maybe you just add them using the event submission form, or maybe you maintain a Google calendar where you add any events you want to add, and you add that Google calendar as a source. (Adding events to Google calendar may be faster than submitting them via the form.) * Ask the source! * It's possible that they actually do have a readable feed that just isn't obvious or we just haven't found. * Or it's possible that whoever takes care of their website can turn on a readable feed with a couple clicks. Ask for an ICS feed. * If someone is regularly submitting events via the form, consider some outreach. It would be faster for them and MUCH faster for you if they put their events on a calendar and shared that calendar link with you. [This assumes you don't want to pre-approve their events.] * Events that fail the auto-tool can be submitted for further investigation. My priority will be sources with many events (because a single annual event can just be added manually) and sources that are going to be generally useful (i.e. a common CMS/calendar system used by many organizations that will help many curators). ### What happens after I add a source? You can trigger a refresh on your source. Changes are typically live in 2-10 minutes, depending on source type. Sources are checked for new and updated events once daily. (more to come!)
020
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 22/06/2026
Another Spectral Web Services tool
spectralwebservices.com
How to connect your Ghost site to Apple News
Newly out in alpha over on the Spectral Web Services Tools for Ghost page: 🎉An Apple News integration! This one was a bear to build, because Apple News Format is its own thing, and although it sort of looks like HTML, it isn't. So I needed to translate every single Ghost card (and every single variant) into an Apple News component. You know how it always seems like it'd be nice to have just a few more cards built into the editor? There was a lot of swearing and not really feeling that. (I'm better now, and back to thinking it'd be super nice to have another half-dozen or so cards to give us more publishing options.) OK, enough whining, what's it do? ## Features * Triggered on post published event in Ghost, or manually. * Go straight to published, or save drafts for review later. * Configuration options for how it handles paywalled content, including publishing or protecting your members-only content. (Yes, it understands the preview line, too.) * Layout configuration options * Publish everything, or use tags to control what syndicates * Compatible with all Ghost cards (er... except HTML and Codepen) ### Caveats * It's in alpha. There might be bugs. 🐛 * The toggle card doesn't toggle - it starts open and stays there. (Apple News just can't do that.) Of course, it doesn't toggle in email, either! * Getting approved for Apple News distribution is a hurdle. I can get your content from Ghost to Apple News, but I can't promise they'll surface it once it gets there. That appears to be the hardest and slowest part, at this point. ## How to get an Apple News account ### Make your account 1. Read this first - if you aren't publishing news, stop here, go do something else. 2. Sign up for an account at icloud.com, if you don't already have one. Make sure 2FA is on. 3. Follow these instructions to get your channel id, key, and secret: https://support.apple.com/en-jo/guide/news-publisher/apd88c8447e6/1.0/icloud/1.0 4. Head over to the Apple News Integration page at https://tools.spectralwebservices.com/ . (Log in and set up your site if you haven't already.) In the Install tab, copy and paste in those values from step 3. 5. Publish something on Ghost! Or... head over to the Activity tab and manually publish some things. (Note, you need an Admin API key set up for your site before any of this will work.) 6. Your content should show up on the Tools > Apple News Integration > Activity tab within a minute or so, and then within your site's Apple news publisher page (accessible through iCloud.com) a minute or two after that. The activity tab gives you a direct link to the article which you can use on an Apple device to view the article directly. 7. Check out your articles using the direct link to each, or use the channel link (available in Apple News Publisher) to link directly to your channel. 8. Once you've got multiple articles published and looking great, you can request to have your site available to the public. Strangely, it appears that this form is the current mechanism for doing so. (Another option is having a contact at Apple News, being invited to apply, etc.) ## Help wanted! I would really appreciate hearing from you on whether this integration does what you need it to do, or if not, which knobs and settings are missing.
011
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 22/06/2026
apple.news/AUDbM2KZXRni2A-2Y-j8P7w (view on iphone or ipad) is not exactly demo.spectralwebservices.com/an-art… yet, but it's getting closer by the hour!
apple.news
An article with a reasonably long title. No one just writes "Style Guide" — Spectral Web Services (Test Dev channel)
A demonstration of every content card available in the Ghost editor. Mostly
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 19/06/2026
That moment when you think "well, I've already got ad analytics, so it wouldn't be that bad to add republish button tracking too... "
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 19/06/2026
An embeddable calendar that auto-updates every day.
spectralwebservices.com
Introducing Calendar Caddie
Want to get started with Calendar Caddie? Head on over to https://tools.spectralwebservices.com . Calendar Caddie is a community events calendar that you can embed on your website. Once you set up your sources (more on that in the next article), it self-updates nightly. The goal is a feed that updates itself – while you _can_ take community submissions or add events yourself, the idea here is that you'll invest time finding calendar sources to start, and then the events will flow in without much intervention on your part. A community calendar can be useful in several ways. You might view it as a community resource and a traffic driver that brings more visitors to your site. You might run ads on the page alongside it. You might charge event producers for featuring their events, or for submitting some types of events. Or it could be a subscribers-only feature. If you send a weekly newsletter, you may also find it to be a good resource for _you_ , as you assemble that newsletter. (A direct pipeline to the newsletter digest builder is coming soon.) There's some flexibility here, and I'm interested to hear how you use it, and where it isn't yet meeting your needs. Actual documentation for how to use it to follow!
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 18/06/2026
Because sometimes you need a quick way to stick a few sponsor messages on the page, without a ton of fuss
spectralwebservices.com
Introducing the Itty Bitty Ad Server for Ghost
Here's the latest tool launch for https://tools.spectralwebservices.com/ - an ad server for Ghost sites that just need to run a few local business ads. I've worked with lots of sites that just need to run a handful of locally-originated ads. Or sponsor messages. Either way, they don't need anything super complicated, but they do need to know how many impressions and clicks their ads got. ### What is it? An itty bitty ad server. If you want super fancy features and a huge learning curve, it might not be for you. If you just want to serve some sponsor messages/ads that you sell yourself, it might be just what you're looking for. As the video shows, if you have your ad images ready to go, you can get online and serving in about 12 minutes. ### Built in: * Responsive ad options - serve a mobile size cube on phones, banner on desktop * Ad analytics - track views and clicks, with 7day and 30day reporting. * Easy integration in Ghost. One copy-paste and you're done! * No theme edits needed. * Privacy! Your site visitors are not tracked. Seriously, ick. * Load your ad images and where they should link to, and you're ready to serve! * Fast loading. The itty bitty ad server code is about 7 kb zipped, and serves from Cloudflare. ### Not included: * Super detailed details on who saw your ad. (When you need geolocation and advanced analytics, you're ready for an advanced platform, not itty bitty ads.) * Bidding, 3rd party networks, payment collection. You don't need any of that for your first few locally-sourced ads/sponsorships * Waiting on someone to approve your site that isn't even live yet * Unexpected ads out of your control (ick) * Crazy steep learning curve. You can do this.
001