Automation Guide for ctw

January 23, 2026 · View on GitHub

This guide shows how to use ctw in scripts for Twitter automation workflows.

Why ctw is Perfect for Scripting

  • CLI-first design - Every feature accessible via command line
  • JSON output - Easy to parse with jq
  • Exit codes - Standard Unix conventions for error handling
  • Environment variables - Configure once, use everywhere
  • Pipeable - Works with Unix pipes and redirects
  • No dependencies - Single binary, no runtime required

Quick Start

1. Setup for Automation

# Add to your ~/.bashrc or ~/.zshrc
export BEARER_TOKEN="your_twitter_bearer_token"
export PATH="$PATH:/path/to/ctw/bin"

# Or use a config file
cat > ~/.ctw_config << EOF
export BEARER_TOKEN="your_token_here"
export USER_AGENT="my-automation-bot/1.0"
EOF

# Source it in your scripts
source ~/.ctw_config

2. Test Your Setup

ctw users lookup --usernames twitter

Automation Patterns

Pattern 1: Monitor and React

Watch for keywords and trigger actions:

#!/bin/bash
# Monitor brand mentions and log them

ctw watch --keyword "@YourBrand" --auto-setup | while read -r line; do
    if echo "$line" | grep -q "Text:"; then
        # Extract the tweet text
        tweet=$(echo "$line" | sed 's/Text://')
        
        # Log it
        echo "[$(date)] New mention: $tweet" >> mentions.log
        
        # Send alert (example)
        # curl -X POST https://your-webhook.com/alert -d "tweet=$tweet"
    fi
done

More copy-paste recipes are available in script/recipes/.

Pattern 2: Scheduled Data Collection

Use cron for periodic data gathering:

#!/bin/bash
# Collect tweets about a topic every hour
# Add to crontab: 0 * * * * /path/to/collect_tweets.sh

KEYWORD="artificial intelligence"
OUTPUT_DIR="/data/tweets"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

ctw search recent \
    --query "$KEYWORD" \
    --param "max_results=100" \
    > "${OUTPUT_DIR}/ai_tweets_${TIMESTAMP}.json"

# Process results
jq -r '.data[].text' "${OUTPUT_DIR}/ai_tweets_${TIMESTAMP}.json" \
    >> "${OUTPUT_DIR}/all_tweets.txt"

Pattern 3: Automated Publishing

Schedule tweets or publish based on conditions:

#!/bin/bash
# Publish daily summary

# Generate content
SUMMARY=$(./generate_daily_summary.sh)

# Upload image if exists
if [ -f "daily_chart.png" ]; then
    MEDIA_ID=$(ctw media upload --file daily_chart.png --category tweet_image \
        | jq -r '.media_id_string')
    
    # Tweet with media
    ctw tweets create \
        --text "$SUMMARY" \
        --media-ids "$MEDIA_ID"
else
    # Tweet without media
    ctw tweets create --text "$SUMMARY"
fi

Pattern 4: Bulk Operations

Process multiple items efficiently:

#!/bin/bash
# Bulk follow users from a list

USER_ID="your_user_id"

while IFS= read -r target_username; do
    # Look up user
    TARGET_ID=$(ctw users lookup --usernames "$target_username" \
        | jq -r '.data[0].id')
    
    if [ -n "$TARGET_ID" ]; then
        echo "Following $target_username (ID: $TARGET_ID)"
        ctw users follow --source-id "$USER_ID" --target-id "$TARGET_ID"
        
        # Rate limit friendly delay
        sleep 2
    fi
done < users_to_follow.txt

Pattern 5: Data Pipeline

Build data processing pipelines:

#!/bin/bash
# Extract, transform, and load tweet data

# Extract: Get tweets
ctw search recent --query "golang" --param "max_results=100" |
    # Transform: Extract relevant fields
    jq -r '.data[] | [.id, .author_id, .text, .created_at] | @csv' |
    # Load: Import to database
    psql -d mydb -c "COPY tweets(id, author_id, text, created_at) FROM STDIN CSV"

Real-World Automation Examples

Example 1: Social Media Dashboard

#!/bin/bash
# Update dashboard with latest metrics

DASHBOARD_DIR="/var/www/dashboard"

# Get account stats
ctw users lookup --usernames "YourAccount" > "${DASHBOARD_DIR}/account.json"

# Get recent mentions
ctw search recent --query "@YourAccount" --param "max_results=50" \
    > "${DASHBOARD_DIR}/mentions.json"

# Get engagement metrics
ctw timelines user --user-id "YOUR_ID" --param "max_results=20" \
    > "${DASHBOARD_DIR}/recent_tweets.json"

# Generate HTML report
./generate_report.py "${DASHBOARD_DIR}"/*.json > "${DASHBOARD_DIR}/index.html"

Example 2: Customer Support Bot

#!/bin/bash
# Monitor support mentions and auto-respond

SUPPORT_USER_ID="your_support_account_id"

ctw watch --keyword "@YourSupport" --auto-setup | while read -r line; do
    # Extract tweet ID from the stream
    if echo "$line" | grep -q "^ID:"; then
        TWEET_ID=$(echo "$line" | awk '{print \$2}')
        
        # Get full tweet details
        TWEET_DATA=$(ctw tweets get --id "$TWEET_ID")
        
        # Check if it's a question
        if echo "$TWEET_DATA" | jq -r '.data.text' | grep -qi "how\|help\|support"; then
            # Auto-reply
            AUTHOR_ID=$(echo "$TWEET_DATA" | jq -r '.data.author_id')
            ctw tweets create \
                --text "Thanks for reaching out! Our team will respond soon. In the meantime, check out our FAQ: https://example.com/faq"
            
            # Log for follow-up
            echo "$TWEET_ID" >> support_queue.txt
        fi
    fi
done

Example 3: Content Aggregator

#!/bin/bash
# Aggregate tweets from multiple sources

SOURCES=("techcrunch" "verge" "wired" "arstechnica")
OUTPUT_FILE="tech_news_$(date +%Y%m%d).json"

echo '{"aggregated_tweets": []}' > "$OUTPUT_FILE"

for source in "${SOURCES[@]}"; do
    echo "Fetching from @$source..."
    
    # Get user ID
    USER_ID=$(ctw users lookup --usernames "$source" | jq -r '.data[0].id')
    
    # Get their recent tweets
    ctw timelines user --user-id "$USER_ID" --param "max_results=10" |
        jq '.data[]' >> temp_tweets.json
done

# Combine and deduplicate
jq -s 'add | unique_by(.id)' temp_tweets.json > "$OUTPUT_FILE"
rm temp_tweets.json

echo "Aggregated $(jq '.[]  | length' "$OUTPUT_FILE") unique tweets"

Example 4: Sentiment Analysis Pipeline

#!/bin/bash
# Real-time sentiment analysis

KEYWORD="YourProduct"
SENTIMENT_API="http://localhost:5000/analyze"

ctw watch --keyword "$KEYWORD" --auto-setup | while read -r line; do
    if echo "$line" | grep -q "^Text:"; then
        TWEET_TEXT=$(echo "$line" | sed 's/Text://' | xargs)
        
        # Analyze sentiment
        SENTIMENT=$(curl -s -X POST "$SENTIMENT_API" \
            -H "Content-Type: application/json" \
            -d "{\"text\": \"$TWEET_TEXT\"}" |
            jq -r '.sentiment')
        
        # Log with sentiment
        echo "[$(date)] [$SENTIMENT] $TWEET_TEXT" >> sentiment_log.txt
        
        # Alert on negative sentiment
        if [ "$SENTIMENT" = "negative" ]; then
            ./send_alert.sh "Negative mention detected: $TWEET_TEXT"
        fi
    fi
done

Example 5: Automated Content Curation

#!/bin/bash
# Find and retweet quality content

USER_ID="your_user_id"
KEYWORDS=("golang tutorial" "golang tips" "golang best practices")

for keyword in "${KEYWORDS[@]}"; do
    echo "Searching for: $keyword"
    
    # Find tweets
    ctw search recent \
        --query "$keyword lang:en -is:retweet has:links" \
        --param "max_results=10" |
        jq -r '.data[] | select(.public_metrics.retweet_count > 100) | .id' |
        head -n 3 |
        while read -r tweet_id; do
            echo "Retweeting $tweet_id"
            ctw retweets add --user-id "$USER_ID" --tweet-id "$tweet_id"
            sleep 5
        done
done

Advanced Techniques

Error Handling

#!/bin/bash
# Robust error handling

set -euo pipefail  # Exit on error, undefined vars, pipe failures

function handle_error() {
    echo "❌ Error on line \$1" >&2
    # Send alert
    curl -X POST https://alerts.example.com/error \
        -d "script=automation.sh&line=\$1"
    exit 1
}

trap 'handle_error $LINENO' ERR

# Your automation code here
ctw tweets create --text "Automated tweet" || {
    echo "Failed to post tweet" >&2
    exit 1
}

Rate Limit Handling

#!/bin/bash
# Handle rate limits gracefully

function api_call_with_retry() {
    local max_retries=3
    local retry_delay=60
    local attempt=1
    
    while [ $attempt -le $max_retries ]; do
        if "$@"; then
            return 0
        else
            echo "Attempt $attempt failed. Waiting ${retry_delay}s..." >&2
            sleep $retry_delay
            retry_delay=$((retry_delay * 2))  # Exponential backoff
            attempt=$((attempt + 1))
        fi
    done
    
    return 1
}

# Usage
api_call_with_retry ctw search recent --query "test"

Parallel Processing

#!/bin/bash
# Process multiple queries in parallel

QUERIES=("golang" "python" "rust" "javascript")
MAX_PARALLEL=4

export BEARER_TOKEN  # Make available to subshells

process_query() {
    local query="\$1"
    echo "Processing: $query"
    ctw search recent --query "$query" --param "max_results=100" \
        > "results_${query}.json"
}

export -f process_query

# Run in parallel
printf '%s\n' "${QUERIES[@]}" | xargs -P "$MAX_PARALLEL" -I {} bash -c 'process_query "$@"' _ {}

Logging and Monitoring

#!/bin/bash
# Comprehensive logging

LOG_DIR="/var/log/ctw-automation"
mkdir -p "$LOG_DIR"

# Redirect all output
exec 1> >(tee -a "${LOG_DIR}/automation_$(date +%Y%m%d).log")
exec 2> >(tee -a "${LOG_DIR}/errors_$(date +%Y%m%d).log" >&2)

echo "[$(date)] Starting automation"

# Track metrics
START_TIME=$(date +%s)
TWEETS_PROCESSED=0

# Your automation code
# ...

# Summary
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
echo "[$(date)] Completed. Processed $TWEETS_PROCESSED tweets in ${DURATION}s"

Integration Examples

Slack Integration

#!/bin/bash
# Post tweet notifications to Slack

SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK"

ctw watch --keyword "#YourHashtag" --auto-setup | while read -r line; do
    if echo "$line" | grep -q "^Text:"; then
        TWEET=$(echo "$line" | sed 's/Text://')
        
        curl -X POST "$SLACK_WEBHOOK" \
            -H 'Content-Type: application/json' \
            -d "{\"text\": \"New tweet: $TWEET\"}"
    fi
done

Database Integration

#!/bin/bash
# Store tweets in PostgreSQL

DB_CONN="postgresql://user:pass@localhost/twitter_db"

ctw search recent --query "data science" --param "max_results=100" |
    jq -r '.data[] | [.id, .author_id, .text, .created_at] | @csv' |
    while IFS=, read -r id author_id text created_at; do
        psql "$DB_CONN" -c \
            "INSERT INTO tweets (id, author_id, text, created_at) 
             VALUES ('$id', '$author_id', '$text', '$created_at')
             ON CONFLICT (id) DO NOTHING"
    done

Webhook Server

#!/bin/bash
# Simple webhook receiver

while true; do
    # Listen for webhooks
    REQUEST=$(nc -l 8080)
    
    # Extract action from webhook
    ACTION=$(echo "$REQUEST" | grep -oP '(?<=action=)[^&]+')
    
    case "$ACTION" in
        "post_tweet")
            TEXT=$(echo "$REQUEST" | grep -oP '(?<=text=)[^&]+' | sed 's/+/ /g')
            ctw tweets create --text "$TEXT"
            ;;
        "check_mentions")
            ctw search recent --query "@YourAccount" --param "max_results=10"
            ;;
    esac
done

Cron Examples

# Monitor mentions every 5 minutes
*/5 * * * * /opt/ctw/scripts/check_mentions.sh

# Daily content curation at 9 AM
0 9 * * * /opt/ctw/scripts/curate_content.sh

# Hourly data backup
0 * * * * /opt/ctw/scripts/backup_tweets.sh

# Weekly analytics report every Monday at 8 AM
0 8 * * 1 /opt/ctw/scripts/generate_weekly_report.sh

# Real-time monitoring (runs continuously)
@reboot /opt/ctw/scripts/start_monitoring.sh

Systemd Service Example

# /etc/systemd/system/ctw-monitor.service

[Unit]
Description=CTW Twitter Monitor
After=network.target

[Service]
Type=simple
User=twitter-bot
Environment="BEARER_TOKEN=your_token_here"
ExecStart=/usr/local/bin/ctw watch --keyword "YourBrand" --auto-setup
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl enable ctw-monitor
sudo systemctl start ctw-monitor
sudo journalctl -u ctw-monitor -f  # Watch logs

Docker Integration

FROM golang:1.18-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o ctw ./cmd/ctw

FROM alpine:latest
RUN apk --no-cache add ca-certificates jq
COPY --from=builder /app/ctw /usr/local/bin/
ENV BEARER_TOKEN=""
CMD ["ctw", "watch", "--keyword", "automation", "--auto-setup"]

Best Practices

1. Use Environment Variables

# Don't hardcode tokens
export BEARER_TOKEN="..."

# Use config files for complex setups
source /etc/ctw/config

2. Implement Retry Logic

for i in {1..3}; do
    ctw tweets create --text "Retry test" && break
    sleep $((i * 30))
done

3. Log Everything

ctw search recent --query "test" 2>&1 | tee -a ctw.log

4. Use Locks for Cron Jobs

#!/bin/bash
LOCKFILE=/tmp/ctw-script.lock

if [ -e "$LOCKFILE" ]; then
    echo "Already running"
    exit 1
fi

trap "rm -f $LOCKFILE" EXIT
touch "$LOCKFILE"

# Your automation code here

5. Monitor Script Health

#!/bin/bash
# Heartbeat script

while true; do
    if ! pgrep -f "ctw watch" > /dev/null; then
        echo "Monitor died, restarting..."
        /opt/ctw/scripts/start_monitor.sh &
    fi
    sleep 60
done

Troubleshooting

Check Exit Codes

ctw tweets create --text "test"
if [ $? -eq 0 ]; then
    echo "Success"
else
    echo "Failed with code $?"
fi

Debug Mode

# Enable verbose curl output
export CTW_DEBUG=1

# Or use set -x for bash debugging
set -x
ctw search recent --query "debug"
set +x

Test Before Deploying

# Dry-run mode (if supported)
ctw stream rules add --value "test" --dry-run

# Test with small limits
ctw search recent --query "test" --param "max_results=1"

Resources

Summary

ctw is designed for automation:

  • ✅ Single binary deployment
  • ✅ JSON output for easy parsing
  • ✅ Standard exit codes
  • ✅ Environment variable configuration
  • ✅ Stream processing capabilities
  • ✅ Rate-limit aware
  • ✅ Scriptable and pipeable

Start automating your Twitter workflows today! 🚀