Post to Bluesky
Inform your the Bluesky crowd when you publish a post
schemaTypes/post.ts
defineField({
name: 'blueskyPost',
title: 'Bluesky Post Content',
type: 'text',
description: 'Content to post on Bluesky when this post is published',
})index.ts
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
}
})sanity.blueprints.ts
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({
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
- Log into your Bluesky account: Go to bsky.app and sign in with your account
- Create an App Password: Navigate to Settings → Privacy and Security → App Passwords, click "Add App Password", give it a descriptive name, and click "Create App Password"
- Save your credentials: Add
BLUESKY_USERNAME,BLUESKY_PASSWORD, andBLUESKY_HOSTto your.envfile
How 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
Contributors

Ken Jones Pizza
Designer who spends most of his time coding

Simon MacDonald
Software Engineer, Comic Enthusiast, Coffee Lover, Human Goodreads and Staff Software Engineer at Sanity. He/Him