Documentation Index
Fetch the complete documentation index at: https://docs.onlyautomator.com/llms.txt
Use this file to discover all available pages before exploring further.
The OnlyAutomator Microservice is a crucial backend component that processes OnlyFans creator accounts, collecting analytics data and storing it in the Supabase database. This service works both autonomously through scheduled cron jobs and on-demand via API endpoints.
System Architecture
The microservice consists of two primary components:
- Express Server: Handles API requests for manually triggering account processing
- Cron Job: Automatically processes all connected accounts at regular intervals
Both components share the core business logic for data collection but operate independently, allowing for flexibility in how data is gathered.
Technology Stack
The microservice leverages a modern Node.js ecosystem:
Core Technologies
- Node.js (v18+): JavaScript runtime environment
- TypeScript (v5.5+): Typed superset of JavaScript for robust code
- Express.js (v4.19+): Fast, unopinionated web framework
- PM2 (v5+): Advanced production process manager with integrated load balancer
Web Scraping & Automation
- Puppeteer (v22+): Headless Chrome API for automated web interactions
- Puppeteer-core: Lightweight version with reduced footprint
Database & Storage
- Supabase: Open source Firebase alternative
- PostgreSQL: Advanced relational database for structured data storage
Queue & Task Management
- Better-Queue: Priority queue with concurrency control
- Multi-Queue System: Load balancing across parallel queues
Logging & Monitoring
- Winston: Versatile logging library with multiple transports
- Morgan: HTTP request logger middleware for Express
Data Flow Process
The microservice collects data through the following process:
Implementation Details
Authentication Mechanism
The microservice uses browser storage data (cookies, localStorage, sessionStorage) collected from users’ devices to authenticate with OnlyFans:
// Authentication using storage data from accounts table
export async function getCreatorData(
userId: string,
accountId: string,
username: string,
userAgent: string,
localStorage: Json | null,
sessionStorage: Json | null,
cookies: Json | null,
isDebug: boolean = false
) {
// Initialize browser with collected authentication data
const browser = await puppeteer.launch({
headless: !isDebug,
args: [
'--disable-extensions',
'--disable-gpu',
'--no-sandbox',
'--disable-setuid-sandbox',
]
});
try {
const page = await browser.newPage();
await page.setUserAgent(userAgent);
// Set cookies from stored data
if (cookies) {
for (const cookie of Object.values(cookies)) {
await page.setCookie(cookie);
}
}
// Navigate to OnlyFans and inject localStorage/sessionStorage
await page.goto('https://onlyfans.com/');
if (localStorage) {
await page.evaluate((storageData) => {
for (const [key, value] of Object.entries(storageData)) {
window.localStorage.setItem(key, value as string);
}
}, localStorage);
}
if (sessionStorage) {
await page.evaluate((storageData) => {
for (const [key, value] of Object.entries(storageData)) {
window.sessionStorage.setItem(key, value as string);
}
}, sessionStorage);
}
// Proceed with data extraction
// ...
} finally {
await browser.close();
}
}
Queue Management
The service implements a multi-queue system for concurrent processing:
const NUM_QUEUES = 3; // Default number of concurrent queues
const queues: Queue[] = [];
let currentQueueIndex = 0; // Round-robin queue selection
// Initialize multiple processing queues
for (let i = 0; i < NUM_QUEUES; i++) {
const queue = new Queue(async function(accountData, cb) {
logger.info(`Queue Function called in Queue ${i}`);
getCreatorData(
accountData.user_id,
accountData.id.toString(),
accountData.username,
accountData.user_agent,
accountData.web_local_storage ? accountData.web_local_storage : null,
accountData.web_session_storage ? accountData.web_session_storage : null,
accountData.web_cookies ? accountData.web_cookies : null,
false
)
.then(() => {
logger.info(`Finished processing account data for ${accountData.id} in Queue ${i}`);
cb();
return true;
})
.catch((error) => {
console.error(
'Error in account',
accountData.name,
accountData.username,
error.message
);
cb(`Error in account: ${accountData.name}, ${accountData.username}, ${error.message}`);
});
});
queues.push(queue);
// Log queue statistics daily
setInterval(
() => logger.info(`Queue ${i} stats: ${queue.getStats()}`),
24 * 60 * 60 * 1000
);
}
API Endpoints
| Endpoint | Method | Description |
|---|
/api/test | GET | Health check endpoint to verify service status |
/api/process-account/:accountId | POST | Manually trigger processing for a specific account |
Environment Variables
The microservice relies on the following environment variables for configuration:
# Core configuration
PORT=3001 # Port for the Express server
NEXT_PUBLIC_SITE_URL=http://localhost:3000/ # URL of the web application
# Security
CRON_SECRET=your_cron_secret # Secret for securing cron routes
API_SECRET=your_api_secret # Secret for API authentication
# Supabase connection
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
In the production environment, these variables are securely stored in PM2’s ecosystem configuration file and passed to the application at runtime.
Development Environment Setup
To set up the microservice for local development:
-
Clone the repository
git clone https://github.com/OnlyAutomator/only-automator-microservice.git
cd only-automator-microservice
-
Install dependencies
-
Configure environment variables
Create a
.env file with the required variables:
# Core configuration
PORT=3001
NEXT_PUBLIC_SITE_URL=http://localhost:3000/
# Supabase connection
SUPABASE_URL=https://qyzigfweeamoatcrnpgc.supabase.co
SUPABASE_ANON_KEY=your_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
# Security
CRON_SECRET=your_cron_secret
API_SECRET=your_api_secret
-
Generate Supabase type definitions
-
Build the TypeScript code
-
Start the service in development mode
Production Deployment
For production deployment, we use PM2 to manage the application processes:
-
Build the application
-
Configure PM2
The
ecosystem.config.js file contains the PM2 configuration:
module.exports = {
apps: [{
name: 'express-server',
script: 'build/app.js',
instances: 1,
autorestart: true,
watch: false,
env: {
SUPABASE_URL: process.env.SUPABASE_URL,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY,
SUPABASE_SERVICE_ROLE_KEY: process.env.SUPABASE_SERVICE_ROLE_KEY,
NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
PORT: process.env.PORT,
CRON_SECRET: process.env.CRON_SECRET,
API_SECRET: process.env.API_SECRET,
},
},
{
name: 'cron-job',
script: 'build/cron_job.js',
cron_restart: '* * * * *', // restart every minute
// cron_restart: '0 */6 * * *', // every 6 hours (production recommendation)
env: {
SUPABASE_URL: process.env.SUPABASE_URL,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY,
SUPABASE_SERVICE_ROLE_KEY: process.env.SUPABASE_SERVICE_ROLE_KEY,
NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
PORT: process.env.PORT,
CRON_SECRET: process.env.CRON_SECRET,
API_SECRET: process.env.API_SECRET,
},
}],
};
-
Start the application with PM2
pm2 start ecosystem.config.js
-
Configure PM2 to start on system boot
-
Monitor the application
pm2 status # Check process status
pm2 logs # View logs
pm2 monit # Monitor CPU and memory usage
Cron Job Configuration
The cron job automatically processes all accounts at regular intervals. The schedule is configured in ecosystem.config.js:
{
name: 'cron-job',
script: 'build/cron_job.js',
cron_restart: '* * * * *', // Every minute (for testing)
// cron_restart: '0 */6 * * *', // Every 6 hours (recommended for production)
}
To modify the schedule, update the cron_restart parameter using standard cron syntax:
* * * * *
│ │ │ │ │
│ │ │ │ └─── day of week (0-7, where 0 and 7 are Sunday)
│ │ │ └───── month (1-12)
│ │ └─────── day of month (1-31)
│ └───────── hour (0-23)
└─────────── minute (0-59)
Common examples:
*/30 * * * *: Every 30 minutes
0 */6 * * *: Every 6 hours
0 0 * * *: Once a day at midnight
0 0 * * 0: Once a week on Sunday
Scaling Considerations
Vertical Scaling
- Increase server resources (CPU/RAM) to handle more concurrent processes
- Adjust Node.js memory limits with
--max-old-space-size flag:
NODE_OPTIONS="--max-old-space-size=4096" npm run start
Horizontal Scaling
- Deploy multiple instances behind a load balancer
- Use PM2 cluster mode for the Express server:
{
name: 'express-server',
script: 'build/app.js',
instances: 'max', // Use maximum available CPUs
exec_mode: 'cluster',
}
Queue Optimization
- Adjust the number of concurrent queues based on server capacity:
const NUM_QUEUES = 3; // Default is 3, increase for higher concurrency
- Implement priority queueing for critical accounts:
const queue = new Queue({
priority: function(task, cb) {
// Determine task priority (lower number = higher priority)
if (task.isPremium) return cb(null, 1);
return cb(null, 10);
}
});
The microservice extracts several types of data from OnlyFans:
-
User Statistics
- Subscriber count and growth rate
- Revenue metrics
- Content engagement metrics
-
Engagement Metrics
- Message response rates
- Fan interaction frequency
- Content popularity analytics
-
Fan Data
- Active subscribers list
- Spending patterns
- Engagement behavior
The data extraction process uses Puppeteer to navigate through various pages on OnlyFans, executing a sequence of operations:
// Example of statistics extraction logic
async function extractStatisticsData(page) {
await page.goto('https://onlyfans.com/my/statistics/');
await page.waitForSelector('.stats-card');
return await page.evaluate(() => {
const stats = {};
// Extract subscriber metrics
const subCount = document.querySelector('.subscribers-count');
if (subCount) stats.subscriberCount = parseInt(subCount.textContent.trim(), 10);
// Extract revenue metrics
const revenue = document.querySelector('.revenue-total');
if (revenue) stats.totalRevenue = parseFloat(revenue.textContent.replace(/[^0-9.]/g, ''));
// Extract other metrics...
return stats;
});
}
Troubleshooting
| Issue | Solution |
|---|
| Connection timeout | Increase Puppeteer navigation timeout: page.setDefaultNavigationTimeout(60000); |
| Memory leaks | Ensure Puppeteer instances are closed properly in finally blocks |
| Database errors | Verify Supabase credentials and check database schema compatibility |
| Queue bottlenecks | Increase the number of concurrent queues and monitor queue statistics |
| Cron job failures | Check logs with pm2 logs cron-job and verify environment variables |
For deeper debugging, enable verbose logging by adjusting the Winston logger configuration:
// Set Winston to debug level
const logger = winston.createLogger({
level: 'debug', // Change from 'info' to 'debug'
format: winston.format.combine(
winston.format.timestamp(),
winston.format.printf(({ level, message, timestamp }) => {
return `${timestamp} ${level}: ${message}`;
})
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
new winston.transports.File({ filename: 'logs/combined.log' })
]
});
Security Best Practices
- Environment Variables: All sensitive credentials stored in environment variables
- API Authentication: API endpoints secured with API_SECRET token validation
- CORS Policy: Configured for specific origins in production:
app.use(cors({
origin: process.env.NODE_ENV === 'production'
? [process.env.NEXT_PUBLIC_SITE_URL]
: '*',
methods: ['GET', 'POST', 'OPTIONS'],
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization']
}));
- Helmet.js: Secures Express app with various HTTP headers:
app.use(helmet({
crossOriginResourcePolicy: { policy: "cross-origin" },
contentSecurityPolicy: false
}));
- Input Validation: All API inputs validated before processing
- Regular Updates: Dependencies kept updated to patch security vulnerabilities
Integration with Other Components
- Web Application: Displays data collected by the microservice through Supabase real-time subscriptions
- Chrome Extension: Provides authentication data (cookies, localStorage, sessionStorage) for the microservice
- Supabase Database: Stores all processed data and enables real-time updates through PostgreSQL change data capture