Automation Guide
Comprehensive guide to automating Statuz with URL schemes, MCP, and external tools. Build powerful workflows that save time and streamline your social media management.
Automation Methods
Statuz offers two powerful automation APIs:
URL Scheme API
Best for:
open "statuz://compose?text=Automated%20post"
Learn more about URL Scheme API →
MCP Server
Best for:
"Schedule a post about our launch for tomorrow at 2pm"
Learn more about MCP Integration →
Quick Start Workflows
Daily Morning Post
Schedule a good morning post every day:
#!/bin/bash
# morning-post.sh
TOMORROW=$(date -v+1d -u +"%Y-%m-%dT14:00:00Z") # 9 AM EST
TEXT="Good morning! ☀️ Have a productive day!"
ENCODED=$(printf %s "$TEXT" | jq -sRr @uri)
open "statuz://schedule?text=$ENCODED&date=$TOMORROW&status=queued"Add to crontab:
0 20 * * * /path/to/morning-post.sh # Run at 8 PM daily
Screenshot to Social
Quick screenshot sharing:
#!/bin/bash
# screenshot.sh
screencapture -i /tmp/screenshot.png
if [ -f /tmp/screenshot.png ]; then
open "statuz://compose?media=file:///tmp/screenshot.png"
rm /tmp/screenshot.png
fiAssign to a keyboard shortcut in System Settings or Keyboard Maestro.
Clipboard to Post
Post whatever's in your clipboard:
#!/bin/bash
# clipboard-post.sh
CONTENT=$(pbpaste)
ENCODED=$(printf %s "$CONTENT" | jq -sRr @uri)
open "statuz://compose?text=$ENCODED"Git Commit Announcements
Announce commits automatically:
#!/bin/bash
# .git/hooks/post-commit
COMMIT=$(git log -1 --pretty=%B)
HASH=$(git log -1 --pretty=%h)
TEXT="🚀 New commit: $COMMIT ($HASH)"
ENCODED=$(printf %s "$TEXT" | jq -sRr @uri)
open "statuz://compose?text=$ENCODED&draft=true"Apple Shortcuts Integration
Quick Post Shortcut
Schedule Tomorrow Shortcut
Share Screenshot Shortcut
Raycast Extensions
Post Command
Create post-to-statuz.sh:
#!/bin/bash
# @raycast.schemaVersion 1
# @raycast.title Post to Statuz
# @raycast.mode silent
# @raycast.packageName Statuz
# @raycast.argument1 { "type": "text", "placeholder": "Your post" }
TEXT="$1"
ENCODED=$(printf %s "$TEXT" | jq -sRr @uri)
open "statuz://compose?text=$ENCODED"Schedule Command
Create schedule-to-statuz.sh:
#!/bin/bash
# @raycast.schemaVersion 1
# @raycast.title Schedule to Statuz
# @raycast.mode silent
# @raycast.packageName Statuz
# @raycast.argument1 { "type": "text", "placeholder": "Post text" }
# @raycast.argument2 { "type": "text", "placeholder": "When (e.g., '2pm tomorrow')" }
TEXT="$1"
# Parse date with natural language tool of your choice
DATE="2025-01-20T14:00:00Z" # Replace with actual parsing
ENCODED=$(printf %s "$TEXT" | jq -sRr @uri)
open "statuz://schedule?text=$ENCODED&date=$DATE&status=queued"Alfred Workflows
Post Workflow
Keyword: post {query}
Script:
query="{query}"
encoded=$(printf %s "$query" | jq -sRr @uri)
open "statuz://compose?text=$encoded"Schedule Workflow
Keyword: schedule {query}
Script:
query="{query}"
# Split query into text and date
encoded=$(printf %s "$query" | jq -sRr @uri)
open "statuz://schedule?text=$encoded&status=queued"Account Switcher Workflow
Keyword: switch work / switch personal
Script (work):
open "statuz://accounts?action=set-default&platform=x&nickname=Work%20X"
open "statuz://accounts?action=set-default&platform=bluesky&nickname=Work%20BS"
osascript -e 'display notification "Switched to work accounts" with title "Statuz"'Script (personal):
open "statuz://accounts?action=set-default&platform=x&nickname=Personal%20X"
open "statuz://accounts?action=set-default&platform=bluesky&nickname=Personal%20BS"
osascript -e 'display notification "Switched to personal accounts" with title "Statuz"'Keyboard Maestro Macros
Screenshot to Statuz
Trigger: ⌃⌥⇧S
Actions:
if [ -f /tmp/km-screenshot.png ]; then
open "statuz://compose?media=file:///tmp/km-screenshot.png"
fiPost Selected Text
Trigger: ⌃⌥⇧P
Actions:
SELECTED="$KMVAR_Selected_Text"
ENCODED=$(printf %s "$SELECTED" | jq -sRr @uri)
open "statuz://compose?text=$ENCODED"Daily Report Macro
Trigger: Every day at 8 PM
Actions:
#!/bin/bash
TOMORROW=$(date -v+1d -u +"%Y-%m-%dT14:00:00Z")
TEXT="Daily check-in: $(date +%Y-%m-%d)
Today's progress:
- [Add your updates here]
Tomorrow's goals:
- [Add your plans]"
ENCODED=$(printf %s "$TEXT" | jq -sRr @uri)
open "statuz://compose?text=$ENCODED&draft=true"Hazel Rules
Auto-Post Screenshots
Folder: ~/Desktop/To Post/
Conditions:
Actions:
#!/bin/bash
FILE="$1"
BASENAME=$(basename "$FILE")
TEXT="Latest screenshot: $BASENAME"
ENCODED_TEXT=$(printf %s "$TEXT" | jq -sRr @uri)
ENCODED_FILE=$(printf %s "file://$FILE" | jq -sRr @uri)
open "statuz://compose?text=$ENCODED_TEXT&media=$ENCODED_FILE"
# Move to processed folder
mkdir -p ~/Desktop/Posted
mv "$FILE" ~/Desktop/Posted/Auto-Share Blog Posts
Folder: ~/Sites/blog/_posts/
Conditions:
Actions:
#!/bin/bash
FILE="$1"
# Extract title from frontmatter
TITLE=$(grep "^title:" "$FILE" | cut -d: -f2- | xargs)
SLUG=$(basename "$FILE" .md)
TEXT="📝 New blog post: $TITLE
Read more: https://example.com/blog/$SLUG"
ENCODED=$(printf %s "$TEXT" | jq -sRr @uri)
open "statuz://compose?text=$ENCODED&draft=true"Python Automation
Daily Report Generator
#!/usr/bin/env python3
"""
Generate and post daily reports
"""
import subprocess
from datetime import datetime, timedelta
from urllib.parse import quote
def generate_daily_report():
# Fetch metrics from your systems
metrics = {
'users': 1250,
'revenue': 5400,
'signups': 23
}
text = f"""📊 Daily Report - {datetime.now().strftime('%Y-%m-%d')}
👥 Active Users: {metrics['users']:,}
💰 Revenue: ${metrics['revenue']:,}
✨ New Signups: {metrics['signups']}
Keep up the great work! 🚀"""
# Schedule for tomorrow at 9 AM
tomorrow = datetime.now() + timedelta(days=1)
schedule_time = tomorrow.replace(hour=9, minute=0, second=0)
iso_time = schedule_time.strftime('%Y-%m-%dT%H:%M:%S')
encoded = quote(text)
url = f"statuz://schedule?text={encoded}&date={iso_time}&timezone=America/New_York&status=queued"
subprocess.run(['open', url])
print(f"Report scheduled for {schedule_time}")
if __name__ == "__main__":
generate_daily_report()RSS Feed Monitor
#!/usr/bin/env python3
"""
Monitor RSS feed and post new items
"""
import feedparser
import subprocess
from urllib.parse import quote
import json
import os
FEED_URL = "https://example.com/feed.xml"
STATE_FILE = os.path.expanduser("~/.statuz-feed-state.json")
def load_state():
if os.path.exists(STATE_FILE):
with open(STATE_FILE, 'r') as f:
return json.load(f)
return {'seen_ids': []}
def save_state(state):
with open(STATE_FILE, 'w') as f:
json.dump(state, f)
def check_feed():
state = load_state()
feed = feedparser.parse(FEED_URL)
for entry in feed.entries[:5]: # Check last 5
if entry.id not in state['seen_ids']:
text = f"📰 {entry.title}\n\n{entry.summary[:150]}...\n\n{entry.link}"
encoded = quote(text)
subprocess.run(['open', f"statuz://compose?text={encoded}&draft=true"])
state['seen_ids'].append(entry.id)
save_state(state)
break # Post one at a time
if __name__ == "__main__":
check_feed()Run with cron:
*/15 * * * * /path/to/rss-monitor.py # Check every 15 minutes
Node.js Automation
Slack to Statuz Bridge
#!/usr/bin/env node
/**
* Slack webhook handler to post announcements
*/
const express = require('express');
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
const app = express();
app.use(express.json());
app.post('/webhook', async (req, res) => {
const { text, channel } = req.body;
// Only post from #announcements channel
if (channel !== 'announcements') {
return res.sendStatus(200);
}
const encoded = encodeURIComponent(text);
await execAsync(`open "statuz://compose?text=${encoded}&draft=true"`);
res.sendStatus(200);
});
app.listen(3000, () => {
console.log('Slack to Statuz bridge running on port 3000');
});CI/CD Integration
#!/usr/bin/env node
/**
* Post deployment notifications
*/
const { exec } = require('child_process');
const ENVIRONMENT = process.env.ENVIRONMENT || 'production';
const VERSION = process.env.VERSION || 'unknown';
const text = `✅ Deployment Complete
Environment: ${ENVIRONMENT}
Version: ${VERSION}
Time: ${new Date().toLocaleString()}
All systems operational! 🎉`;
const encoded = encodeURIComponent(text);
exec(`open "statuz://compose?text=${encoded}"`);Add to your CI/CD pipeline (e.g., GitHub Actions):
- name: Announce Deployment
run: |
export VERSION=${{ github.ref_name }}
export ENVIRONMENT=production
node announce-deploy.jsAdvanced Workflows
Multi-Platform Content Distribution
#!/bin/bash
# distribute-content.sh - Post to all platforms with platform-specific formatting
BASE_TEXT="🚀 Exciting news!"
# Platform-specific variations
X_TEXT="$BASE_TEXT
Full details in the thread below 👇"
BLUESKY_TEXT="$BASE_TEXT
Check out what we've been building! 🛠️"
MASTODON_TEXT="$BASE_TEXT
More info on our blog: https://example.com/blog"
# Post to each platform
X_ENCODED=$(printf %s "$X_TEXT" | jq -sRr @uri)
BS_ENCODED=$(printf %s "$BLUESKY_TEXT" | jq -sRr @uri)
MASTO_ENCODED=$(printf %s "$MASTODON_TEXT" | jq -sRr @uri)
open "statuz://compose?text=$X_ENCODED&platforms=x"
sleep 1
open "statuz://compose?text=$BS_ENCODED&platforms=bluesky"
sleep 1
open "statuz://compose?text=$MASTO_ENCODED&platforms=mastodon"Content Calendar Population
#!/bin/bash
# populate-calendar.sh - Bulk schedule posts for the week
declare -A schedule=(
["2025-01-20T09:00:00Z"]="Monday motivation: Start the week strong! 💪"
["2025-01-21T14:00:00Z"]="Tuesday tip: Stay focused on your goals 🎯"
["2025-01-22T10:00:00Z"]="Wednesday wisdom: Progress over perfection 📈"
["2025-01-23T15:00:00Z"]="Thursday thoughts: Keep pushing forward 🚀"
["2025-01-24T16:00:00Z"]="Friday feels: Weekend is almost here! 🎉"
)
for date in "${!schedule[@]}"; do
text="${schedule[$date]}"
encoded=$(printf %s "$text" | jq -sRr @uri)
open "statuz://schedule?text=$encoded&date=$date&status=queued"
echo "Scheduled: $text"
sleep 1
done
echo "Content calendar populated!"Best Practices
URL Encoding
Always encode text parameters:
# ✅ Correct
ENCODED=$(printf %s "$TEXT" | jq -sRr @uri)
# ❌ Wrong (special characters will break)
ENCODED="$TEXT"Error Handling
Add robust error handling:
#!/bin/bash
set -euo pipefail # Exit on error, undefined vars, pipe failures
# Check dependencies
if ! command -v jq &> /dev/null; then
echo "Error: jq is required. Install with: brew install jq"
exit 1
fi
# Validate input
if [ -z "${TEXT:-}" ]; then
echo "Error: TEXT variable is empty"
exit 1
fiRate Limiting
Avoid overwhelming Statuz with rapid requests:
# Add delays between bulk operations
for item in "${items[@]}"; do
# ... process item ...
sleep 1 # Wait 1 second
doneLogging
Log automation activities:
#!/bin/bash
LOG_FILE="$HOME/.statuz-automation.log"
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
log "Starting automation..."
# ... automation logic ...
log "Completed successfully"State Management
Track what's been processed:
import json
import os
STATE_FILE = os.path.expanduser("~/.my-automation-state.json")
def load_state():
if os.path.exists(STATE_FILE):
with open(STATE_FILE, 'r') as f:
return json.load(f)
return {}
def save_state(state):
with open(STATE_FILE, 'w') as f:
json.dump(state, f, indent=2)Troubleshooting
URL Scheme Not Opening
# Check if Statuz is installed
if [ ! -d "/Applications/Statuz.app" ]; then
echo "Error: Statuz not found in /Applications"
exit 1
fi
# Try opening manually
open -a Statuz "statuz://compose?text=Test"Encoding Issues
# Test encoding
TEXT="Hello 👋 World!"
ENCODED=$(printf %s "$TEXT" | jq -sRr @uri)
echo "Encoded: $ENCODED"
# Decode to verify
DECODED=$(printf '%b' "$(echo "$ENCODED" | sed 's/+/ /g; s/%/\\x/g')")
echo "Decoded: $DECODED"File Access Denied
# Check file exists and is readable
if [ ! -r "$FILE" ]; then
echo "Error: Cannot read file: $FILE"
exit 1
fi
# Use absolute paths
FILE=$(realpath "$FILE")Resources
Community Scripts
Share your automation scripts with the community:
Support
Need help with automation?