toolzer Internal Docs
WorkerSites

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 client

Response 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

FeatureGraphQL friendly namedoc_id
Search adsAdLibrarySearchPaginationQuery24922295957467452
Page adsAdLibrarySearchPaginationQuery24922295957467452
Ad detailsAdLibraryV3AdDetailsQuery25068828942793558
Filter optionsAdLibraryFilterContextProviderQuery29650582277919185
Search pagesuseAdLibraryTypeaheadSuggestionDataSourceQuery9755915494515334

Removed non-internal convenience routes:

  • /meta/countries
  • /meta/ad-analytics

Endpoints

GET /meta/search

Search ads by keyword or advertiser name.

ParamTypeRequiredDescription
qstringyesKeyword, phrase, brand, or advertiser name
countrystringnoISO 3166-1 alpha-2 country code, default IN
active_statusstringnoall, active, or inactive; default all
ad_typestringnoALL, POLITICAL_AND_ISSUE_ADS, HOUSING_ADS, EMPLOYMENT_ADS, CREDIT_ADS
search_typestringnokeyword_unordered or keyword_exact_phrase
media_typestringnoall, image, video, or meme
date_minstringnoYYYY-MM-DD; impressions/date overlap lower bound
date_maxstringnoYYYY-MM-DD; impressions/date overlap upper bound
page_idsstringnoComma-separated advertiser page IDs
content_languagesstringnoComma-separated language codes, for example en,hi
publisher_platformsstringnoComma-separated platforms: FACEBOOK, INSTAGRAM, AUDIENCE_NETWORK, MESSENGER
is_targeted_countryboolnoRestrict to ads targeted at the selected country
potential_reach_minintnoMinimum potential reach
potential_reach_maxintnoMaximum potential reach
sort_modestringnoOnly total_impressions is supported
sort_directionstringnoOnly desc is supported
cursorstringnoPagination cursor from pageInfo
page_sizeintno1-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.

ParamTypeRequiredDescription
ad_archive_idstringyesMeta Ad Library archive ID
page_idstringyesFacebook Page ID
countrystringnoISO country code, default IN
rawboolnoReturn 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.

ParamTypeRequiredDescription
page_idstringyesFacebook Page ID
countrystringnoISO country code, default IN
active_statusstringnoall, active, or inactive
media_typestringnoall, image, video, or meme
date_minstringnoYYYY-MM-DD; impressions/date overlap lower bound
date_maxstringnoYYYY-MM-DD; impressions/date overlap upper bound
content_languagesstringnoComma-separated language codes
publisher_platformsstringnoComma-separated platform names
sort_modestringnoOnly total_impressions is supported
sort_directionstringnoOnly desc is supported
cursorstringnoPagination cursor
page_sizeintno1-50, default 10
rawboolnoReturn 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.

ParamTypeRequiredDescription
query_stringstringyesQuery context, for example flipkart
countrystringnoISO country code, default IN
ad_typestringnoMeta ad category, default ALL
search_typestringnokeyword_unordered or keyword_exact_phrase
rawboolnoReturn 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.

ParamTypeRequiredDescription
qstringyesBrand, company, or advertiser name
countrystringnoISO country code, default IN
ad_typestringnoMeta ad category, default ALL
rawboolnoReturn 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=desc is the only confirmed stable sort.

Configuration

VariableDefaultDescription
META_BASE_URLhttps://www.facebook.com/ads/library/Meta Ads Library base URL
META_GRAPHQL_URLhttps://www.facebook.com/api/graphql/GraphQL endpoint
META_ASBD_ID359341Fallback ASBD ID
META_SEARCH_DOC_ID24922295957467452Search/page ads doc ID
META_AD_DETAILS_DOC_ID25068828942793558Ad details doc ID
META_FILTER_OPTIONS_DOC_ID29650582277919185Filter options doc ID
META_SEARCH_PAGES_DOC_ID9755915494515334Page 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: 70

Production Notes

  • Default responses are cleaned JSON and safe for API consumers.
  • raw=true is 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=desc is the only confirmed stable sort.
  • /meta/countries and /meta/ad-analytics are intentionally not exposed because they do not map to separate confirmed Meta internal APIs.

On this page