examples/functions/social-media-crosspost/README.md
Content teams need to share their content across multiple social media platforms to maximize reach, but manually posting to each platform is time-consuming, error-prone, and often forgotten. Each platform has different character limits and formatting requirements, making it even more challenging to maintain consistent messaging.
This Sanity Function automatically posts content to multiple social media platforms (X, Mastodon, Bluesky, LinkedIn, Discord, Telegram, Slack, and Dev.to) when you publish a social post document. Using the @humanwhocodes/crosspost library, it handles platform-specific formatting, character limits, and authentication, allowing you to write once and publish everywhere from a single Sanity document.
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 includes a socialPost document type schema with a custom character counter component.
Add the schema files to your Studio:
Copy socialPost.ts to your Studio's schema types directory (e.g., studio/schemaTypes/documents/)
Copy characterCount.tsx to your components directory (e.g., studio/schemaTypes/components/)
Import and add the schema to your sanity.config.ts:
import {socialPost} from './schemaTypes/documents/socialPost'
export default defineConfig({
// ... other config
schema: {
types: [
// ... your existing types
socialPost,
],
},
})
Install required dependencies in your Studio:
cd studio # or your Studio directory
npm install @sanity/ui
Deploy your updated schema:
cd studio
npx sanity schema deploy
Supported Platforms: This function supports 8 platforms via the @humanwhocodes/crosspost library:
Important: Run these commands from the root of your project (not inside the studio/ folder).
Set up platform credentials
You'll need API credentials for each platform you want to post to. Follow the detailed setup instructions in the crosspost library documentation:
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 social-media-crosspost
Add configuration to your blueprint
// sanity.blueprint.ts
import 'dotenv/config'
import process from 'node:process'
import {defineBlueprint, defineDocumentFunction} from '@sanity/blueprints'
// Extract environment variables for platforms you want to use
const {
TWITTER_ACCESS_TOKEN_KEY,
TWITTER_ACCESS_TOKEN_SECRET,
TWITTER_API_CONSUMER_KEY,
TWITTER_API_CONSUMER_SECRET,
MASTODON_ACCESS_TOKEN,
MASTODON_HOST,
BLUESKY_IDENTIFIER,
BLUESKY_PASSWORD,
BLUESKY_HOST,
LINKEDIN_ACCESS_TOKEN,
DISCORD_WEBHOOK_URL,
TELEGRAM_BOT_TOKEN,
TELEGRAM_CHAT_ID,
SLACK_BOT_TOKEN,
SLACK_CHANNEL,
DEVTO_API_KEY,
} = process.env
// Ensure environment variables are strings or provide defaults
const crosspostEnvVars = {
TWITTER_ACCESS_TOKEN_KEY: TWITTER_ACCESS_TOKEN_KEY || '',
TWITTER_ACCESS_TOKEN_SECRET: TWITTER_ACCESS_TOKEN_SECRET || '',
TWITTER_API_CONSUMER_KEY: TWITTER_API_CONSUMER_KEY || '',
TWITTER_API_CONSUMER_SECRET: TWITTER_API_CONSUMER_SECRET || '',
MASTODON_ACCESS_TOKEN: MASTODON_ACCESS_TOKEN || '',
MASTODON_HOST: MASTODON_HOST || '',
BLUESKY_IDENTIFIER: BLUESKY_IDENTIFIER || '',
BLUESKY_PASSWORD: BLUESKY_PASSWORD || '',
BLUESKY_HOST: BLUESKY_HOST || '',
LINKEDIN_ACCESS_TOKEN: LINKEDIN_ACCESS_TOKEN || '',
DISCORD_WEBHOOK_URL: DISCORD_WEBHOOK_URL || '',
TELEGRAM_BOT_TOKEN: TELEGRAM_BOT_TOKEN || '',
TELEGRAM_CHAT_ID: TELEGRAM_CHAT_ID || '',
SLACK_BOT_TOKEN: SLACK_BOT_TOKEN || '',
SLACK_CHANNEL: SLACK_CHANNEL || '',
DEVTO_API_KEY: DEVTO_API_KEY || '',
}
export default defineBlueprint({
resources: [
defineDocumentFunction({
name: 'social-media-crosspost',
src: './functions/social-media-crosspost',
memory: 2,
timeout: 30,
event: {
on: ['create'],
filter: "_type == 'socialPost'",
projection: '{_id, body, mainImage, platforms, platformOverrides}',
},
env: crosspostEnvVars,
}),
],
})
Install dependencies
Install dependencies in the project root and in the functions directory:
# Install dependencies in the root
npm install dotenv
# Install in the functions directory
cd functions/social-media-crosspost
npm install
Configure environment variables
Create a .env file in your project root with your platform credentials:
# X (Twitter)
TWITTER_ACCESS_TOKEN_KEY=your-access-token
TWITTER_ACCESS_TOKEN_SECRET=your-access-secret
TWITTER_API_CONSUMER_KEY=your-consumer-key
TWITTER_API_CONSUMER_SECRET=your-consumer-secret
# Mastodon
MASTODON_ACCESS_TOKEN=your-access-token
MASTODON_HOST=mastodon.social
# Bluesky
BLUESKY_IDENTIFIER=yourname.bsky.social
BLUESKY_PASSWORD=xxxx-xxxx-xxxx-xxxx
BLUESKY_HOST=bsky.social
# LinkedIn
LINKEDIN_ACCESS_TOKEN=your-linkedin-token
# Discord
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
# Telegram
TELEGRAM_BOT_TOKEN=your-bot-token
TELEGRAM_CHAT_ID=your-chat-id
# Slack
SLACK_BOT_TOKEN=xoxb-your-bot-token
SLACK_CHANNEL=your-channel-id
# Dev.to
DEVTO_API_KEY=your-api-key
Only include credentials for platforms you want to use.
[!NOTE] Running tests will post to the social media accounts you have configured in your environment variables and test document/json. Use test accounts if you do not want to post live content to real audiences.
You can test the social-media-crosspost function locally using the Sanity CLI before deploying it to production.
Test the function with the included sample document:
npx sanity functions test social-media-crosspost --file functions/social-media-crosspost/document.json
Start the development server for interactive testing:
npx sanity functions dev
This opens an interactive playground where you can:
social-media-crosspost functiondocument.json if you want to use the sample data, or create your ownOnce you've tested your function locally and are satisfied with its behavior, you can deploy it to production.
Deploy your blueprint
From your project root, run:
npx sanity blueprints deploy
This command will:
Optional: Add environment variables
If you did not use a .env file you can add your environment variables using the CLI after deployment:
npx sanity functions env add social-media-crosspost MASTODON_ACCESS_TOKEN "your-token"
npx sanity functions env add social-media-crosspost MASTODON_HOST "mastodon.social"
You can verify the environment variables were added successfully:
npx sanity functions env list social-media-crosspost
Verify deployment
After deployment, you can verify your function is active by:
status field for links to published posts or error messagesUse Sanity's Content Releases feature to schedule posts in advance! Draft your social posts and bundle them into a scheduled release for coordinated multi-platform launches.
The schema includes a real-time character counter that:
You can override the global post body for specific platforms:
Error: "No enabled strategies found"
Error: "Authentication failed" for a platform
Posts not appearing on social platforms
status field on your social post document for error messagesX (Twitter):
TWITTER_* environment variables (not X_*)Mastodon:
mastodon.social)write:media to attach imagesBluesky:
xxxx-xxxx-xxxx-xxxxBLUESKY_IDENTIFIER (not BLUESKY_USERNAME)LinkedIn:
Discord:
https://discord.com/api/webhooks/...Telegram:
Slack:
xoxb-chat:write and files:write scopesfiles:write scope is required if attaching images - posts will fail with "missing_scope" error without itDev.to: