Sign in

Spectral Web Services

@cathy.spectralwebservices.com.ap.brid.gy
7 followers 0 following 228 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 · 08/10/2026
🚨 WDYBTW: Check for hardcoded /users/1/ calls, now rejected What did you break this week, week of 2026-10-01 www.spectralwebservices.com/blog/wd…
spectralwebservices.com
🚨 WDYBTW: Check for hardcoded /users/1/ calls, now rejected
What did you break this week, week of 2026-10-01
000
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 07/10/2026
If you've wanted to add a social post card in Ghost and been frustrated that it doesn't survive email, I've got you. toolbox.spectralwebservices.com/emb…
toolbox.spectralwebservices.com
Email-Friendly Embeds — Spotify, Instagram, Bluesky, X, LinkedIn, Bandcamp, SoundCloud, Datawrapper, Flourish and writer headshots that still work in email | SWS Tools
Paste a Spotify, Instagram, Bluesky, X, LinkedIn, Bandcamp, SoundCloud, Datawrapper, Flourish or PDF link and get cards for the Ghost editor: the real embed for your site, and a card that works in email, where embeds never load. Plus cards Ghost doesn't have: a small image with its caption, and an author bio card.
001
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 05/10/2026
I bought a Mac! Not because I wanted a Mac. Not because my cats wanted another laptop to sit on (although they did, I'm sure). Nope, I bought a Mac because it was the only reasonable way to deal with obnoxious Safari "quirks" and to get access to dev tools for iPhones and tablets without paying […]
spectralwebservices.com
Original post on spectralwebservices.com
001
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 05/10/2026
🎉Introducing "What did you break this week?" An AI-generated rundown of the things that are going to have me patching integrations at 10pm on a Friday. www.spectralwebservices.com/blog/in…
spectralwebservices.com
🎉Introducing "What did you break this week?"
An AI-generated rundown of the things that are going to have me patching integrations at 10pm on a Friday.
001
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 04/10/2026
🚨 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
002
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 04/10/2026
🚨 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
001
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
001
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?
011
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
001
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?
001
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...
001
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
Advanced Search, Bulk Actions, Clickable Footnotes, Content Lifecycle, Editorial Board, Email Automations, Fundraising Thermometer, Ghost to Apple News integration, Haunts Event Calendar, Image Library, Institutional Access, Itty Bitty Ad Server, Label Pairs, Member Preferences, Membership […]
spectralwebservices.com
Original post on spectralwebservices.com
000
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
Apparently working on i18n on Ghost taught me a few things, because it's been really easy to jump in and address the various strings, date parsing, and display issues. Yep, been there, done that before. Not everything is perfect yet, but at least I know where the issues are likely to be. [Dates […]
spectralwebservices.com
Original post on spectralwebservices.com
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
Looking great! I maintain the shared theme for the publisher members of Tiny News Collective, and I suspect I've got a dozen requests for tweaks on custom themes coming once the changelog email goes out. Did I get to do any of that today? Nope. Instead a client created a minor emergency that […]
spectralwebservices.com
Original post on spectralwebservices.com
010
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
Sigh. It's LIVE on...
000
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 · 30/08/2026
Well, we knew it was possible already, because it's possible to paste these cards between browser sessions using just Ghost. It was just a question of working out exactly what to load on the clipboard to make it work from outside Ghost, too. :)
010
Spectral Web Services @cathy.spectralwebservices.com.ap.brid.gy · 30/08/2026
Yep! Complete with caption and alt text. (It can also copy-paste a product card/cta/header with the image pre-filled. It's now a dropdown option, with image as the default.)
110
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
Today, it occurred to me that my client whose whole back catalog was already indexed in Algolia (to power advanced search) was not in fact very far from having a searchable collection of all their images. Pretty good stopgap solution until/unless Ghost deploys a native option.
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 · 22/08/2026
This thing: a.co/d/0fSe5Rmk This thing will cause you NOT to have this voice in your head, because it's seriously magic. -- Love, a 50-something year old chick with small hands.
010
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 · 08/08/2026
Late-breaking addition: And I fixed the URL generator on the TOC so that it'll work on ActivityPub. It'll take users to your site, but it'll get them to the right spot in the article...
001
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
Yeah. Haunts. gethaunts.com
gethaunts.com
Haunts — the community events calendar for publishers
Every event in town, on your site automagically. One embed, an RSS feed, and a weekend roundup that writes its own boring half.
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