Automation

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:

  • Shell scripts and command-line tools
  • Shortcuts and quick actions
  • External app integrations
  • Cron jobs and scheduled tasks
open "statuz://compose?text=Automated%20post"

Learn more about URL Scheme API →

MCP Server

Best for:

  • AI assistant integration (Claude, Cursor, Zed)
  • Natural language control
  • Complex queries and filtering
  • Editor-based workflows
"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
fi

Assign 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

  1. Create new Shortcut
  2. Add Get Clipboard action
  3. Add URL action: statuz://compose?text=[Clipboard]
  4. Add Open URLs action
  5. Assign keyboard shortcut (e.g., ⌃⌥⇧P)

Schedule Tomorrow Shortcut

  1. Add Ask for Input (Text)
  2. Add Adjust Date (Add 1 day)
  3. Add Format Date (ISO 8601)
  4. Add URL action: statuz://schedule?text=[Input]&date=[Date]&status=queued
  5. Add Open URLs action

Share Screenshot Shortcut

  1. Add Take Screenshot
  2. Add Save File to /tmp/shortcut-screenshot.png
  3. Add URL action: statuz://compose?media=file:///tmp/shortcut-screenshot.png
  4. Add Open URLs action

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:

  1. Take Screenshot - Interactive
  2. Set Variable screenshot_path to /tmp/km-screenshot.png
  3. Execute Shell Script:
if [ -f /tmp/km-screenshot.png ]; then
  open "statuz://compose?media=file:///tmp/km-screenshot.png"
fi

Post Selected Text

Trigger: ⌃⌥⇧P

Actions:

  1. Get Clipboard (Save to variable)
  2. Execute Shell Script:
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:

  1. Execute Shell Script:
#!/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:

  • Kind is Image
  • Name contains "Screen Shot"

Actions:

  • Run Shell Script:
#!/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:

  • Kind is Text File
  • Date Created is in the last 1 hour

Actions:

  • Run Shell Script:
#!/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.js

Advanced 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
fi

Rate Limiting

Avoid overwhelming Statuz with rapid requests:

# Add delays between bulk operations
for item in "${items[@]}"; do
  # ... process item ...
  sleep 1  # Wait 1 second
done

Logging

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?

Try Statuz today,
it's free.