npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

x-safe-post

v1.0.0

Published

Post to X/Twitter safely with built-in shadowban avoidance. Human-like timing, rate limiting, content deduplication, and jitter.

Readme

🛡️ x-safe-post

npm version License: MIT TypeScript

Post to X/Twitter with built-in shadowban avoidance. Human-like timing, rate limiting, content deduplication, and jitter - all automatic.

npx x-safe-post post "Hello world!"

Stop getting shadowbanned. Post like a human.


🚀 Quick Start

1. Install

npm install -g x-safe-post
# or use npx
npx x-safe-post --help

2. Configure

x-safe-post config \
  --app-key YOUR_APP_KEY \
  --app-secret YOUR_APP_SECRET \
  --access-token YOUR_ACCESS_TOKEN \
  --access-secret YOUR_ACCESS_SECRET

3. Post

x-safe-post post "My awesome tweet!"

That's it. The tool handles timing, deduplication, and rate limits automatically.


✨ Features

🎲 Human-Like Timing

  • Random jitter on all posts (±30 min by default)
  • Quiet hours (no posting 11pm-6am)
  • Minimum intervals between posts
  • No robotic patterns

🔄 Content Deduplication

  • Tracks all posts for 30 days
  • Blocks duplicate content
  • Warns on similar content (>80% match)
  • Prevents repeat hashtag abuse

⚡ Rate Limit Protection

  • Tracks X API rate limits
  • Auto-backoff when approaching limits
  • Daily post caps (default: 8/day)
  • Graceful handling of 429 errors

🔍 Shadowban Detection

  • Built-in shadowban checker
  • Monitors account health
  • Actionable recommendations

📖 CLI Usage

Post a Tweet

# Basic post
x-safe-post post "Hello world!"

# Reply to a tweet
x-safe-post post "Great point!" --reply-to 1234567890

# Quote tweet
x-safe-post post "This is amazing" --quote 1234567890

# Check safety without posting
x-safe-post post "Test tweet" --dry-run

# Wait if delayed (instead of returning)
x-safe-post post "Hello" --wait

# Skip safety checks (not recommended)
x-safe-post post "YOLO" --force

Check Shadowban Status

x-safe-post check

View Statistics

x-safe-post stats

Configure Settings

# Show current config
x-safe-post config --show

# Set minimum interval to 45 minutes
x-safe-post config --min-interval 45

# Set max 6 posts per day
x-safe-post config --max-daily 6

# Set quiet hours (no posting 10pm - 7am)
x-safe-post config --quiet-start 22 --quiet-end 7

# Disable jitter (not recommended)
x-safe-post config --no-jitter

Get Next Safe Post Time (for cron)

# Human readable
x-safe-post next-time

# Unix timestamp (for scripts)
x-safe-post next-time --unix

# ISO 8601
x-safe-post next-time --iso

Clear History

# Clear post history (allows "duplicate" posts again)
x-safe-post clear --history

# Reset daily counter
x-safe-post clear --daily

# Clear everything
x-safe-post clear --all

💻 Programmatic Usage

import { XSafePost } from 'x-safe-post';

const client = new XSafePost({
  credentials: {
    appKey: 'YOUR_APP_KEY',
    appSecret: 'YOUR_APP_SECRET',
    accessToken: 'YOUR_ACCESS_TOKEN',
    accessSecret: 'YOUR_ACCESS_SECRET',
  },
  safety: {
    minIntervalMinutes: 30,
    maxPostsPerDay: 8,
    enableJitter: true,
    maxJitterMinutes: 30,
    quietHoursStart: 23,
    quietHoursEnd: 6,
  },
});

// Post with safety checks
const result = await client.post({ text: 'Hello from the API!' });

if (result.success) {
  console.log(`Posted! Tweet ID: ${result.tweetId}`);
} else if (result.delayed) {
  console.log(`Delayed until: ${result.scheduledFor}`);
} else if (result.blocked) {
  console.log(`Blocked: ${result.blockReason}`);
}

// Post and wait if delayed
const result2 = await client.postAndWait({ text: 'This will wait if needed' });

// Check content safety before posting
const safety = await client.checkSafety('My tweet with #too #many #hashtags');
console.log(safety.warnings); // ['Too many hashtags (3) - recommend max 2-3']

// Check for shadowban
const shadowban = await client.checkShadowban();
if (shadowban.likely) {
  console.log('Possible shadowban detected!');
}

// Get next safe posting time
const nextTime = client.getNextPostTime();
console.log(`Next safe time: ${nextTime}`);

// Get stats
const stats = client.getStats();
console.log(`Posts today: ${stats.todayPosts}/${stats.maxDailyPosts}`);

⏰ Cron Integration

Basic Cron Job

# Post every 4 hours with random jitter
0 */4 * * * npx x-safe-post post "$(cat /path/to/tweets.txt | shuf -n 1)"

Smart Cron (Check Time First)

#!/bin/bash
# smart-post.sh

NEXT_TIME=$(x-safe-post next-time --unix)
NOW=$(date +%s)

if [ $NOW -ge $NEXT_TIME ]; then
  x-safe-post post "$1"
else
  echo "Not yet safe to post. Next: $(x-safe-post next-time)"
fi

With Queue (Node.js)

import { XSafePost } from 'x-safe-post';
import { CronJob } from 'cron';

const client = new XSafePost({ /* config */ });
const queue: string[] = [
  'Tweet 1',
  'Tweet 2',
  'Tweet 3',
];

// Run every hour, but tool handles actual timing
new CronJob('0 * * * *', async () => {
  if (queue.length === 0) return;
  
  const text = queue.shift()!;
  const result = await client.postAndWait({ text });
  
  if (result.success) {
    console.log(`Posted: ${text}`);
  }
}, null, true);

🛡️ Shadowban Avoidance Tips

This tool handles most issues automatically, but here are extra tips:

Do ✅

  • Vary your content
  • Engage with others (not just post)
  • Use 1-2 hashtags max
  • Post during normal hours
  • Mix media types (text, images, threads)

Don't ❌

  • Post identical content
  • Use 5+ hashtags
  • Post at exact intervals
  • Use URL shorteners
  • Mention-spam people
  • Post 24/7 without breaks

🔧 Configuration Reference

| Option | Default | Description | |--------|---------|-------------| | minIntervalMinutes | 30 | Minimum minutes between posts | | maxPostsPerDay | 8 | Maximum posts per 24 hours | | enableJitter | true | Add random timing variance | | maxJitterMinutes | 30 | Maximum jitter in minutes | | dedupeWindowDays | 7 | Days to check for duplicates | | quietHoursStart | 23 | Hour to start quiet period (0-23) | | quietHoursEnd | 6 | Hour to end quiet period (0-23) | | enableQuietHours | true | Enable quiet hour restrictions |


📄 License

MIT License - see LICENSE


🔗 Links