A tool for downloading TikTok videos with or without watermarks and automatically uploading them to Facebook Reels
—
Browser automation system for uploading videos to Facebook Reels using Puppeteer. Handles session management through exported cookies, video upload workflow, caption input, and video duration validation.
Main function for uploading videos to Facebook Reels with automated browser workflow.
/**
* Upload video to Facebook Reels via browser automation
* @param namafile - Filename without extension (video should exist in ./download/ directory)
* @param caption - Video caption/description to add
* @returns Promise resolving to upload result status
*/
function ReelsUpload(namafile: string, caption: string): Promise<UploadResult>;
interface UploadResult {
/** Upload status indicator */
status: 'success' | 'error';
/** Descriptive message about upload result */
message: string;
}Usage Examples:
import { ReelsUpload } from './lib/browserHandler.js';
// Basic upload (requires cookies.json and video file)
const result = await ReelsUpload('video123', 'Check out this amazing video! #viral');
if (result.status === 'success') {
console.log('Upload successful:', result.message);
} else {
console.log('Upload failed:', result.message);
}
// Handle different outcomes
const uploadResult = await ReelsUpload('longvideo', 'My caption');
switch (uploadResult.status) {
case 'success':
console.log('Video published to Reels');
break;
case 'error':
console.log('Failed:', uploadResult.message);
break;
}Functions for managing Facebook authentication through exported cookies.
/**
* Check if valid Facebook session cookies exist
* @returns Promise resolving to boolean indicating session validity
*/
function checkSession(): Promise<boolean>;
/**
* Generate timestamped console log message
* @param str - Message to log with timestamp
*/
function printLog(str: string): void;Usage Examples:
// Check session before attempting upload
const hasValidSession = await checkSession();
if (!hasValidSession) {
console.log('Please export Facebook cookies to cookies.json');
return;
}
// Logging with timestamps
printLog('Starting upload process...');
// Output: [14:30:25] Starting upload process...The module uses specific Puppeteer configuration for Facebook compatibility:
interface BrowserConfig {
/** Chrome executable path from puppeteer */
executablePath: string;
/** Headless mode (set to false for debugging) */
headless: boolean;
/** Chrome launch arguments */
args: string[];
}
const browserOptions: BrowserConfig = {
executablePath: executablePath("chrome"),
headless: false,
args: [
'--user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"',
'--no-sandbox',
'--mute-audio'
]
};interface PageOptions {
/** Wait condition for page loads */
waitUntil: 'networkidle0' | 'load' | 'domcontentloaded';
}
const browserPageOpt: PageOptions = { waitUntil: 'networkidle0' };XPath selectors used for Facebook Reels UI automation. These are critical for the upload workflow and may need updates if Facebook changes their interface.
/** Facebook UI element selectors */
interface FacebookSelectors {
/** Upload button selector */
uploadButtonSelector: string;
/** Next button selectors for different steps */
nextButtonSelector: string;
nextButtonSelector2: string;
nextButtonSelector3: string;
/** Caption text area selector */
textAreaSelector: string;
/** Publish button selector */
publishButtonSelector: string;
/** Upload completion indicator */
ended: string;
/** 90-second duration limit detector */
s90detector: string;
/** Video cutting tool selector */
cutvideoSelector: string;
}
// Current XPath selectors (may change with Facebook UI updates)
const selectors: FacebookSelectors = {
uploadButtonSelector: '/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/form/div/div/div[1]/div/div[2]/div[1]/div[2]/div/div/div[1]/div/div/div/div/div/div[1]',
nextButtonSelector: '//*[starts-with(@id, "mount")]/div/div[1]/div/div[3]/div/div/div[1]/form/div/div/div[1]/div/div[3]/div[2]/div/div/div',
nextButtonSelector2: '//*[starts-with(@id, "mount")]/div/div[1]/div/div[3]/div/div/div[1]/form/div/div/div[1]/div/div[3]/div[2]/div[2]/div[1]/div',
nextButtonSelector3: '/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/form/div/div/div[1]/div/div[3]/div[2]/div[2]/div[1]',
textAreaSelector: '//*[starts-with(@id, "mount")]/div/div[1]/div/div[3]/div/div/div[1]/form/div/div/div[1]/div/div[2]/div[1]/div[2]/div/div/div/div/div[1]/div[1]/div[1]',
publishButtonSelector: '/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/form/div/div/div[1]/div/div[3]/div[2]/div[2]/div[1]/div/div[1]/div',
ended: '/html/body/div[1]/div/div[1]/div/div[5]/div/div/div[3]/div[2]/div/div/div[1]/div/div/div/div/div[2]/div[1]/div/div/div[2]/div[2]',
s90detector: '/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/form/div/div/div[1]/div/div[3]/div[1]/div[1]/div/div/div/div[2]/div/div/div/div/span/span',
cutvideoSelector: '/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/form/div/div/div[1]/div/div[2]/div[1]/div[2]/div/div/div/div/div/div/div[1]/div/div'
};The upload process follows these automated steps:
Facebook Reels have a 90-second limit. The module automatically detects videos over this limit:
// If video exceeds 90 seconds, the upload will fail with:
{
status: "error",
message: "Video Gagal di publish!"
}The module requires a cookies.json file containing exported Facebook session cookies:
// cookies.json format (array of cookie objects)
[
{
"name": "cookie_name",
"value": "cookie_value",
"domain": ".facebook.com",
"path": "/",
"expires": 1234567890,
"httpOnly": true,
"secure": true
}
// ... more cookies
]Videos must be placed in the ./download/ directory with .mp4 extension:
./download/{namafile}.mp4namafile (meaning "filename")Additional session and browser configuration options:
/** Browser visibility control */
const browserHide: boolean = false;
/**
* Print timestamped log messages
* @param str - Message to log
*/
function printLog(str: string): void;
/**
* Check if valid Facebook session exists
* @returns Promise resolving to session validity
*/
function checkSession(): Promise<boolean>;Common error scenarios and their handling:
Session Errors:
{
status: "error",
message: "INFO: Session tidak ditemukan..."
}Upload Errors:
{
status: "error",
message: "Video Gagal di publish!"
}Duration Errors:
"Durasi video tidak boleh lebih dari 90 detik."Specific Error Messages:
// Indonesian language error messages used in implementation
{
status: "error",
message: "INFO: Session tidak ditemukan..." // "Session not found"
}
{
status: "error",
message: "Video Gagal di publish!" // "Video failed to publish"
}
// Console messages during processing
"Durasi video tidak boleh lebih dari 90 detik." // "Video duration cannot exceed 90 seconds"
"Video lebih dari 90 detik tidak terdeteksi" // "Video over 90 seconds not detected"
"Berhasil membuka fb" // "Successfully opened Facebook"
"Menginput Caption..." // "Inputting caption..."
"Post ke Reels" // "Post to Reels"
"Berhasil" // "Success"The module uses XPath selectors to interact with Facebook's interface. Key interaction points:
All browser interactions include appropriate delays and wait conditions to ensure reliable automation.
Install with Tessl CLI
npx tessl i tessl/npm-tiktok-src