Skip to content

DomEscobar/Social-Poster-API

Repository files navigation

Social Media Poster API

A RESTful API server for automated social media posting using signed-in browser sessions on VMs.

πŸ’‘ What is This?

This API allows you to automate social media posts (Instagram, Twitter/X) by leveraging browser sessions where you're already logged in. Perfect for VM deployments where you maintain signed-in accounts.

How it works:

  1. Deploy on a Linux VM (or Windows)
  2. Connect via RDP to sign into your social media accounts in the browser
  3. Use the API to automate posts with those signed-in sessions
  4. No credentials stored - uses your existing browser sessions
  5. Supports Instagram and Twitter/X with advanced features like auto-threading

πŸ—οΈ Architecture

β”œβ”€β”€ app.ts                          # Express application
β”œβ”€β”€ index.ts                        # Server entry point
β”œβ”€β”€ config.ts                       # Configuration manager
β”œβ”€β”€ controllers/                    # Business logic
β”œβ”€β”€ routes/                         # API endpoints
β”œβ”€β”€ middleware/                     # Error handling
β”œβ”€β”€ lib/                           # Core services
β”œβ”€β”€ setup-linux.sh                  # Initial setup script
β”œβ”€β”€ update-server.sh                # Update & restart script
β”œβ”€β”€ fix-browser-display.sh          # Fix browser display issues
└── config-browser.sh               # Configure browser paths

πŸš€ Setup (Linux VM)

Step 1: Run Setup Script

SSH into your Linux VM and run:

chmod +x setup-linux.sh
./setup-linux.sh

This installs:

  • Node.js (LTS)
  • Brave Browser
  • System dependencies
  • Server packages

Step 2: Connect via RDP

Install and configure RDP on your VM:

# Install RDP server (Ubuntu/Debian)
sudo apt install xrdp
sudo systemctl enable xrdp
sudo systemctl start xrdp

# Allow RDP through firewall
sudo ufw allow 3389/tcp

Connect from your local machine:

  • Windows: Use built-in Remote Desktop Connection
  • Mac: Download Microsoft Remote Desktop from App Store
  • Linux: Use Remmina or similar

Step 3: Sign Into Social Media Accounts

Once connected via RDP:

  1. Open Brave browser on the VM
  2. Navigate to Instagram or Twitter/X
  3. Sign in with "Remember me" checked
  4. Close browser (session is saved)

Step 4: Configure

# In another terminal, configure browser paths (only needed once)
./config-browser.sh

The API is now ready at http://localhost:3000

Note: Browser configuration is automatically saved to browser-config.json and persists across restarts. You only need to run config-browser.sh once!

πŸ“‘ API Endpoints

Browser Configuration

Configure which browser session to use (saved persistently):

POST /api/browser/config     # Set config (saved to file)
GET  /api/browser/config     # Get current config
DELETE /api/browser/config   # Clear config (deletes file)

Instagram Posting

Post to Instagram using signed-in session:

POST /api/instagram/post              # Upload image file
POST /api/instagram/post-with-path    # Use image from server path
POST /api/instagram/post-with-url      # Use image from external URL

Twitter/X Posting

Post to Twitter/X using signed-in session:

POST /api/twitter/post                # Upload image file (optional)
POST /api/twitter/post-with-url       # Use image from external URL (optional)

Twitter Features:

  • βœ… Auto-threading: Text >280 chars automatically splits into thread
  • βœ… Manual splitting: Use --- to specify exact thread breaks
  • βœ… Optional images: Post text-only or with images
  • βœ… Fast typing: Optimized for thread creation

πŸ“– Usage Example

Configure Browser (Run Once)

The config-browser.sh script does this automatically, or manually:

curl -X POST http://YOUR_VM_IP:3000/api/browser/config \
  -H "Content-Type: application/json" \
  -d '{
    "executablePath": "/usr/bin/brave-browser",
    "userDataDir": "/home/YOUR_USER/.config/BraveSoftware/Brave-Browser"
  }'

Post to Instagram

curl -X POST http://YOUR_VM_IP:3000/api/instagram/post \
  -F "[email protected]" \
  -F "caption=Automated post from my VM! πŸš€"

Post to Twitter/X

Simple tweet:

curl -X POST http://YOUR_VM_IP:3000/api/twitter/post \
  -F "text=Hello Twitter! 🐦"

Tweet with image:

curl -X POST http://YOUR_VM_IP:3000/api/twitter/post \
  -F "text=Check out this image! πŸ–ΌοΈ" \
  -F "[email protected]"

Long tweet (auto-threaded):

curl -X POST http://YOUR_VM_IP:3000/api/twitter/post \
  -F "text=This is a very long tweet that exceeds 280 characters and will automatically be split into a thread. The system intelligently breaks it at sentence boundaries to create natural thread breaks. Each tweet will be numbered like (1/3), (2/3), etc."

Manual thread splitting:

curl -X POST http://YOUR_VM_IP:3000/api/twitter/post \
  -F "text=First tweet in my thread.---Second tweet continues the thought.---Final tweet wraps it up."

Tweet with image URL:

curl -X POST http://YOUR_VM_IP:3000/api/twitter/post-with-url \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Tweet with external image!",
    "imageUrl": "https://example.com/image.jpg"
  }'

🎨 Features

  • βœ… Uses existing browser sessions (no credential storage)
  • βœ… VM-friendly deployment (Linux & Windows)
  • βœ… RESTful API with TypeScript
  • βœ… Instagram & Twitter/X support
  • βœ… File upload, server path, or external URL support
  • βœ… Auto-threading for long tweets (>280 chars)
  • βœ… Manual thread splitting with --- markers
  • βœ… Automated setup script for Linux
  • βœ… Persistent browser configuration (survives restarts)
  • βœ… CORS enabled for remote access
  • βœ… Automatic file cleanup
  • βœ… Human-like typing delays and natural behavior

πŸ“ Integration Examples

Python

import requests

VM_URL = "http://your-vm-ip:3000"

# Post to Instagram
files = {'image': open('photo.jpg', 'rb')}
data = {'caption': 'Automated post! πŸš€'}
response = requests.post(f'{VM_URL}/api/instagram/post', files=files, data=data)
print(response.json())

# Post to Twitter (simple tweet)
data = {'text': 'Hello Twitter! 🐦'}
response = requests.post(f'{VM_URL}/api/twitter/post', data=data)
print(response.json())

# Post to Twitter (with image)
files = {'image': open('photo.jpg', 'rb')}
data = {'text': 'Check this out! πŸ–ΌοΈ'}
response = requests.post(f'{VM_URL}/api/twitter/post', files=files, data=data)
print(response.json())

# Post to Twitter (long tweet - auto-threaded)
data = {'text': 'This is a very long tweet that will automatically be split into a thread...'}
response = requests.post(f'{VM_URL}/api/twitter/post', data=data)
print(response.json())

# Post to Twitter (manual thread split)
data = {'text': 'First tweet.---Second tweet.---Third tweet.'}
response = requests.post(f'{VM_URL}/api/twitter/post', data=data)
print(response.json())

Node.js

const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

const VM_URL = 'http://your-vm-ip:3000';

// Post to Instagram
const form = new FormData();
form.append('image', fs.createReadStream('photo.jpg'));
form.append('caption', 'Automated post! πŸš€');
const instagramResponse = await axios.post(`${VM_URL}/api/instagram/post`, form, {
  headers: form.getHeaders()
});
console.log(instagramResponse.data);

// Post to Twitter (simple tweet)
const twitterResponse = await axios.post(`${VM_URL}/api/twitter/post`, {
  text: 'Hello Twitter! 🐦'
}, {
  headers: { 'Content-Type': 'application/json' }
});
console.log(twitterResponse.data);

// Post to Twitter (with image)
const twitterForm = new FormData();
twitterForm.append('text', 'Check this out! πŸ–ΌοΈ');
twitterForm.append('image', fs.createReadStream('photo.jpg'));
const twitterWithImage = await axios.post(`${VM_URL}/api/twitter/post`, twitterForm, {
  headers: twitterForm.getHeaders()
});
console.log(twitterWithImage.data);

// Post to Twitter (long tweet - auto-threaded)
const longTweetResponse = await axios.post(`${VM_URL}/api/twitter/post`, {
  text: 'This is a very long tweet that will automatically be split into a thread...'
}, {
  headers: { 'Content-Type': 'application/json' }
});
console.log(longTweetResponse.data);

cURL

Instagram:

curl -X POST http://your-vm-ip:3000/api/instagram/post \
  -F "[email protected]" \
  -F "caption=Automated post! πŸš€"

Twitter (simple tweet):

curl -X POST http://your-vm-ip:3000/api/twitter/post \
  -F "text=Hello Twitter! 🐦"

Twitter (with image):

curl -X POST http://your-vm-ip:3000/api/twitter/post \
  -F "text=Check this out! πŸ–ΌοΈ" \
  -F "[email protected]"

Twitter (long tweet - auto-threaded):

curl -X POST http://your-vm-ip:3000/api/twitter/post \
  -F "text=This is a very long tweet that will automatically be split into a thread..."

Twitter (manual thread split):

curl -X POST http://your-vm-ip:3000/api/twitter/post \
  -F "text=First tweet.---Second tweet.---Third tweet."

πŸ“Š API Response Format

Success (Instagram)

{
  "success": true,
  "message": "Posted to Instagram successfully",
  "data": {
    "caption": "Automated post! πŸš€",
    "imageSize": 1234567
  }
}

Success (Twitter)

{
  "success": true,
  "message": "Posted to Twitter successfully",
  "data": {
    "text": "Hello Twitter! 🐦",
    "hasImage": false
  }
}

Success (Twitter Thread)

{
  "success": true,
  "message": "Tweet posted successfully!",
  "data": {
    "text": "Long tweet that was auto-threaded...",
    "hasImage": false
  }
}

Error

{
  "success": false,
  "error": "Browser configuration not set"
}

πŸ” Security Considerations

  • No authentication by default - Add auth middleware if exposing publicly
  • CORS enabled - Restrict origins in production
  • No credential storage - Uses browser sessions only
  • Firewall rules - Use SSH tunneling or VPN for secure access

🚦 Best Practices

  1. VM Setup: Use a dedicated VM for each social media account
  2. RDP Security: Use strong passwords and consider SSH tunneling
  3. Rate Limiting: Don't post too frequently (wait 1-2 minutes between posts)
  4. File Handling: Clean up uploaded files (handled automatically)
  5. Browser Sessions: Keep browser logged in with "Remember me"

πŸ› Troubleshooting

Cannot connect via RDP

# Check if xrdp is running
sudo systemctl status xrdp

# Check firewall
sudo ufw status

Browser configuration not set

# Run the config script
./config-browser.sh

# Or manually configure
curl -X POST http://localhost:3000/api/browser/config -H "Content-Type: application/json" -d '{"executablePath":"/usr/bin/brave-browser","userDataDir":"/home/YOUR_USER/.config/BraveSoftware/Brave-Browser"}'

Browser fails to launch (ERROR: Failed to launch browser)

# Install virtual display support
./fix-browser-display.sh

# Or manually install Xvfb
sudo apt-get install -y xvfb
xvfb-run --auto-servernum npm start

Instagram/Twitter session expired

  • Connect via RDP
  • Open Brave browser
  • Log into Instagram/Twitter again with "Remember me" checked
  • Keep browser open or close it (session persists)

Port 3000 already in use

# Change port in the server or kill existing process
lsof -ti:3000 | xargs kill -9

πŸ”§ Server Management

Update Server

To update the server with latest code:

chmod +x update-server.sh
./update-server.sh

This script will:

  • Stop the running server
  • Pull latest code (if using git)
  • Install dependencies
  • Rebuild the project
  • Restart the server

Fix Browser Display Issues

If you get "Failed to launch browser" errors:

chmod +x fix-browser-display.sh
./fix-browser-display.sh

This installs Xvfb (virtual display) so the browser can run without GUI/RDP.

Development

# Development with auto-reload
npm run dev:watch

# Build for production
npm run build

# Run production
npm start

πŸ“ Notes

  • Built with Express, TypeScript, and Puppeteer
  • Tested on Ubuntu 20.04/22.04 LTS and Windows 10/11
  • Works with Brave, Chrome, or Chromium
  • Twitter auto-threading: Automatically splits tweets >280 chars
  • Manual thread control: Use --- to specify exact break points
  • Can be extended for other social media platforms

Need help? Check the setup script logs or open an issue.

About

Social Media Poster via Real Browser Automation on a signed user Account on your VM

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •