twitter-rss is a TypeScript tool that generates RSS feeds from Twitter (X.com) search results. It uses the Twitter internal API to fetch recent tweets matching your search queries and converts them into standard RSS 2.0 XML feeds, which can be consumed by any RSS reader.
Note
A Japanese translation of this document is available at README.ja.md.
- RSS 2.0 feeds from Twitter searches β Converts Twitter search results into standard RSS XML files readable by any RSS reader.
- Advanced Twitter query support β Supports all Twitter advanced search operators (
from:,filter:images,exclude:retweets, etc.). - Cookie caching β Caches authentication cookies for up to 30 days to avoid repeated logins.
- Login retry with backoff β Automatically retries logins on transient failures (HTTP 503 with exponential backoff, error 399 with a fixed 120-second delay).
- Two-factor authentication (TOTP) β Supports TOTP-based 2FA via a secret key.
- Proxy and TLS fingerprint spoofing β Uses CycleTLS to spoof TLS fingerprints (JA3) and route requests through an HTTP proxy.
- Ad filtering β Automatically removes promoted tweets from results.
- XSS protection β All user-generated content is HTML-escaped before being embedded in the RSS output.
- Docker support β Includes a
Dockerfileanddocker-compose.ymlfor containerized deployment. - GitHub Actions + GitHub Pages β Automated hourly RSS generation and publishing via GitHub Pages.
- Node.js 24.x
- Yarn 1.22.x
- Xvfb (required at runtime; the underlying scraper requires a virtual display)
- A Twitter (X.com) account with username/password credentials
Warning
SSO (Single Sign-On) authentication is not supported and will not be supported due to technical constraints. You must use a username and password to authenticate.
git clone https://github.com/book000/twitter-rss.git
cd twitter-rssyarn installCreate a .env file in the project root (this file is .gitignore-d):
TWITTER_USERNAME=your_twitter_username
TWITTER_PASSWORD=your_twitter_password
# Optional: required if your account uses email verification on login
TWITTER_EMAIL_ADDRESS=your_email@example.com
# Optional: TOTP secret key for 2FA (base32-encoded)
TWITTER_AUTH_CODE_SECRET=YOUR_TOTP_SECRET
# Optional: proxy settings
PROXY_SERVER=http://proxy.example.com:8080
PROXY_USERNAME=proxyuser
PROXY_PASSWORD=proxypass
# Optional: RSS feed language tag (default: ja)
RSS_LANGUAGE=en
# Optional: path to the search words JSON (default: data/searches.json)
SEARCH_WORD_PATH=data/searches.jsonEdit data/searches.json. Each key is the RSS filename (without .xml) and each value is a Twitter advanced search query:
{
"my-feed-name": "from:someuser filter:images exclude:retweets",
"keyword-search": "some keyword -filter:retweets"
}See Twitter Advanced Search for supported operators.
Start Xvfb and then build/run the tool:
Xvfb :99 -ac -screen 0 600x1000x16 &
export DISPLAY=:99
yarn buildRSS XML files are saved to the output/ directory. An output/index.html listing all feeds is also generated.
| Variable | Required | Default | Description |
|---|---|---|---|
TWITTER_USERNAME |
β | β | Twitter account username |
TWITTER_PASSWORD |
β | β | Twitter account password |
TWITTER_EMAIL_ADDRESS |
β | β | Email address (required if Twitter prompts for email verification during login) |
TWITTER_AUTH_CODE_SECRET |
β | β | TOTP secret key for two-factor authentication |
PROXY_SERVER |
β | β | Proxy server URL (host:port, http://host:port, or https://host:port) |
PROXY_USERNAME |
β | β | Proxy authentication username |
PROXY_PASSWORD |
β | β | Proxy authentication password |
RSS_LANGUAGE |
β | ja |
Language tag embedded in the RSS feed (e.g., en, ja) |
SEARCH_WORD_PATH |
β | data/searches.json |
Path to the search query configuration file |
DISPLAY |
β | :99 |
X display for Xvfb |
The search configuration file is a JSON object where:
- Key: The output filename (used as
<filename>.xml). Special characters, spaces, and path separators are stripped automatically. - Value: The Twitter search query string, including any advanced search operators.
Example:
{
"my-feed": "from:myaccount filter:images exclude:retweets",
"breaking-news": "#breakingnews lang:en -filter:retweets"
}Supported Twitter search operators include:
| Operator | Example | Description |
|---|---|---|
from: |
from:username |
Tweets from a specific user |
to: |
to:username |
Tweets directed at a user |
filter:images |
query filter:images |
Tweets containing images |
filter:videos |
query filter:videos |
Tweets containing videos |
exclude:retweets |
query exclude:retweets |
Exclude retweets |
lang: |
query lang:en |
Filter by language |
-
Create a
data/directory and add yoursearches.json(see Search Configuration):mkdir -p data # Create data/searches.json with your queries (see Search Configuration section) -
Create a
.envfile with your credentials (see Environment Variables). -
Start the container:
docker compose up
The container mounts
./datainto/dataand runs Xvfb + x11vnc internally. A VNC server is exposed on port5910for debugging.
docker build -t twitter-rss .
docker run --env-file .env -v "$(pwd)/data:/data" twitter-rssThe Docker image is based on zenika/alpine-chrome:with-puppeteer-xvfb, which bundles Chromium and Xvfb.
The repository includes two GitHub Actions workflows:
Runs on every push to main/master and on pull requests. Executes build and lint checks using a reusable workflow template.
| Trigger | Description |
|---|---|
schedule: '0 * * * *' |
Runs every hour at minute 0 |
workflow_dispatch |
Manual trigger via GitHub UI |
push to main/master (.ts files) |
Triggered when TypeScript source changes |
Setup steps:
-
Configure repository secrets in GitHub Settings β Secrets and variables β Actions:
Secret Required Description TWITTER_USERNAMEβ Twitter username TWITTER_PASSWORDβ Twitter password TWITTER_EMAIL_ADDRESSβ Email address for login verification TWITTER_AUTH_CODE_SECRETβ TOTP secret for 2FA PROXY_SERVERβ Proxy server URL PROXY_USERNAMEβ Proxy username PROXY_PASSWORDβ Proxy password TWITTER_COOKIES_JSONβ Pre-existing cookies JSON (bootstraps the cache) DISCORD_WEBHOOKβ Discord webhook URL for failure notifications -
Enable GitHub Pages in repository Settings β Pages β Source: GitHub Actions.
-
The workflow runs on a self-hosted runner. Ensure your runner has the following packages installed (listed in
.github/apt-packages.txt):chromium-browser,xvfb,xauth,fonts-noto-cjk,libnss3, and others.
Cookie caching:
The workflow caches data/twitter-cookies.json using actions/cache with a per-run cache key (twitter-cookies-v2-{repo}-{run_id}). On cache miss, it falls back to the TWITTER_COOKIES_JSON secret to bootstrap the session. Cookies are valid for 30 days.
To manually update the TWITTER_COOKIES_JSON secret after a fresh login:
gh secret set TWITTER_COOKIES_JSON --body "$(cat data/twitter-cookies.json)"Failure notifications:
On failure, the workflow sends a Discord embed message to the configured webhook URL.
twitter-rss/
βββ src/
β βββ main.ts # Main application entry point
β βββ model/
β βββ collect-result.ts # RSS Item interface definition
βββ data/
β βββ searches.json # Search query configuration (key: filename, value: query)
βββ .github/
β βββ apt-packages.txt # apt dependencies for self-hosted runner
β βββ workflows/
β βββ nodejs-ci.yml # CI: build + lint check
β βββ update-rss.yml # RSS update + GitHub Pages deployment
βββ Dockerfile # Docker image (zenika/alpine-chrome based)
βββ docker-compose.yml # Docker Compose for local container usage
βββ entrypoint.sh # Docker entrypoint (Xvfb + x11vnc + yarn build)
βββ template.html # HTML template for output/index.html
βββ tsconfig.json # TypeScript compiler settings
βββ eslint.config.mjs # ESLint configuration
βββ .prettierrc.yml # Prettier configuration
Data flow:
main.tsreadsdata/searches.jsonto get search queries.- It authenticates with Twitter using cached cookies or fresh login via
@the-convocation/twitter-scraper(with CycleTLS for TLS fingerprint spoofing). - For each query, it calls the Twitter search API via
twitter-openapi-typescript. - Results are mapped to RSS 2.0
<item>elements (title = JST timestamp, content = tweet text + media images). - XML is written to
output/<filename>.xmlusingfast-xml-parser. output/index.htmlis generated fromtemplate.htmllisting all feeds.
# Install dependencies
yarn install
# Run with hot reload (development)
yarn dev
# Build and run (TypeScript via ts-node)
yarn build
# Compile TypeScript to dist/ (no execution)
yarn compile
# Run compiled output from dist/
yarn start
# Lint (Prettier + ESLint + TypeScript, runs in parallel)
yarn lint
# Auto-fix formatting and linting issues
yarn fixTypeScript configuration:
- Strict mode enabled (
strict: true) noUnusedLocalsandnoUnusedParametersenforcedskipLibCheckis explicitly forbidden
- No SSO: Only username/password authentication is supported.
- Credentials: All secrets are managed via environment variables or
.envfiles. Never commit.envordata/twitter-cookies.json. - XSS prevention: All tweet text and media URLs are HTML-escaped before being embedded in RSS output.
- Path traversal prevention: RSS filenames derived from
data/searches.jsonkeys are sanitized (removes..,/,\, and other dangerous characters). - Cookie safety: Authentication cookies are stored only in
data/twitter-cookies.json(excluded from Git) and cached in GitHub Actions secrets/cache.
MIT License β Copyright (c) 2023 Tomachi. See LICENSE for details.