Skip to content

Commit 7fdfec6

Browse files
committed
chore: add cycletls example and use separate export
1 parent 1e6f5dc commit 7fdfec6

File tree

11 files changed

+816
-15
lines changed

11 files changed

+816
-15
lines changed

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,41 @@ const scraper = new Scraper({
168168
});
169169
```
170170

171+
### Bypassing Cloudflare bot detection
172+
173+
In some cases, Twitter's authentication endpoints may be protected by Cloudflare's advanced bot detection, resulting in `403 Forbidden` errors during login. This typically happens because standard Node.js TLS fingerprints are detected as non-browser clients.
174+
175+
To bypass this protection, you can use the optional CycleTLS integration, which uses golang to mimic Chrome browser TLS fingerprints:
176+
177+
**Installation:**
178+
179+
```sh
180+
npm install cycletls
181+
# or
182+
yarn add cycletls
183+
```
184+
185+
**Usage:**
186+
187+
```ts
188+
import { Scraper } from '@the-convocation/twitter-scraper';
189+
import { cycleTLSFetch, cycleTLSExit } from '@the-convocation/twitter-scraper/cycletls';
190+
191+
const scraper = new Scraper({
192+
fetch: cycleTLSFetch,
193+
});
194+
195+
// Use the scraper normally
196+
await scraper.login(username, password, email);
197+
198+
// Important: cleanup CycleTLS resources when done
199+
cycleTLSExit();
200+
```
201+
202+
**Note:** The `/cycletls` entrypoint is Node.js only and will not work in browser environments. It's provided as a separate optional entrypoint to avoid bundling golang dependencies in environments where they cannot run.
203+
204+
See the [cycletls-cloudflare example](./examples/cycletls-cloudflare/) for a complete working example.
205+
171206
### Rate limiting
172207
The Twitter API heavily rate-limits clients, requiring that the scraper has its own
173208
rate-limit handling to behave predictably when rate-limiting occurs. By default, the

examples/cycletls/README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# CycleTLS Cloudflare Bypass Example
2+
3+
This example demonstrates how to use the `@the-convocation/twitter-scraper/cycletls` entrypoint to bypass Cloudflare bot detection when authenticating with Twitter.
4+
5+
## Problem
6+
7+
Twitter's authentication endpoints may be protected by Cloudflare's advanced bot detection, which analyzes TLS fingerprints to detect non-browser clients. Standard Node.js TLS handshakes can trigger `403 Forbidden` errors during login.
8+
9+
## Solution
10+
11+
This example uses [CycleTLS](https://github.com/Danny-Dasilva/CycleTLS), which leverages golang to mimic Chrome browser TLS fingerprints, allowing requests to pass through Cloudflare's protection.
12+
13+
## Installation
14+
15+
```sh
16+
yarn install
17+
```
18+
19+
## Configuration
20+
21+
Create a `.env` file in the root of the repository (two levels up) with your Twitter credentials:
22+
23+
```
24+
TWITTER_USERNAME=your_username
25+
TWITTER_PASSWORD=your_password
26+
TWITTER_EMAIL=your_email
27+
```
28+
29+
## Usage
30+
31+
```sh
32+
yarn start
33+
```
34+
35+
## How it works
36+
37+
The example imports the `cycleTLSFetch` function from the `/cycletls` subpath:
38+
39+
```ts
40+
import { Scraper } from '@the-convocation/twitter-scraper';
41+
import { cycleTLSFetch, cycleTLSExit } from '@the-convocation/twitter-scraper/cycletls';
42+
43+
const scraper = new Scraper({
44+
fetch: cycleTLSFetch as any,
45+
});
46+
```
47+
48+
This replaces the default fetch implementation with one that uses Chrome-like TLS fingerprints, bypassing Cloudflare's detection.
49+
50+
## Important Notes
51+
52+
- **Node.js only**: The `/cycletls` entrypoint requires Node.js and will not work in browsers
53+
- **Cleanup required**: Always call `cycleTLSExit()` when done to cleanup golang resources
54+
- **Optional dependency**: `cycletls` must be explicitly installed alongside the main package

examples/cycletls/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"private": true,
3+
"packageManager": "[email protected]",
4+
"scripts": {
5+
"start": "tsx src/index.ts"
6+
},
7+
"dependencies": {
8+
"@the-convocation/twitter-scraper": "file:../../",
9+
"cycletls": "^2.0.4",
10+
"tsx": "^4.15.5"
11+
}
12+
}

examples/cycletls/src/index.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import assert from 'node:assert';
2+
import { Scraper } from '@the-convocation/twitter-scraper';
3+
import {
4+
cycleTLSFetch,
5+
cycleTLSExit,
6+
} from '@the-convocation/twitter-scraper/cycletls';
7+
8+
/**
9+
* Example: Using CycleTLS to bypass Cloudflare bot detection
10+
*
11+
* CycleTLS uses golang to mimic Chrome browser TLS fingerprints, which helps
12+
* bypass Cloudflare's advanced bot detection. This is particularly useful
13+
* when you encounter 403 errors during authentication.
14+
*
15+
* Usage:
16+
* 1. Install cycletls: yarn add cycletls
17+
* 2. Pass cycleTLSFetch as the fetch option when creating a Scraper
18+
* 3. Make sure to call cycleTLSExit() when done to cleanup resources
19+
*/
20+
21+
// Load credentials from the environment
22+
const username = process.env['TWITTER_USERNAME'];
23+
const password = process.env['TWITTER_PASSWORD'];
24+
const email = process.env['TWITTER_EMAIL'];
25+
26+
assert(username && password && email, 'Missing required environment variables');
27+
28+
// Create scraper with CycleTLS fetch
29+
const scraper = new Scraper({
30+
fetch: cycleTLSFetch as any,
31+
});
32+
33+
const main = async () => {
34+
try {
35+
console.log('Logging in with CycleTLS-powered requests...');
36+
await scraper.login(username, password, email);
37+
38+
console.log('Login successful! Fetching a tweet...');
39+
const tweet = await scraper.getTweet('1585338303800578049');
40+
41+
console.log('Tweet details:');
42+
console.log(`- Text: ${tweet?.text}`);
43+
console.log(`- Likes: ${tweet?.likes}`);
44+
console.log(`- Retweets: ${tweet?.retweets}`);
45+
} catch (error) {
46+
console.error('Error:', error);
47+
} finally {
48+
// Important: cleanup CycleTLS resources
49+
cycleTLSExit();
50+
}
51+
};
52+
53+
main();

examples/cycletls/tsconfig.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "./dist"
5+
},
6+
"include": ["src"]
7+
}

0 commit comments

Comments
 (0)