Meta Ads — Worker-Internal Reference
Worker-internal routes for Meta Ad Library data. These are not the public API routes — they are called by the API layer (apps/api) via HTTP. Clients never call these directly.
Architecture
Client -> API layer -> GET /meta/search?q=flipkart&country=IN
-> SiteRouteEngine
-> SessionPool.allocate("meta")
-> MetaAdapter.build_fetch_request()
-> Builds Meta GraphQL form body
-> Attaches MetaFingerprint cookies and headers
-> Uses confirmed persisted query doc_id
-> StatefulFetcher.fetch()
-> Redis: load pooled SessionBundle
-> HttpFetcher: TLS-impersonated request via residential proxy
-> Block detection: checkpoint, login, captcha, rate limit
-> ON SUCCESS:
-> SessionPool.release(session_id)
-> Save response cookies + extracted lsd/asbd/datr
-> ON BLOCK:
-> SessionPool.quarantine(session_id)
-> Background spawns replacement
-> MetaAdapter.transform_response()
-> Parses Meta JSON
-> Returns cleaned data by default
-> Response to clientResponse Envelope
No wrapper object. On success, the cleaned (or raw, if raw=true and the route
supports it) payload IS the response body:
{}On failure, api/responses.py::fail() returns a minimal problem object with
the HTTP status line carrying the code — there is no success/data field:
{
"type": "RATE_LIMITED",
"message": "Meta Ad Library rate limited this request",
"context": {
"upstream_status": 429,
"graphql_errors": []
}
}with HTTP status 429. By default, the success body is cleaned parsed JSON (not
an escaped string). Use raw=true where supported (see "Raw Mode" below —
/meta/search does not support it).
Confirmed Internal Operations
| Feature | GraphQL friendly name | doc_id |
|---|---|---|
| Search ads | AdLibrarySearchPaginationQuery | 24922295957467452 |
| Page ads | AdLibrarySearchPaginationQuery | 24922295957467452 |
| Ad details | AdLibraryV3AdDetailsQuery | 25068828942793558 |
| Filter options | AdLibraryFilterContextProviderQuery | 29650582277919185 |
| Search pages | useAdLibraryTypeaheadSuggestionDataSourceQuery | 9755915494515334 |
Removed non-internal convenience routes:
/meta/countries/meta/ad-analytics
Endpoints
GET /meta/search
Search ads by keyword or advertiser name.
| Param | Type | Required | Description |
|---|---|---|---|
q | string | yes | Keyword, phrase, brand, or advertiser name |
country | string | no | ISO 3166-1 alpha-2 country code, default IN |
active_status | string | no | all, active, or inactive; default all |
ad_type | string | no | ALL, POLITICAL_AND_ISSUE_ADS, HOUSING_ADS, EMPLOYMENT_ADS, CREDIT_ADS |
search_type | string | no | keyword_unordered or keyword_exact_phrase |
media_type | string | no | all, image, video, or meme |
date_min | string | no | YYYY-MM-DD; impressions/date overlap lower bound |
date_max | string | no | YYYY-MM-DD; impressions/date overlap upper bound |
page_ids | string | no | Comma-separated advertiser page IDs |
content_languages | string | no | Comma-separated language codes, for example en,hi |
publisher_platforms | string | no | Comma-separated platforms: FACEBOOK, INSTAGRAM, AUDIENCE_NETWORK, MESSENGER |
is_targeted_country | bool | no | Restrict to ads targeted at the selected country |
potential_reach_min | int | no | Minimum potential reach |
potential_reach_max | int | no | Maximum potential reach |
sort_mode | string | no | Only total_impressions is supported |
sort_direction | string | no | Only desc is supported |
cursor | string | no | Pagination cursor from pageInfo |
page_size | int | no | 1-50, default 10 |
MetaSearchRequest has no raw field — unlike every other route on this
page, /meta/search does not support raw mode. Passing ?raw=true here is
silently ignored (FastAPI drops unknown query params) and always returns
cleaned data.
curl "http://localhost:8000/meta/search?q=flipkart&country=IN&page_size=10"Date note: Meta's UI calls this "Impressions by date". date_min and date_max filter ads whose delivery/impression window overlaps the range; they are not strict ad start-date filters.
GET /meta/ad-details
Get details for a single ad archive ID. page_id is required
(MetaAdDetailsRequest.page_id: str = Field(..., min_length=1) in
schemas.py) — there is no auto-resolution from ad_archive_id alone. A
request that omits it gets a 422.
| Param | Type | Required | Description |
|---|---|---|---|
ad_archive_id | string | yes | Meta Ad Library archive ID |
page_id | string | yes | Facebook Page ID |
country | string | no | ISO country code, default IN |
raw | bool | no | Return parsed upstream GraphQL instead of cleaned data |
curl "http://localhost:8000/meta/ad-details?ad_archive_id=527778036512305&page_id=102988293558&country=IN"GET /meta/page
Browse ads for a specific Facebook Page ID.
| Param | Type | Required | Description |
|---|---|---|---|
page_id | string | yes | Facebook Page ID |
country | string | no | ISO country code, default IN |
active_status | string | no | all, active, or inactive |
media_type | string | no | all, image, video, or meme |
date_min | string | no | YYYY-MM-DD; impressions/date overlap lower bound |
date_max | string | no | YYYY-MM-DD; impressions/date overlap upper bound |
content_languages | string | no | Comma-separated language codes |
publisher_platforms | string | no | Comma-separated platform names |
sort_mode | string | no | Only total_impressions is supported |
sort_direction | string | no | Only desc is supported |
cursor | string | no | Pagination cursor |
page_size | int | no | 1-50, default 10 |
raw | bool | no | Return parsed upstream GraphQL instead of cleaned data |
curl "http://localhost:8000/meta/page?page_id=102988293558&country=IN&page_size=10"Clean response shape is the same as /meta/search.
GET /meta/filter-options
Discover dynamic filters for a query context.
| Param | Type | Required | Description |
|---|---|---|---|
query_string | string | yes | Query context, for example flipkart |
country | string | no | ISO country code, default IN |
ad_type | string | no | Meta ad category, default ALL |
search_type | string | no | keyword_unordered or keyword_exact_phrase |
raw | bool | no | Return parsed upstream GraphQL instead of cleaned data |
curl "http://localhost:8000/meta/filter-options?query_string=flipkart&country=IN"Clean response shape:
{
"languages": [],
"pages": [],
"disclaimers": [],
"regions": [],
"countries": [],
"cities": [],
"targetedRegions": []
}Each item in filter arrays: {"count": number, "key": string, "display_name": string}.
GET /meta/search-pages
Search advertiser/page suggestions by brand or company name.
| Param | Type | Required | Description |
|---|---|---|---|
q | string | yes | Brand, company, or advertiser name |
country | string | no | ISO country code, default IN |
ad_type | string | no | Meta ad category, default ALL |
raw | bool | no | Return parsed upstream GraphQL instead of cleaned data |
curl "http://localhost:8000/meta/search-pages?q=nike&country=IN"Clean response item shape:
{
"pageId": "15087023444",
"name": "Nike",
"alias": "nike",
"category": "Sportswear shop",
"imageUrl": "https://...",
"likes": 39606218,
"verification": "BLUE_VERIFIED",
"instagramUsername": "nike",
"instagramFollowers": 291914384,
"instagramVerified": true,
"deleted": false
}Raw Mode
Every Meta route accepts raw=true except /meta/search (see above).
Returns the parsed upstream GraphQL object (not an escaped JSON string):
{
"raw": {
"data": {
"ad_library_main": {}
}
},
"source": {
"operation": "AdLibrarySearchPaginationQuery",
"docId": "24922295957467452"
}
}Use raw mode for debugging or when adding new clean mappers. Client integrations should use the cleaned default response.
Rate Limits and Blocks
Meta can return GraphQL-level errors with HTTP 200. The adapter parses these and maps rate-limit code 1675004 to a 429 RATE_LIMITED response. Other blocked responses (status 401, 403, 429) are mapped to UPSTREAM_BLOCKED.
Session Notes
- Sessions are managed by
SessionPool— clients never provide session IDs. - Search/page date filters use ISO dates and Meta's delivery-window semantics.
sort_mode=total_impressions&sort_direction=descis the only confirmed stable sort.
Configuration
| Variable | Default | Description |
|---|---|---|
META_BASE_URL | https://www.facebook.com/ads/library/ | Meta Ads Library base URL |
META_GRAPHQL_URL | https://www.facebook.com/api/graphql/ | GraphQL endpoint |
META_ASBD_ID | 359341 | Fallback ASBD ID |
META_SEARCH_DOC_ID | 24922295957467452 | Search/page ads doc ID |
META_AD_DETAILS_DOC_ID | 25068828942793558 | Ad details doc ID |
META_FILTER_OPTIONS_DOC_ID | 29650582277919185 | Filter options doc ID |
META_SEARCH_PAGES_DOC_ID | 9755915494515334 | Page typeahead doc ID |
Pool sizing is configured in sites.yaml:
sites:
meta:
session_ttl: 1800
pool_min_idle: 6
pool_max_idle: 35
pool_max_total: 110
max_retries: 2
max_concurrency: 70Production Notes
- Default responses are cleaned JSON and safe for API consumers.
raw=trueis intentionally opt-in (where supported) because Meta payloads are large.- Search/page date filters use ISO dates and Meta's delivery-window semantics.
sort_mode=total_impressions&sort_direction=descis the only confirmed stable sort./meta/countriesand/meta/ad-analyticsare intentionally not exposed because they do not map to separate confirmed Meta internal APIs.