Ken Jones Pizza
Designer who spends most of his time coding
Inform your the Bluesky crowd when you publish a post
defineField({
name: 'blueskyPost',
title: 'Bluesky Post Content',
type: 'text',
description: 'Content to post on Bluesky when this post is published',
})import {env} from 'node:process'
import {BlueskyStrategy, Client} from '@humanwhocodes/crosspost'
import {documentEventHandler} from '@sanity/functions'
const {BLUESKY_USERNAME = '', BLUESKY_PASSWORD = '', BLUESKY_HOST = 'bsky.social'} = env
interface NotificationData {
slug: {
current: string
}
blueskyPost: string
title: string
}
export const handler = documentEventHandler<NotificationData>(async ({event}) => {
const {data} = event
const {title, blueskyPost, slug} = data
try {
const bluesky = new BlueskyStrategy({
identifier: BLUESKY_USERNAME,
password: BLUESKY_PASSWORD,
host: BLUESKY_HOST,
})
const client = new Client({
strategies: [bluesky],
})
const postContent = `${title}
${blueskyPost}
${slug.current}`
await client.post(postContent)
console.log('Successfully sent post to Bluesky')
} catch (error) {
console.error('Error posting to Bluesky:', error)
throw error
}
})import 'dotenv/config'
import process from 'node:process'
import {defineBlueprint, defineDocumentFunction} from '@sanity/blueprints'
const {BLUESKY_USERNAME, BLUESKY_PASSWORD, BLUESKY_HOST} = process.env
if (typeof BLUESKY_USERNAME !== 'string' || typeof BLUESKY_PASSWORD !== 'string') {
throw new Error('BLUESKY_USERNAME and BLUESKY_PASSWORD must be set')
}
export default defineBlueprint({
resources: [
defineDocumentFunction({
type: 'sanity.function.document',
name: 'bluesky-post',
src: './functions/bluesky-post',
memory: 1,
timeout: 10,
event: {
on: ['create'],
filter: "_type == 'post' && defined(blueskyPost)",
projection: '{title, blueskyPost, slug}',
},
env: {
BLUESKY_USERNAME: BLUESKY_USERNAME,
BLUESKY_PASSWORD: BLUESKY_PASSWORD,
BLUESKY_HOST: BLUESKY_HOST || 'bsky.social',
},
}),
],
})The Problem
Content teams want to automatically share their published articles on Bluesky to increase reach and engagement. Manually cross-posting to social platforms is time-consuming and often forgotten, leading to missed opportunities for content promotion.
The Solution
This Sanity Function automatically posts to Bluesky when content is published using the @humanwhocodes/crosspost library. When a post is created with the blueskyPost field populated, the function creates a Bluesky post containing the title, summary, and slug, helping maintain consistent social media presence without manual effort.
Quick Start
View full instructions and source code.
Initialize blueprints if you haven't already: npx sanity blueprints init
Then: npx sanity blueprints add function --example bluesky-post
Then deploy: npx sanity blueprints deploy
Bluesky Setup
More detailed instructions in the GitHub README
BLUESKY_USERNAME, BLUESKY_PASSWORD, and BLUESKY_HOST to your .env fileHow It Works
When a post is published, the function automatically:
• Creates a Bluesky post containing the title, summary, and slug
• Uses the @humanwhocodes/crosspost library to handle posting
• Maintains a consistent social media presence without manual effort
• Ensures the post is shared immediately upon publication
Key Benefits
• Automates social media sharing by posting to Bluesky on content publish
• Saves time by eliminating manual cross-posting tasks
• Ensures consistency with automatic posting of title, summary, and link
• Increases content reach by maintaining active social media presence
• Reduces missed opportunities by never forgetting to share published content
Technical Implementation
The function uses the @humanwhocodes/crosspost library to automate posting to Bluesky. It's built with:
• Event-driven architecture (triggers on publish)
• Integration with Bluesky API using app passwords
• Environment variable configuration for credentials
• Error handling for authentication and posting issues
Perfect For
• Content teams looking to automate social media posting
• Workflows that benefit from increased content reach and engagement
• Teams managing multiple social media accounts
• Projects that require consistent and timely content promotion
Designer who spends most of his time coding
Software Engineer, Comic Enthusiast, Coffee Lover, Human Goodreads and Staff Software Engineer at Sanity. He/Him
Automatically track when content was first published with a timestamp that sets once and never overwrites, providing reliable publication history for analytics and editorial workflows.
Go to First Published Timestamp FunctionAI-powered automatic tagging for Sanity blog posts that analyzes content to generate 3 relevant tags, maintaining consistency by reusing existing tags from your content library.
Go to Automatically tag blog postsOn document publish, send a Slack notification so your team is informed
Go to Notify your team via Slack on publishCreate, preview, and send Klaviyo campaigns without ever leaving Sanity Studio"
Go to Klaviyo campaigns without leaving your Studio