You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make curl_cffi the sole HTTP dependency, remove requests and httpx
Facebook blocks any HTTP client without Chrome-like TLS fingerprints,
making requests and httpx dead-weight fallbacks that fail with 403.
curl_cffi is now required (not optional), and the [stealth] and [async]
extras are removed. Installation is simplified to just `pip install
meta-ads-collector`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+15-2Lines changed: 15 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
5
5
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
8
+
## [1.3.0] - 2026-02-21
9
+
10
+
### Changed
11
+
-**curl_cffi is now the sole HTTP dependency.** Removed `requests` and `httpx` entirely. Facebook blocks any HTTP client without Chrome-like TLS fingerprints, so `curl_cffi` (with `impersonate="chrome"`) is the only backend that actually works. Both `requests` and `httpx` were dead-weight fallbacks that failed with HTTP 403.
12
+
-**Simplified installation.**`pip install meta-ads-collector` now includes everything -- no more `[stealth]` or `[async]` extras needed.
13
+
-**Async client simplified.** Removed the `_AsyncResponse` wrapper and httpx fallback code paths. The async client now uses `curl_cffi.AsyncSession` directly.
14
+
- Renamed `ProxyPool.get_requests_proxies()` to `get_proxy_dict()`.
15
+
16
+
### Removed
17
+
-`requests` dependency (was required, now removed)
18
+
-`httpx` dependency and `[async]` optional extra
19
+
-`[stealth]` optional extra (curl_cffi is now always installed)
20
+
-`types-requests` from dev dependencies
21
+
8
22
## [1.2.0] - 2026-02-21
9
23
10
24
### Fixed
@@ -90,10 +104,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
90
104
- Optional batch mode for webhook sends
91
105
92
106
#### Async Support
93
-
-`AsyncMetaAdsClient` with `curl_cffi.AsyncSession` (preferred) or `httpx.AsyncClient` (fallback)
107
+
-`AsyncMetaAdsClient` with `curl_cffi.AsyncSession`
94
108
-`AsyncMetaAdsCollector` mirroring the sync API with `async for` generators
@@ -381,14 +371,6 @@ with MetaAdsCollector() as collector:
381
371
382
372
Full async API with the same TLS fingerprint impersonation as the sync client.
383
373
384
-
```bash
385
-
# Recommended: uses curl_cffi for TLS fingerprinting (same as sync client)
386
-
pip install meta-ads-collector[stealth]
387
-
388
-
# Alternative: uses httpx (may be detected by Facebook)
389
-
pip install meta-ads-collector[async]
390
-
```
391
-
392
374
```python
393
375
import asyncio
394
376
from meta_ads_collector.async_collector import AsyncMetaAdsCollector
@@ -405,7 +387,7 @@ async def main():
405
387
asyncio.run(main())
406
388
```
407
389
408
-
The async collector mirrors the sync API: `search()`, `collect()`, `collect_to_json()`, `collect_to_csv()`, `search_pages()`, `get_stats()`. When `curl_cffi` is installed, the async client uses `curl_cffi.AsyncSession` with Chrome TLS impersonation. Otherwise it falls back to `httpx.AsyncClient`.
390
+
The async collector mirrors the sync API: `search()`, `collect()`, `collect_to_json()`, `collect_to_csv()`, `search_pages()`, `get_stats()`. The async client uses `curl_cffi.AsyncSession` with Chrome TLS impersonation.
409
391
410
392
---
411
393
@@ -718,7 +700,7 @@ All exceptions inherit from `MetaAdsError`.
718
700
## Development
719
701
720
702
```bash
721
-
# Install with dev dependencies
703
+
# Install with dev dependencies (curl_cffi is included automatically)
Copy file name to clipboardExpand all lines: docs/api-reference.md
+3-7Lines changed: 3 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -173,8 +173,6 @@ Close the collector and release resources.
173
173
174
174
**Module:**`meta_ads_collector.async_collector`
175
175
176
-
**Requires:**`pip install meta-ads-collector[stealth]` (recommended) or `pip install meta-ads-collector[async]`
177
-
178
176
### class AsyncMetaAdsCollector
179
177
180
178
Async mirror of `MetaAdsCollector`. All methods are `async def` and iterators are `async for`.
@@ -247,11 +245,9 @@ Close the session.
247
245
248
246
**Module:**`meta_ads_collector.async_client`
249
247
250
-
**Requires:**`pip install meta-ads-collector[stealth]` (recommended) or `pip install meta-ads-collector[async]`
251
-
252
248
### class AsyncMetaAdsClient
253
249
254
-
Async mirror of `MetaAdsClient` using `curl_cffi.AsyncSession` (preferred) or `httpx.AsyncClient` (fallback). Handles Facebook's 403 verification challenges automatically. All HTTP methods are async, while pure-logic methods are delegated to the sync client.
250
+
Async mirror of `MetaAdsClient` using `curl_cffi.AsyncSession`. Handles Facebook's 403 verification challenges automatically. All HTTP methods are async, while pure-logic methods are delegated to the sync client.
255
251
256
252
Same method signatures as `MetaAdsClient` with `async def`.
257
253
@@ -544,7 +540,7 @@ Download images, videos, and thumbnails from ad creatives.
|`async_client.py`| Client | Async mirror of `client.py`, delegates logic to sync client |
34
34
|`models.py`| Data |`Ad`, `AdCreative`, `PageInfo`, `PageSearchResult`, etc. |
@@ -172,9 +172,9 @@ Sessions become stale after `MAX_SESSION_AGE` (30 minutes by default). Before ea
172
172
173
173
`_refresh_session()` performs a full re-initialization:
174
174
175
-
1. Close the old session (`requests.Session` or `curl_cffi.requests.Session`)
175
+
1. Close the old session (`curl_cffi.requests.Session`)
176
176
2. Generate a new `BrowserFingerprint`
177
-
3. Create a fresh session with new headers (preferring `curl_cffi` when available)
177
+
3. Create a fresh session with new headers
178
178
4. Re-run `initialize()` to get new tokens
179
179
5. Track consecutive refresh failures to prevent infinite loops
180
180
@@ -204,7 +204,7 @@ All headers derived from the fingerprint are self-consistent -- the Chrome versi
204
204
205
205
### TLS Fingerprint Impersonation
206
206
207
-
When the optional `curl_cffi` dependency is installed (`pip install meta-ads-collector[stealth]`), the client uses `curl_cffi.requests.Session(impersonate="chrome")`instead of `requests.Session`. This provides Chrome-like TLS fingerprints (JA3/JA4) at the connection level, making requests indistinguishable from a real Chrome browser to TLS-based bot detection systems. If `curl_cffi` is not installed, the library falls back to `requests.Session` transparently.
207
+
The client uses `curl_cffi.requests.Session(impersonate="chrome")`which provides Chrome-like TLS fingerprints (JA3/JA4) at the connection level, making requests indistinguishable from a real Chrome browser to TLS-based bot detection systems.
208
208
209
209
### Request Mimicry
210
210
@@ -265,7 +265,7 @@ Seven lifecycle events:
265
265
self._logic = MetaAdsClient.__new__(MetaAdsClient) # No __init__ call
266
266
```
267
267
268
-
All pure-logic methods (token extraction, payload building, response parsing) are delegated to `_logic`. Only HTTP methods are reimplemented using `curl_cffi.AsyncSession` (preferred) or `httpx.AsyncClient` (fallback). The async client also handles Facebook's 403 verification challenges automatically, matching the sync client's behavior.
268
+
All pure-logic methods (token extraction, payload building, response parsing) are delegated to `_logic`. Only HTTP methods are reimplemented using `curl_cffi.AsyncSession`. The async client also handles Facebook's 403 verification challenges automatically, matching the sync client's behavior.
269
269
270
270
`AsyncMetaAdsCollector` mirrors `MetaAdsCollector` method-for-method, using `async def` and `async for` throughout.
Copy file name to clipboardExpand all lines: docs/async.md
+4-10Lines changed: 4 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,21 +1,15 @@
1
1
# Async Usage Guide
2
2
3
-
`meta-ads-collector` provides a full async API for use with `asyncio`. The async client uses the same TLS fingerprint impersonation as the sync client to avoid detection.
3
+
`meta-ads-collector` provides a full async API for use with `asyncio`. The async client uses `curl_cffi.AsyncSession` with Chrome TLS fingerprint impersonation, matching the sync client's behavior.
4
4
5
5
## Installation
6
6
7
-
The async client uses `curl_cffi` (recommended) for TLS fingerprint impersonation, or falls back to `httpx`:
7
+
Async support is included out of the box -- no extra install required:
8
8
9
9
```bash
10
-
# Recommended: uses curl_cffi (same TLS fingerprinting as sync client)
11
-
pip install meta-ads-collector[stealth]
12
-
13
-
# Alternative: uses httpx (may get blocked by Facebook's TLS fingerprint detection)
14
-
pip install meta-ads-collector[async]
10
+
pip install meta-ads-collector
15
11
```
16
12
17
-
If both `curl_cffi` and `httpx` are installed, `curl_cffi` is preferred automatically.
18
-
19
13
## AsyncMetaAdsCollector
20
14
21
15
The async collector mirrors the sync `MetaAdsCollector` API with `async def` methods and `async for` generators.
@@ -141,7 +135,7 @@ async with AsyncMetaAdsClient() as client:
141
135
142
136
## Notes
143
137
144
-
- The async client prefers`curl_cffi.AsyncSession`for TLS fingerprint impersonation, falling back to `httpx.AsyncClient` if curl_cffi is not installed
138
+
- The async client uses`curl_cffi.AsyncSession`with Chrome TLS fingerprint impersonation
145
139
- Facebook's 403 verification challenges are handled automatically (same as the sync client)
146
140
- Rate limiting uses `asyncio.sleep()` instead of `time.sleep()`
147
141
- Session initialization is performed asynchronously on the first request
0 commit comments