notion-twitter-sync
v1.1.1
Published
Automatic sync tool with web dashboard that manages your Twitter posting queue from Notion, text files, and manual entries
Maintainers
Readme
Notion-Twitter Sync
Automatic sync tool with web dashboard that manages your Twitter posting queue from multiple sources:
- Notion database (checks every 15 minutes for "Done" items)
- Text file (checks tweets.txt every 15 minutes)
- Manual entry via dashboard
Features
- Web Dashboard at http://localhost:3000
- View posting queue and posted tweets
- Add, edit, and delete tweets
- Manual triggers for Notion and file sync
- Character count display for tweets
- Notion Integration - Auto-sync items marked as "Done"
- File-Based Queue - Add tweets via tweets.txt file
- Scheduled Posting - Posts tweets at regular intervals
- Dry Run Mode - Test without actually posting to Twitter
Setup
1. Notion API Setup
- Go to https://www.notion.so/my-integrations
- Click "+ New integration"
- Enter a name (e.g., "Twitter Sync")
- Copy the "Internal Integration Token" - this is your
NOTION_API_KEY - Go to your Notion database
- Click the three dots in the top right → "Add connections" → Select your integration
- Copy the Database ID from the URL:
- URL Format:
notion.so/workspace/{database_id}?v=... - The Database ID is the part between the last
/and?
- URL Format:
2. Twitter API Setup
- Go to https://developer.twitter.com/en/portal/dashboard
- Create a new project and app (if not already done)
- Go to your app → "Keys and tokens"
- Generate the following credentials:
- API Key and Secret (App Key/Secret)
- Access Token and Secret
- Make sure the app has "Read and Write" permissions
3. Installation
cd notion-twitter-sync
npm install4. Configuration
Copy
.env.exampleto.env:cp .env.example .envFill in the
.envfile with your credentials:NOTION_API_KEY=secret_xxx... NOTION_DATABASE_ID=xxx... TWITTER_APP_KEY=xxx... TWITTER_APP_SECRET=xxx... TWITTER_ACCESS_TOKEN=xxx... TWITTER_ACCESS_SECRET=xxx... DRY_RUN=true PORT=3000 DASHBOARD_PASSWORD=your_secure_passwordImportant: Set a strong password for
DASHBOARD_PASSWORDto protect your dashboard. Without this, anyone can access and modify your tweet queue!Set up the tweets file:
cp tweets.example.txt tweets.txtEdit
tweets.txtand add your tweets (one per line). Empty lines and lines starting with#are ignored.
5. Notion Database Requirements
Your Notion database must have the following properties:
- Status (Type: Status) - with a value "Done"
- Name, Title, or Task (Type: Title) - for the tweet text
The script automatically searches for these standard property names.
Usage
Start
npm run devThe application:
- Starts the web dashboard at http://localhost:3000
- Checks immediately for new Done items in Notion
- Checks immediately for new tweets in tweets.txt
- Runs both checks automatically every 15 minutes
- Posts only new items (no duplicates)
- Saves state in
sync-state.jsonandfile-state.json
Stop
Press Ctrl+C to stop the application.
Web Dashboard
Access the dashboard at http://localhost:3000 to:
- View Queue: See all tweets waiting to be posted with character counts
- View Posted: See all tweets that have been posted
- Add Tweets: Manually add new tweets to the queue
- Edit/Delete: Modify or remove tweets from the queue
- Manual Sync:
- "Pull from Notion" - Manually trigger Notion sync
- "Pull from tweets.txt" - Manually trigger file sync
- "Post Next Tweet" - Immediately post the next tweet in queue
File-Based Queue (tweets.txt)
The tweets.txt file allows you to queue tweets without using the dashboard:
- Edit
tweets.txtand add your tweets (one per line) - Empty lines and lines starting with
#are ignored - The file is checked every 15 minutes
- New tweets are automatically added to the posting queue
Example tweets.txt:
# My Tweet Queue
# Add one tweet per line
Just shipped a new feature! Check it out.
Working on something exciting. More details soon.
# This is a comment and will be ignored
Another tweet to post later.How It Works
Every 15 Minutes:
- Queries Notion API for all items with Status "Done"
- Checks tweets.txt for new lines
- Compares with already posted items (stored in state files)
- Adds new items to the posting queue
Avoiding Duplicates:
- Each Notion Page ID is saved after first sync
- Each line number in tweets.txt is tracked
- Already processed items are skipped
Posting:
- Posts are sent to Twitter (or logged if DRY_RUN=true)
- Posted items are moved to the "Posted" section
- Character limit: 280 characters
Configuration Options
Dashboard Authentication
The dashboard is protected by HTTP Basic Authentication. When you access the dashboard, your browser will prompt you to enter credentials:
- Username: Enter anything (e.g., "admin" or "user") - the username is completely ignored by the system
- Password: Must match
DASHBOARD_PASSWORDfrom.env
Note: HTTP Basic Auth requires both fields, but only the password is actually checked. The username field is there because it's part of the authentication standard, but you can type literally anything.
Security Notes:
- Always set a strong password when deploying to production
- If
DASHBOARD_PASSWORDis not set, authentication is disabled (not recommended for production!) - Use HTTPS in production to encrypt credentials during transmission
- The password is checked on every request to the dashboard and API endpoints
Dry Run Mode
Set DRY_RUN=true in .env to test without posting to Twitter. Posts will only be logged to the console.
Change Port
Change the PORT value in .env (default: 3000).
Change Interval
To change from 15 minutes to another interval, edit src/modules/schedule/schedule.scheduler.ts:
// For 30 minutes
cron.schedule('*/30 * * * *', async () => {Different Status Than "Done"
Edit the Notion filter in src/services/NotionService.ts:
status: {
equals: 'In Progress' // or another status name
}Autostart on System Boot (Optional)
macOS (with launchd)
- Create the file
~/Library/LaunchAgents/com.notion-twitter-sync.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.notion-twitter-sync</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/node</string>
<string>/Users/YOUR_USERNAME/work/projects/notion-twitter-sync/dist/server.js</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/YOUR_USERNAME/work/projects/notion-twitter-sync/output.log</string>
<key>StandardErrorPath</key>
<string>/Users/YOUR_USERNAME/work/projects/notion-twitter-sync/error.log</string>
</dict>
</plist>Adjust the path (replace
YOUR_USERNAME)Load the service:
launchctl load ~/Library/LaunchAgents/com.notion-twitter-sync.plist- Start service:
launchctl start com.notion-twitter-syncWindows (with Task Scheduler)
- Open Task Scheduler
- Create a new task
- Trigger: At logon
- Action:
node.exewith argument to path ofdist/server.js
Linux (with systemd)
- Create
/etc/systemd/system/notion-twitter-sync.service:
[Unit]
Description=Notion Twitter Sync
After=network.target
[Service]
Type=simple
User=YOUR_USERNAME
WorkingDirectory=/path/to/notion-twitter-sync
ExecStart=/usr/bin/node dist/server.js
Restart=always
[Install]
WantedBy=multi-user.target- Enable service:
sudo systemctl enable notion-twitter-sync
sudo systemctl start notion-twitter-syncTroubleshooting
"Missing required environment variables"
- Check if the
.envfile exists and all values are filled in
"Error fetching from Notion"
- Make sure the integration has access to the database
- Check if the Database ID is correct
- Verify that the property "Status" with value "Done" exists
"Error posting to Twitter"
- Check the Twitter API credentials
- Make sure the app has "Read and Write" permissions
- Rate Limits: Twitter allows 300 tweets per 3 hours
No new posts despite Done items
- Check the
sync-state.jsonfile - Delete it to re-process all items (Warning: may create duplicates!)
- Check the logs in the console
tweets.txt not being processed
- Check
file-state.json- it tracks which lines have been processed - Make sure tweets.txt has new lines after the
processedLinescount - Reset
file-state.jsonby settingprocessedLinesto 0 if needed
Project Structure
notion-twitter-sync/
├── src/
│ ├── config/ # Configuration management
│ ├── modules/ # Feature modules (notion, twitter, schedule, file)
│ ├── services/ # Business logic services
│ └── types/ # TypeScript type definitions
├── public/ # Web dashboard (HTML/CSS/JS)
├── dist/ # Compiled JavaScript (generated)
├── tweets.txt # File-based tweet queue
├── tweets.example.txt # Example file to get started
├── sync-state.json # Notion sync state
├── file-state.json # File sync state
├── queue-state.json # Posting queue state
└── server.ts # Application entry pointSecurity
- The
.envfile is in.gitignoreand won't be committed to Git - Never share your API keys publicly
- The
sync-state.jsoncontains only Notion Page IDs (no sensitive data) - The
queue-state.jsoncontains tweet texts and metadata
License
MIT
