examples/functions/bluesky-post/README.md
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.
This Sanity Function automatically posts to Bluesky when you publish a new post with the blueskyPost field defined using the @humanwhocodes/crosspost library. The function creates a Bluesky post containing the title, summary, and slug, helping maintain consistent social media presence without manual effort.
post document type containing:
title field (string)blueskyPost field (text or string)slug field (slug type with current property)This function is built to be compatible with any of the official "clean" templates. We recommend testing the function out in one of those after you have installed them locally.
This function expects your post schema to include:
title field (string)blueskyPost field (text) - for the post contentslug field (slug type with current property)Most official templates already include the title and slug fields, but you will need to add the blueskyPost field.
Add the blueskyPost field to your post schema:
defineField({
name: 'blueskyPost',
title: 'Bluesky Post Content',
type: 'text',
description: 'Content to post on Bluesky when this post is published',
})
Important: Run these commands from the root of your project (not inside the studio/ folder).
Set up Bluesky Credentials
First, you'll need to create a Bluesky app password for API access:
Log into your Bluesky account:
Create an App Password:
Save your credentials:
yourname.bsky.social)xxxx-xxxx-xxxx-xxxxbsky.social (default)Important: App passwords have the same abilities as your account password but are restricted from destructive actions like account deletion. Store them securely.
Initialize the example
Run this if you haven't initialized blueprints:
npx sanity blueprints init
You'll be prompted to select your organization and Sanity studio.
Then run:
npx sanity blueprints add function --example bluesky-post
Add configuration to your blueprint
// sanity.blueprint.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',
},
}),
],
})
Install dependencies
Install dependencies in the project root:
npm install dotenv
Configure environment variables
Create a .env file in your project root with the following variables:
# Required
BLUESKY_USERNAME=yourname.bsky.social
BLUESKY_PASSWORD=xxxx-xxxx-xxxx-xxxx
# Optional (defaults shown)
BLUESKY_HOST=bsky.social
Required:
BLUESKY_USERNAME: Your full Bluesky handle (e.g., yourname.bsky.social)BLUESKY_PASSWORD: Your Bluesky app password (19 characters with dashes)Optional:
BLUESKY_HOST: Bluesky instance host (default: 'bsky.social')You can test the bluesky-post function locally using the Sanity CLI before deploying it to production.
Test the function with an existing document ID from your dataset:
npx sanity functions test bluesky-post --document-id <insert-document-id> --dataset production --with-user-token
Test the function with the included sample document:
npx sanity functions test bluesky-post --file functions/bluesky-post/document.json
Start the development server for interactive testing:
npx sanity functions dev
This opens an interactive playground where you can test functions with custom data.
Once you've tested your function locally and are satisfied with its behavior, you can deploy it to production.
Important: Make sure you have the Deploy Studio permission for your Sanity project before attempting to deploy.
Verify your blueprint configuration
Make sure your sanity.blueprint.ts file is properly configured with your function as shown in the implementation section above.
Deploy your blueprint
From your project root, run:
npx sanity blueprints deploy
This command will:
blueskyPost fieldAdd environment variables
After deployment, you need to add your Bluesky credentials as environment variables:
npx sanity functions env add bluesky-post BLUESKY_USERNAME "yourname.bsky.social"
npx sanity functions env add bluesky-post BLUESKY_PASSWORD "xxxx-xxxx-xxxx-xxxx"
npx sanity functions env add bluesky-post BLUESKY_HOST "bsky.social"
You can verify the environment variables were added successfully:
npx sanity functions env list bluesky-post
Verify deployment
After deployment, you can verify your function is active by:
blueskyPost field and confirming it appears on BlueskyModify the postContent template in index.ts:
const postContent = `🚀 ${title}
${blueskyPost}
Read more: ${slug.current}`
Only post when the postToBlue field is set to true:
filter: "_type == 'post' && defined(blueskyPost) && postToBluesky == true"
Add more fields to the projection and use them in the post:
projection: '{title, blueskyPost, slug, author}'
Error: "Authentication failed"
Error: "Missing environment variable BLUESKY_USERNAME"
Error: "Post content too long"
Posts not appearing on Bluesky
Function not triggering
blueskyPost field is defined when creating posts