<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Troy Cottam</title>
    <description>The latest articles on DEV Community by Troy Cottam (@fallout76er).</description>
    <link>https://dev.to/fallout76er</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4035634%2Fbb8fcf9f-580b-4477-b1ea-a09465c9c3b9.png</url>
      <title>DEV Community: Troy Cottam</title>
      <link>https://dev.to/fallout76er</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fallout76er"/>
    <language>en</language>
    <item>
      <title>Auto-posting RSS to Bluesky with Make.com — with an actually clickable link</title>
      <dc:creator>Troy Cottam</dc:creator>
      <pubDate>Sat, 18 Jul 2026 18:03:11 +0000</pubDate>
      <link>https://dev.to/fallout76er/auto-posting-rss-to-bluesky-with-makecom-with-an-actually-clickable-link-461k</link>
      <guid>https://dev.to/fallout76er/auto-posting-rss-to-bluesky-with-makecom-with-an-actually-clickable-link-461k</guid>
      <description>&lt;p&gt;How to get past the "links are just plain text" problem using one fixed-offset facet and zero code.&lt;/p&gt;

&lt;p&gt;I run a &lt;a href="https://fallout76er.com" rel="noopener noreferrer"&gt;Fallout 76 fan site&lt;/a&gt; — a static, no-framework photo archive with an Atom feed. I'm a huge fan of automating grunt work — the wife says lazy — so I wanted every new in-game screenshot I add to the site to auto-post to &lt;a href="https://bsky.app/profile/fallout76er.com" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt; with the image attached and a clickable link back to my site. I chose Make.com because it can do the RSS-watching and the image-uploading out of the box, but the last step in making this automation happen hides a trap that took me a fair amount of debugging to solve:&lt;/p&gt;

&lt;p&gt;Weirdly, Bluesky does not auto-link URLs, and Make's native "Create a post" module doesn't make links clickable. Your URL posts as inert plain text. I ran into this known limitation, and after some digging located a fix — it just requires understanding one piece of the AT Protocol: &lt;em&gt;rich text facets&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This article is a missing manual for the process and specifically that last step. After reading this piece, you'll have a five-module Make scenario that watches your feed and posts new images + clickable links + hashtags to Bluesky, with no code and no per-post byte counting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why links on Bluesky are hard
&lt;/h2&gt;

&lt;p&gt;On most platforms, you post text containing a URL and the platform "linkifies" it. Bluesky's API doesn't do that. A post record's &lt;code&gt;text&lt;/code&gt; is dumb bytes; anything interactive — links, mentions, hashtags — is declared separately in a &lt;code&gt;facets&lt;/code&gt; array. Each facet says "bytes N through M of the text are a link to this URI."&lt;/p&gt;

&lt;p&gt;Two things make this painful in a no-code tool:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The offsets are &lt;em&gt;byte&lt;/em&gt; offsets into the UTF-8 encoding, not character positions. An em dash is three bytes. One &lt;code&gt;—&lt;/code&gt; before your link and your character-based math is wrong.&lt;/li&gt;
&lt;li&gt;Make.com has no facility for computing byte offsets of a dynamic substring. If your link's position shifts from post to post, you're screwed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The trick: pin the link to a constant prefix
&lt;/h2&gt;

&lt;p&gt;You can sidestep all byte math with one formatting trick: start every post with a fixed, ASCII-only prefix, and make the prefix the link.&lt;/p&gt;

&lt;p&gt;My posts all begin with the literal string &lt;code&gt;fallout76er.com&lt;/code&gt; — 15 ASCII characters, which is exactly 15 bytes, always at position 0. So the facet is a constant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"facets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"byteStart"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"byteEnd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"features"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"$type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app.bsky.richtext.facet#link"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{2.URL}}"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No formulas, no counting, ever. The facet's &lt;em&gt;target&lt;/em&gt; (&lt;code&gt;uri&lt;/code&gt;) is dynamic — it's mapped from the RSS item, so each post links to its own entry — but the &lt;em&gt;clickable region&lt;/em&gt; never moves. Readers see a click-through &lt;code&gt;fallout76er.com&lt;/code&gt; at the start of every post.&lt;/p&gt;

&lt;p&gt;Here are the rules for the prefix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep it exactly the byte length in &lt;code&gt;byteEnd&lt;/code&gt;. Change the prefix, recount the bytes.&lt;/li&gt;
&lt;li&gt;ASCII only. The moment you put a &lt;code&gt;—&lt;/code&gt; or an emoji inside the linked region, bytes will no longer equal characters.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;byteEnd&lt;/code&gt; is exclusive: &lt;code&gt;[0, 15)&lt;/code&gt; covers positions 0–14.&lt;/li&gt;
&lt;li&gt;Anything &lt;em&gt;after&lt;/em&gt; the facet region can be whatever multi-byte string you like. My text continues with &lt;code&gt;— {{Title}}&lt;/code&gt; and this em dash doesn't matter, because it's outside the linked range.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The five-module scenario
&lt;/h2&gt;

&lt;p&gt;Here's a capture of the whole chain — five modules, built in this order:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvigl153kpq01bydalmht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvigl153kpq01bydalmht.png" alt="Make.com scenario: RSS watch, photo filter, HTTP download, Bluesky upload, API call" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. RSS → Watch RSS feed items
&lt;/h3&gt;

&lt;p&gt;Point it at your feed. One gotcha for Atom feeds: the module copies each entry's &lt;code&gt;content&lt;/code&gt; element into its Description output, but it ignores &lt;code&gt;&amp;lt;enclosure&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;media:content&amp;gt;&lt;/code&gt; completely — so its Image field stays empty even when your feed dutifully provides image metadata. You'll fetch the image yourself in module 3.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Filter
&lt;/h3&gt;

&lt;p&gt;I only want photo entries to post, not every feed item. My photo entry URLs all contain a &lt;code&gt;#photo=&lt;/code&gt; fragment, so the filter is just: &lt;code&gt;URL&lt;/code&gt; → Text operators: Contains → &lt;code&gt;#photo=&lt;/code&gt;. Guide pages and other entry types sail past untouched. If you control your feed's URL scheme, building a filterable marker into it is the cheapest routing mechanism you'll ever write.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. HTTP → Download a file
&lt;/h3&gt;

&lt;p&gt;My entry URLs are the image URL plus that fragment, so the mapping is one function: &lt;code&gt;replace(2.URL; "#photo="; emptystring)&lt;/code&gt;. Adapt to taste — the point is deriving the image URL from data already in the feed item.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Bluesky → Upload media
&lt;/h3&gt;

&lt;p&gt;This calls &lt;code&gt;com.atproto.repo.uploadBlob&lt;/code&gt; and returns a blob reference you'll need in module 5. Use the "Map" option for the file input and map File name and Data from the HTTP module explicitly. The convenient-looking "HTTP - Download a file" radio button did not persist on save for me — twice — producing "Value must not be empty" warnings on the next run. Map is boring and works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjl5zafd6w5yh9cewi7qk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjl5zafd6w5yh9cewi7qk.png" alt="Bluesky Upload media module using the Map option, with File name and Data mapped from the HTTP module" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Bluesky → Make an API Call
&lt;/h3&gt;

&lt;p&gt;Remember, not "Create a post" — that's the module that can't do facets. The generic API-call module uses your existing Bluesky connection's auth, so this is still no-code, just hand-written JSON. POST to &lt;code&gt;/xrpc/com.atproto.repo.createRecord&lt;/code&gt; with header &lt;code&gt;Content-Type: application/json&lt;/code&gt; and this body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"repo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"did:plc:YOUR-DID-HERE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"collection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app.bsky.feed.post"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"record"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"$type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app.bsky.feed.post"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fallout76er.com — {{2.Title}}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;#Fallout76 #FO76"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"facets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"byteStart"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"byteEnd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"features"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"$type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app.bsky.richtext.facet#link"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{2.URL}}"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"langs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{formatDate(now; "&lt;/span&gt;&lt;span class="err"&gt;YYYY-MM-DDTHH:mm:ssZ&lt;/span&gt;&lt;span class="s2"&gt;")}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"embed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"$type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app.bsky.embed.images"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"images"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"alt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{2.Title}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"$type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"blob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"$link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{6.blob.ref.$link}}"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"mimeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{6.blob.mimeType}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;.blob.size&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"aspectRatio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"width"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;.width&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"height"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;.height&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(The module numbers here match the scenario capture above — RSS is 2, Upload media is 6. Yours will differ, so map the blob fields from whatever your Upload media module returns. Your DID is on your profile via any DID-lookup tool, or grab it from &lt;code&gt;https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=yourhandle&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;Details that will bite you if you skip them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The blob goes in as a reference, not as data. Map Upload media's Blob → Ref → &lt;code&gt;$link&lt;/code&gt; into &lt;code&gt;ref.$link&lt;/code&gt;. If you map the raw file Data there instead, the API answers &lt;code&gt;[400] Expected blob value type&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Stray spaces inside quoted JSON values corrupt them. A space that sneaks in around a mapped value inside the quotes of &lt;code&gt;createdAt&lt;/code&gt; or &lt;code&gt;uri&lt;/code&gt; produces an invalid datetime or URI. Spaces outside quotes are harmless. This is miserable to spot in Make's editor; if you get baffling validation errors, hunt for whitespace first.&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;formatDate(now; ...)&lt;/code&gt;, the &lt;code&gt;now&lt;/code&gt; goes inside the parentheses. Writing it outside fails in ways that aren't obviously about the date.&lt;/li&gt;
&lt;li&gt;Images have a ~1 MB cap. Standard web-quality compression (my q80 WebP files land around 200–300 KB) clears it with room to spare.&lt;/li&gt;
&lt;li&gt;Watch for vendor typos in mapped field names. My Upload media module offers image height as "Media Heigth." Map what the picker shows you, not what spelling suggests.&lt;/li&gt;
&lt;li&gt;Hashtags here are plain text. Making them clickable tag facets would mean real byte math per post, since they sit after variable-length titles. Plain-text tags still surface in Bluesky search, which was enough for me.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The gotcha hiding on your server: charset
&lt;/h2&gt;

&lt;p&gt;My first automated posts rendered em dashes as &lt;code&gt;â€"&lt;/code&gt;. Nothing was wrong in Make's mappings — the problem was the feed itself being served without an explicit charset. Make decoded my UTF-8 feed as Latin-1, and every multi-byte character shattered.&lt;/p&gt;

&lt;p&gt;The fix is one server config line ensuring the feed ships with &lt;code&gt;Content-Type: application/atom+xml; charset=utf-8&lt;/code&gt;. On Apache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;Files&lt;/span&gt;&lt;span class="sr"&gt; "feed.xml"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="nc"&gt;AddDefaultCharset&lt;/span&gt; utf-8
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;Files&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your automated posts have mangled punctuation, check the &lt;code&gt;Content-Type&lt;/code&gt; header on your feed before you touch the scenario.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing without waiting for the scheduler
&lt;/h2&gt;

&lt;p&gt;Two Make features make the debug loop tolerable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Run once" (scenario editor, bottom-left) executes the chain immediately instead of waiting for the next scheduled poll.&lt;/li&gt;
&lt;li&gt;The RSS watcher keeps a pointer of what it's already seen — and every run advances it, even failed ones. To re-test with the same entry: right-click the RSS module → "Choose where to start" → "Since specific date", and reset it before each test run.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;New photo goes up on the site, feed regenerates, and at the next poll the post appears on Bluesky: image embedded, title and hashtags in the text, and a clickable &lt;code&gt;fallout76er.com&lt;/code&gt; at the front. Total running cost is 1–2 Make operations per day on the free tier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fow1n1s29e7tnpo4kwg13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fow1n1s29e7tnpo4kwg13.png" alt="Automated Bluesky post with image embed and clickable site link" width="601" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The site this feeds is &lt;a href="https://fallout76er.com" rel="noopener noreferrer"&gt;fallout76er.com&lt;/a&gt;, a deliberately framework-free static site — feed included — generated by a few small Node scripts, all public &lt;a href="https://github.com/pwyller-creator/fallout76er.com" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt; if you want to see the feed-generation side of the pipeline.&lt;/p&gt;

&lt;p&gt;The fixed-prefix facet trick generalizes to any no-code tool talking to Bluesky, not just Make: if you can't compute byte offsets, design your post format so you never have to.&lt;/p&gt;

&lt;p&gt;That's it, gentle reader. I hope this walkthrough helps you automate some boring task-grind using Make. I'm not a Make affiliate — I'm more of an open-source guy — but if you visit my site and &lt;a href="https://ko-fi.com/fallout76er" rel="noopener noreferrer"&gt;buy me a Ko-fi&lt;/a&gt;, I won't complain.&lt;/p&gt;

</description>
      <category>bluesky</category>
      <category>nocode</category>
      <category>automation</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
