{
  "data": {
    "id": "ztQb0gIwbdWyF5gK7",
    "actId": "ZYe4UyoXnbwoB7Osj",
    "userId": "IYgBDiXtHOijAaUel",
    "startedAt": "2026-11-06T18:18:50.799Z",
    "finishedAt": "2026-11-06T18:18:59.777Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 8856,
      "runTimeSecs": 8.856,
      "computeUnits": 0.00984,
      "imageSizeBytes": 319046144
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "QYo53EZkJk0prePWY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"Snapchat Ads Gallery Scraper\",\n  \"description\": \"Scrape the public Snapchat Ads Library (Ads Gallery) for advertiser ads, sponsored content, and creator-sponsored posts across the EU and Turkey.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"mode\": {\n      \"type\": \"string\",\n      \"title\": \"Scraping Mode\",\n      \"description\": \"adSearch searches ads by paying advertiser, sponsoredContent browses all live sponsored content, and creatorSearch searches sponsored content by creator.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"adSearch\",\n        \"sponsoredContent\",\n        \"creatorSearch\"\n      ],\n      \"enumTitles\": [\n        \"Search Ads by Advertiser\",\n        \"Browse All Sponsored Content\",\n        \"Search Sponsored Content by Creator\"\n      ],\n      \"default\": \"adSearch\",\n      \"prefill\": \"adSearch\"\n    },\n    \"payingAdvertiserNames\": {\n      \"type\": \"array\",\n      \"title\": \"Advertiser Names\",\n      \"description\": \"For adSearch mode: one or more paying-advertiser names, e.g. Nike, Amazon, Zalando. The API matches partial names case-insensitively; set Advertiser Match to exact for case-insensitive exact payer matching.\",\n      \"editor\": \"stringList\",\n      \"prefill\": [\n        \"nike\"\n      ]\n    },\n    \"payingAdvertiserName\": {\n      \"type\": \"string\",\n      \"title\": \"Advertiser Name (single, legacy)\",\n      \"description\": \"Single-advertiser legacy input, still supported. Prefer Advertiser Names. If both are set, the names are merged and deduplicated.\",\n      \"editor\": \"textfield\"\n    },\n    \"advertiserMatch\": {\n      \"type\": \"string\",\n      \"title\": \"Advertiser Match\",\n      \"description\": \"contains (default) uses Snap's partial payer-name search. exact keeps only ads whose paying advertiser exactly equals one of your names, ignoring case and extra whitespace.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"contains\",\n        \"exact\"\n      ],\n      \"enumTitles\": [\n        \"Contains (partial match)\",\n        \"Exact payer name\"\n      ],\n      \"default\": \"contains\",\n      \"prefill\": \"contains\"\n    },\n    \"countries\": {\n      \"type\": \"array\",\n      \"title\": \"Countries\",\n      \"editor\": \"stringList\",\n      \"description\": \"2-letter country codes to filter ads by. Leave empty for all. Supported: the 27 EU codes at, be, bg, cy, cz, de, dk, ee, el (Greece), es, fi, fr, hr, hu, ie, it, lt, lu, lv, mt, nl, pl, pt, ro, se, si, sk, tr (Turkey). gr is accepted as an alias for el. UK (gb/uk) and US are not in the library.\",\n      \"prefill\": []\n    },\n    \"startDate\": {\n      \"type\": \"string\",\n      \"title\": \"Start Date\",\n      \"description\": \"Filter ads that ran on or after this date (ISO 8601 or YYYY-MM-DD). The library only covers the last 12 months; older dates may return nothing.\",\n      \"editor\": \"textfield\"\n    },\n    \"endDate\": {\n      \"type\": \"string\",\n      \"title\": \"End Date\",\n      \"description\": \"Filter ads that ran on or before this date (ISO 8601 or YYYY-MM-DD). The API does not publish an ad end date in records.\",\n      \"editor\": \"textfield\"\n    },\n    \"status\": {\n      \"type\": \"string\",\n      \"title\": \"Ad Status\",\n      \"description\": \"Filter ads by current status: ACTIVE, PAUSED, or ALL.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"ACTIVE\",\n        \"PAUSED\",\n        \"ALL\"\n      ],\n      \"enumTitles\": [\n        \"Active Only\",\n        \"Paused Only\",\n        \"All Statuses\"\n      ],\n      \"default\": \"ALL\",\n      \"prefill\": \"ALL\"\n    },\n    \"creatorName\": {\n      \"type\": \"string\",\n      \"title\": \"Creator Name\",\n      \"description\": \"For creatorSearch mode: creator username or display name used to search sponsored content.\",\n      \"editor\": \"textfield\",\n      \"prefill\": \"beauty\"\n    },\n    \"maxResults\": {\n      \"type\": \"integer\",\n      \"title\": \"Max Results per Advertiser\",\n      \"description\": \"Maximum records to save per advertiser in adSearch, or total records in sponsoredContent/creatorSearch. The actor paginates the public API automatically (10 ads per request for adSearch, up to 200 items per page for sponsored content).\",\n      \"default\": 200,\n      \"minimum\": 1,\n      \"maximum\": 10000\n    },\n    \"includeCoverage\": {\n      \"type\": \"boolean\",\n      \"title\": \"Include Coverage Rows\",\n      \"description\": \"Add one coverage row per advertiser/creator listing matched payer names, status, pages fetched, duplicates removed, countries, and impression coverage.\",\n      \"default\": true,\n      \"prefill\": true\n    },\n    \"proxyConfiguration\": {\n      \"title\": \"Proxy Configuration\",\n      \"description\": \"Optional proxy. The Ads Library API is public and normally works without a proxy; enable one only if your runs keep hitting rate limits.\",\n      \"type\": \"object\",\n      \"editor\": \"proxy\",\n      \"nullable\": true\n    }\n  }\n}",
    "readme": "# Snapchat EU + Turkey Ads Library Impressions & Targeting Extractor\r\n\r\nUnder EU and Turkish digital advertising transparency rules, Snapchat publishes ads delivered in those markets through the public Ads Gallery API. This actor reads that library directly — search by one or more advertisers, browse all publicly disclosed sponsored content, or search by creator — and returns structured records with normalized creative, landing page, impression, targeting, catalog, story, collection and lens data. No login, cookie or OAuth token is required.\r\n\r\n## What this actor does\r\n\r\n- Searches ads by one or more paying-advertiser names, with country, date-range and status filters\r\n- Paginates advertiser search automatically (Snap serves 10 ads per request; the actor follows `paging.next_link` until the per-advertiser limit or the end)\r\n- Browses the full live sponsored-content library with automatic GET pagination (up to 200 items per page)\r\n- Searches sponsored content by creator with POST cursor pagination and deduplication by `contentUrl`\r\n- Supports partial (`contains`) and case-insensitive `exact` payer matching\r\n- Returns normalized lifetime impressions, flat targeting, landing page/domain, media, DPA products, story snaps, collection and lens data\r\n- Emits coverage rows with the payer names actually seen, plus a `RUN_SUMMARY` key-value record\r\n- Distinguishes `no_ads` from `rationed`, `blocked`, `partial`, `invalid` and `error` instead of writing placeholder error rows\r\n- Throttles requests and retries 429/5xx responses with exponential backoff and `Retry-After` support\r\n\r\n## Data scope and freshness\r\n\r\n- **Markets:** 27 EU member states plus **Turkey (`tr`)**. `gr` is accepted as an alias for `el` (Greece). The UK (`gb`/`uk`) and US are not in this library.\r\n- **Window:** Snap only publishes ads delivered in the EU and Turkey during the **last 12 months**. Older `startDate` values may return no ads.\r\n- **Freshness:** Snap refreshes Ads Gallery impressions **at most every 24 hours**. Counts are calculated on GMT.\r\n- **Impressions:** `impressionsTotal` and `impressionsByCountry` are **lifetime** counts for the ad, not 24-hour or daily counts.\r\n- **Not published:** spend, budget, reach, frequency, CTR, conversions, exact end date, and UK/US ads. Sponsored creator content is a secondary surface with fewer fields than ad records.\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `mode` | string | `adSearch` | `adSearch`, `sponsoredContent`, or `creatorSearch` |\r\n| `payingAdvertiserNames` | array | - | One or more paying-advertiser names for `adSearch` |\r\n| `payingAdvertiserName` | string | – | Legacy single-advertiser input; merged with the array |\r\n| `advertiserMatch` | string | `contains` | `contains` uses Snap's partial payer search; `exact` keeps only case-insensitive exact payer matches |\r\n| `countries` | array | `[]` | EU + Turkey codes: `at`, `be`, `bg`, `cy`, `cz`, `de`, `dk`, `ee`, `el`, `es`, `fi`, `fr`, `hr`, `hu`, `ie`, `it`, `lt`, `lu`, `lv`, `mt`, `nl`, `pl`, `pt`, `ro`, `se`, `si`, `sk`, `tr`; `gr` maps to `el` |\r\n| `startDate` | string | – | Ads that ran on or after this date (ISO 8601 or `YYYY-MM-DD`) |\r\n| `endDate` | string | – | Ads that ran on or before this date (ISO 8601 or `YYYY-MM-DD`) |\r\n| `status` | string | `ALL` | `ACTIVE`, `PAUSED`, or `ALL` |\r\n| `creatorName` | string | – | Creator username or name for `creatorSearch` |\r\n| `maxResults` | integer | `200` | Maximum records **per advertiser** in `adSearch`, or total records for the other modes (1–10,000) |\r\n| `includeCoverage` | boolean | `true` | Add one coverage row per advertiser/creator |\r\n| `proxyConfiguration` | object | – | Optional; the public API normally works without a proxy |\r\n\r\n### Example: multiple active advertisers in France, Germany and Turkey\r\n\r\n```json\r\n{\r\n  \"mode\": \"adSearch\",\r\n  \"payingAdvertiserNames\": [\"nike\", \"adidas\"],\r\n  \"advertiserMatch\": \"contains\",\r\n  \"countries\": [\"fr\", \"de\", \"tr\"],\r\n  \"status\": \"ACTIVE\",\r\n  \"maxResults\": 200\r\n}\r\n```\r\n\r\n### Example: exact payer match\r\n\r\n```json\r\n{\r\n  \"mode\": \"adSearch\",\r\n  \"payingAdvertiserNames\": [\"Nike, Inc.\"],\r\n  \"advertiserMatch\": \"exact\",\r\n  \"countries\": [\"fr\"]\r\n}\r\n```\r\n\r\n### Example: browse all sponsored content\r\n\r\n```json\r\n{\r\n  \"mode\": \"sponsoredContent\",\r\n  \"maxResults\": 500\r\n}\r\n```\r\n\r\n### Example: sponsored content by a creator\r\n\r\n```json\r\n{\r\n  \"mode\": \"creatorSearch\",\r\n  \"creatorName\": \"beauty\",\r\n  \"maxResults\": 100\r\n}\r\n```\r\n\r\n## Output per ad (`recordType = \"ad\"`)\r\n\r\n### Identity, advertiser and delivery\r\n\r\n- `adId`, `adName`, `adAccountName` — ad identifier, internal ad name and ad-account name\r\n- `payingAdvertiserName` — paying entity as disclosed by Snap (whitespace-normalized)\r\n- `brandName`, `profileName`, `profileLogoUrl` — brand (`brand_name` or profile fallback) and Snap public profile\r\n- `status`, `reviewStatus`, `rejectionReasons`, `startDate`, `endDate` (when published)\r\n- `daysActive` — days from `startDate` to `endDate` or now\r\n- `languages`\r\n- `searchAdvertiser`, `matchMode` — which input name/match mode produced the record\r\n- `matchedAdvertisers` — added only when the same ad matched more than one input advertiser\r\n\r\n### URLs and media\r\n\r\n- `adUrl` — public Ads Gallery detail page (`https://adsgallery.snap.com/?adId=...`), verified to open the ad\r\n- `adDetailApiUrl` — public API detail endpoint (`/v1/ads_library/ads/{adId}`)\r\n- `landingUrl` — web-view, deep-link or story-snap destination\r\n- `domain` — hostname of the HTTP(S) landing URL\r\n- `mediaUrls`, `mediaType` — all top-level and story-snap creative media URLs and their type\r\n- `topSnapMediaDownloadLink`, `mediaDownloadUrl`, `topSnapMediaType`, `topSnapCropPosition`\r\n- `webViewProperties`, `deepLinkProperties`, `compositePreview`, `dpaPreview`, `collectionPreview`, `lensPreview`, `stickers` — raw API objects, retained for completeness\r\n\r\n### Impressions\r\n\r\n- `impressionsTotal` — lifetime impressions from Snap (falls back to the per-country sum if Snap omits the total)\r\n- `impressionsByCountry` — only countries with a **nonzero** impression count\r\n- `countries` — those countries, largest first\r\n- `topCountry`, `topCountryImpressions`\r\n\r\n### Targeting\r\n\r\n- `targeting` — flat normalized targeting: `minAge`, `maxAge`, `ageRange`, `genders`, `languages`, `devices`, `regulatedContent`\r\n- `targetingV2` — raw `targeting_v2` object\r\n\r\n### Catalog, story, collection and lens\r\n\r\n- `products`, `productCount`, `dpaTemplate` — dynamic product-ad items with flattened image URLs\r\n- `story` — composite/story ads: `titleHeadline`, `shouldLoop`, `previewCreativeRenderType`, `snapCount`, and per-snap `snaps` (type, headline, CTA, media, landing URL)\r\n- `collection` — collection ads: `itemCount`, `items` (including app-install properties when present), `landingUrl`\r\n- `appInstall` — app-install properties when Snap publishes them\r\n- `lens` — lens preview (`iconUrl`)\r\n- `recordType` — always `ad`\r\n- `scrapedAt` — ISO-8601 UTC scrape timestamp\r\n\r\n## Output per sponsored content item (`recordType = \"sponsoredContent\"`)\r\n\r\n- `contentType`, `contentUrl`, `thumbnailUrl`\r\n- `creatorName`, `creatorUrl`\r\n- `sponsorName`, `sponsorUrl`, `brandName`\r\n- `recordType`, `scrapedAt`\r\n\r\n## Coverage rows and run summary\r\n\r\nWith `includeCoverage` enabled (default), the dataset also contains one row per advertiser/creator:\r\n\r\n- `recordType = \"coverage\"`, `mode`, `target`\r\n- `status` — `ok`, `no_ads`, `partial`, `rationed`, `blocked`, `invalid`, or `error`\r\n- `recordCount`, `rawRecordCount`, `duplicatesRemoved`, `pagesFetched`\r\n- `payerNames` — every payer name actually seen for that search, including non-matching names in `exact` mode\r\n- `countries`, `topCountry`, `impressionsTotal`\r\n- `recordsWithImpressions`, `recordsWithLandingUrl`, `recordsWithMedia`\r\n- `error`, `notes`, `requestIds`\r\n- Sponsored-content coverage also includes `creatorNames`, `sponsorNames`, `contentTypes`\r\n\r\nThe key-value store record `RUN_SUMMARY` contains the overall run status, counts by status, errors, notes, duration, input echo, source, scope and freshness.\r\n\r\n## No-results semantics\r\n\r\nEmpty results never produce a placeholder `{mode, error}` row. If Snap returns no matching ads, the run finishes with `status = \"no_ads\"` and writes no ad rows (coverage rows still show the search). If Snap rate-limits, blocks, rejects or partially fails a request, the summary reports `rationed`, `blocked`, `invalid`, `partial` or `error`, and any records already collected are kept.\r\n\r\n## Pagination and limits\r\n\r\n- **Advertiser search:** Snap serves **10 ads per request**. The actor POSTs the returned `paging.next_link` with the same JSON body; pagination is real and advances page by page.\r\n- **Creator search:** Snap serves up to 200 items per page. The actor POSTs `paging.next_link` with the same body. Pages can overlap; records are deduplicated by `contentUrl`.\r\n- **Sponsored content browse:** GET with `limit=200`, following GET `paging.next_link`.\r\n- **Rate limits:** Snap applies server-side limits (HTTP 429 and occasional 500/E4001 BigQuery rate-limit errors). The actor throttles requests and retries with exponential backoff plus `Retry-After`.\r\n- **Ad detail:** `GET /v1/ads_library/ads/{ad_id}` returns a complete `ad_preview`, verified live.\r\n- **Hard limits:** 12-month window, 24-hour impression refresh, no spend/reach, exact end dates are usually unpublished, no UK/US, and creator content has fewer fields.\r\n\r\n## Use cases\r\n\r\n- **Competitive ad monitoring** — track competitor creatives, CTAs, landing pages and per-country lifetime impressions\r\n- **Regulatory/transparency research** — study disclosed EU/Turkey ad targeting and impressions\r\n- **Creator partnership discovery** — find brands sponsoring a creator's content\r\n- **Creative benchmarking** — compare formats, CTAs and catalog/story/collection usage\r\n- **Impressions analysis** — use `impressionsByCountry`, `topCountry` and coverage rows\r\n\r\n## FAQ\r\n\r\n**Is this official Snapchat data?** Yes. It reads Snapchat's public Ads Gallery API, which Snap publishes under transparency rules; no private pages or user data are accessed.\r\n\r\n**Why does advertiser search return 10 ads at a time?** Ten is Snap's page size, not a total cap. This actor follows `paging.next_link` until `maxResults` per advertiser or the end of the result set.\r\n\r\n**Which countries are supported?** The 27 EU member states and Turkey. `gr` is mapped to `el`; unsupported codes are dropped with a warning instead of filtering out all results.\r\n\r\n**How current are impressions?** Snap updates the gallery at most every 24 hours, and the counts are lifetime impressions for each ad.\r\n\r\n**Can I download creatives?** Yes — `mediaUrls` and `topSnapMediaDownloadLink` are direct Snap CDN links. CDN URLs can expire, so download soon after scraping.\r\n\r\n**What is the difference between `sponsoredContent` and `creatorSearch`?** `sponsoredContent` pages through the whole live sponsored-content library. `creatorSearch` narrows it to one creator's name. Both return the same record shape.\r\n\r\n**Is this affiliated with Snapchat?** No. This is an independent third-party actor reading Snap's publicly mandated Ads Gallery API.\r\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "snapchat-eu-ads-library-impressions-and-targeting",
      "title": "Snapchat EU + Turkey Ads Library Impressions & Targeting",
      "description": "Search Snapchat's public EU + Turkey ad transparency library by one or more advertisers or a creator, or browse all sponsored content, returning normalized creative, landing page, lifetime impressions, targeting, catalog, story and collection data.",
      "version": "1.0",
      "meta": {
        "templateId": "python-start"
      },
      "input": {
        "title": "Snapchat Ads Gallery Scraper",
        "description": "Scrape the public Snapchat Ads Library (Ads Gallery) for advertiser ads, sponsored content, and creator-sponsored posts across the EU and Turkey.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "mode": {
            "type": "string",
            "title": "Scraping Mode",
            "description": "adSearch searches ads by paying advertiser, sponsoredContent browses all live sponsored content, and creatorSearch searches sponsored content by creator.",
            "editor": "select",
            "enum": [
              "adSearch",
              "sponsoredContent",
              "creatorSearch"
            ],
            "enumTitles": [
              "Search Ads by Advertiser",
              "Browse All Sponsored Content",
              "Search Sponsored Content by Creator"
            ],
            "default": "adSearch",
            "prefill": "adSearch"
          },
          "payingAdvertiserNames": {
            "type": "array",
            "title": "Advertiser Names",
            "description": "For adSearch mode: one or more paying-advertiser names, e.g. Nike, Amazon, Zalando. The API matches partial names case-insensitively; set Advertiser Match to exact for case-insensitive exact payer matching.",
            "editor": "stringList",
            "prefill": [
              "nike"
            ]
          },
          "payingAdvertiserName": {
            "type": "string",
            "title": "Advertiser Name (single, legacy)",
            "description": "Single-advertiser legacy input, still supported. Prefer Advertiser Names. If both are set, the names are merged and deduplicated.",
            "editor": "textfield"
          },
          "advertiserMatch": {
            "type": "string",
            "title": "Advertiser Match",
            "description": "contains (default) uses Snap's partial payer-name search. exact keeps only ads whose paying advertiser exactly equals one of your names, ignoring case and extra whitespace.",
            "editor": "select",
            "enum": [
              "contains",
              "exact"
            ],
            "enumTitles": [
              "Contains (partial match)",
              "Exact payer name"
            ],
            "default": "contains",
            "prefill": "contains"
          },
          "countries": {
            "type": "array",
            "title": "Countries",
            "editor": "stringList",
            "description": "2-letter country codes to filter ads by. Leave empty for all. Supported: the 27 EU codes at, be, bg, cy, cz, de, dk, ee, el (Greece), es, fi, fr, hr, hu, ie, it, lt, lu, lv, mt, nl, pl, pt, ro, se, si, sk, tr (Turkey). gr is accepted as an alias for el. UK (gb/uk) and US are not in the library.",
            "prefill": []
          },
          "startDate": {
            "type": "string",
            "title": "Start Date",
            "description": "Filter ads that ran on or after this date (ISO 8601 or YYYY-MM-DD). The library only covers the last 12 months; older dates may return nothing.",
            "editor": "textfield"
          },
          "endDate": {
            "type": "string",
            "title": "End Date",
            "description": "Filter ads that ran on or before this date (ISO 8601 or YYYY-MM-DD). The API does not publish an ad end date in records.",
            "editor": "textfield"
          },
          "status": {
            "type": "string",
            "title": "Ad Status",
            "description": "Filter ads by current status: ACTIVE, PAUSED, or ALL.",
            "editor": "select",
            "enum": [
              "ACTIVE",
              "PAUSED",
              "ALL"
            ],
            "enumTitles": [
              "Active Only",
              "Paused Only",
              "All Statuses"
            ],
            "default": "ALL",
            "prefill": "ALL"
          },
          "creatorName": {
            "type": "string",
            "title": "Creator Name",
            "description": "For creatorSearch mode: creator username or display name used to search sponsored content.",
            "editor": "textfield",
            "prefill": "beauty"
          },
          "maxResults": {
            "type": "integer",
            "title": "Max Results per Advertiser",
            "description": "Maximum records to save per advertiser in adSearch, or total records in sponsoredContent/creatorSearch. The actor paginates the public API automatically (10 ads per request for adSearch, up to 200 items per page for sponsored content).",
            "default": 200,
            "minimum": 1,
            "maximum": 10000
          },
          "includeCoverage": {
            "type": "boolean",
            "title": "Include Coverage Rows",
            "description": "Add one coverage row per advertiser/creator listing matched payer names, status, pages fetched, duplicates removed, countries, and impression coverage.",
            "default": true,
            "prefill": true
          },
          "proxyConfiguration": {
            "title": "Proxy Configuration",
            "description": "Optional proxy. The Ads Library API is public and normally works without a proxy; enable one only if your runs keep hitting rate limits.",
            "type": "object",
            "editor": "proxy",
            "nullable": true
          }
        }
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "Snapchat EU + Turkey Ads Library Output",
        "description": "Snapchat ad and sponsored-content records plus coverage rows, with normalized impressions, targeting, landing page, media, catalog, story, collection and lens fields.",
        "properties": {
          "records": {
            "type": "string",
            "title": "Ads, sponsored content, and coverage rows",
            "description": "Default dataset. Ad rows use recordType=ad, sponsored content uses recordType=sponsoredContent, and one coverage row per advertiser/creator uses recordType=coverage.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          },
          "runSummary": {
            "type": "string",
            "title": "Run summary",
            "description": "Key-value store record with overall status (ok, no_ads, partial, rationed, blocked, invalid, error), result counts, request IDs, notes and errors.",
            "template": "{{links.apiDefaultKeyValueStoreUrl}}/records/RUN_SUMMARY"
          }
        }
      },
      "dockerfile": "./Dockerfile",
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "fields": {
            "adId": {
              "type": "string",
              "description": "Unique ad ID (UUID)"
            },
            "adName": {
              "type": "string",
              "description": "Internal ad name"
            },
            "adAccountName": {
              "type": "string",
              "description": "Ad account name"
            },
            "payingAdvertiserName": {
              "type": "string",
              "description": "Paying advertiser name"
            },
            "profileName": {
              "type": "string",
              "description": "Snapchat profile/brand name"
            },
            "profileLogoUrl": {
              "type": "string",
              "description": "Profile logo CDN URL"
            },
            "headline": {
              "type": "string",
              "description": "Ad headline text"
            },
            "adType": {
              "type": "string",
              "description": "Ad type (e.g. REMOTE_WEBPAGE, SNAP_AD)"
            },
            "adRenderType": {
              "type": "string",
              "description": "Ad render type (e.g. DYNAMIC, STATIC)"
            },
            "creativeType": {
              "type": "string",
              "description": "Creative type (e.g. WEB_VIEW, VIDEO)"
            },
            "callToAction": {
              "type": "string",
              "description": "Call to action text (e.g. SHOP NOW)"
            },
            "topSnapMediaType": {
              "type": "string",
              "description": "Top snap media type"
            },
            "topSnapCropPosition": {
              "type": "string",
              "description": "Top snap crop position (e.g. MIDDLE)"
            },
            "mediaDownloadUrl": {
              "type": "string",
              "description": "Top snap media download URL"
            },
            "webViewProperties": {
              "type": "object",
              "description": "Web view URL and related properties"
            },
            "compositePreview": {
              "type": "object",
              "description": "Composite ad preview with multiple snaps"
            },
            "dpaPreview": {
              "type": "object",
              "description": "Dynamic product ad preview with image items"
            },
            "stickers": {
              "type": "array",
              "description": "Stickers attached to the ad"
            },
            "languages": {
              "type": "array",
              "description": "Target languages for this ad"
            },
            "startDate": {
              "type": "string",
              "description": "Ad start date (ISO 8601)"
            },
            "status": {
              "type": "string",
              "description": "Ad status: ACTIVE or PAUSED"
            },
            "reviewStatus": {
              "type": "string",
              "description": "Ad review status"
            },
            "rejectionReasons": {
              "type": "array",
              "description": "Rejection reasons if ad was rejected"
            },
            "impressionsTotal": {
              "type": "integer",
              "description": "Total impressions across all countries"
            },
            "impressionsByCountry": {
              "type": "object",
              "description": "Nonzero impressions broken down by country code"
            },
            "targetingV2": {
              "type": "object",
              "description": "Targeting configuration (demographics, devices, regulated content flag)"
            },
            "contentType": {
              "type": "string",
              "description": "Sponsored content type (e.g. SPOTLIGHT)"
            },
            "contentUrl": {
              "type": "string",
              "description": "Sponsored content URL"
            },
            "thumbnailUrl": {
              "type": "string",
              "description": "Sponsored content thumbnail URL"
            },
            "creatorName": {
              "type": "string",
              "description": "Creator name (sponsored content)"
            },
            "creatorUrl": {
              "type": "string",
              "description": "Creator profile URL (sponsored content)"
            },
            "sponsorName": {
              "type": "string",
              "description": "Sponsor/brand name (sponsored content)"
            },
            "sponsorUrl": {
              "type": "string",
              "description": "Sponsor profile URL (sponsored content)"
            },
            "recordType": {
              "type": "string",
              "description": "Record type: ad, sponsoredContent, creatorContent, coverage, or runSummary"
            },
            "scrapedAt": {
              "type": "string",
              "description": "ISO 8601 UTC timestamp when record was scraped"
            }
          }
        }
      },
      "readme": "# Snapchat EU + Turkey Ads Library Impressions & Targeting Extractor\r\n\r\nUnder EU and Turkish digital advertising transparency rules, Snapchat publishes ads delivered in those markets through the public Ads Gallery API. This actor reads that library directly — search by one or more advertisers, browse all publicly disclosed sponsored content, or search by creator — and returns structured records with normalized creative, landing page, impression, targeting, catalog, story, collection and lens data. No login, cookie or OAuth token is required.\r\n\r\n## What this actor does\r\n\r\n- Searches ads by one or more paying-advertiser names, with country, date-range and status filters\r\n- Paginates advertiser search automatically (Snap serves 10 ads per request; the actor follows `paging.next_link` until the per-advertiser limit or the end)\r\n- Browses the full live sponsored-content library with automatic GET pagination (up to 200 items per page)\r\n- Searches sponsored content by creator with POST cursor pagination and deduplication by `contentUrl`\r\n- Supports partial (`contains`) and case-insensitive `exact` payer matching\r\n- Returns normalized lifetime impressions, flat targeting, landing page/domain, media, DPA products, story snaps, collection and lens data\r\n- Emits coverage rows with the payer names actually seen, plus a `RUN_SUMMARY` key-value record\r\n- Distinguishes `no_ads` from `rationed`, `blocked`, `partial`, `invalid` and `error` instead of writing placeholder error rows\r\n- Throttles requests and retries 429/5xx responses with exponential backoff and `Retry-After` support\r\n\r\n## Data scope and freshness\r\n\r\n- **Markets:** 27 EU member states plus **Turkey (`tr`)**. `gr` is accepted as an alias for `el` (Greece). The UK (`gb`/`uk`) and US are not in this library.\r\n- **Window:** Snap only publishes ads delivered in the EU and Turkey during the **last 12 months**. Older `startDate` values may return no ads.\r\n- **Freshness:** Snap refreshes Ads Gallery impressions **at most every 24 hours**. Counts are calculated on GMT.\r\n- **Impressions:** `impressionsTotal` and `impressionsByCountry` are **lifetime** counts for the ad, not 24-hour or daily counts.\r\n- **Not published:** spend, budget, reach, frequency, CTR, conversions, exact end date, and UK/US ads. Sponsored creator content is a secondary surface with fewer fields than ad records.\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `mode` | string | `adSearch` | `adSearch`, `sponsoredContent`, or `creatorSearch` |\r\n| `payingAdvertiserNames` | array | - | One or more paying-advertiser names for `adSearch` |\r\n| `payingAdvertiserName` | string | – | Legacy single-advertiser input; merged with the array |\r\n| `advertiserMatch` | string | `contains` | `contains` uses Snap's partial payer search; `exact` keeps only case-insensitive exact payer matches |\r\n| `countries` | array | `[]` | EU + Turkey codes: `at`, `be`, `bg`, `cy`, `cz`, `de`, `dk`, `ee`, `el`, `es`, `fi`, `fr`, `hr`, `hu`, `ie`, `it`, `lt`, `lu`, `lv`, `mt`, `nl`, `pl`, `pt`, `ro`, `se`, `si`, `sk`, `tr`; `gr` maps to `el` |\r\n| `startDate` | string | – | Ads that ran on or after this date (ISO 8601 or `YYYY-MM-DD`) |\r\n| `endDate` | string | – | Ads that ran on or before this date (ISO 8601 or `YYYY-MM-DD`) |\r\n| `status` | string | `ALL` | `ACTIVE`, `PAUSED`, or `ALL` |\r\n| `creatorName` | string | – | Creator username or name for `creatorSearch` |\r\n| `maxResults` | integer | `200` | Maximum records **per advertiser** in `adSearch`, or total records for the other modes (1–10,000) |\r\n| `includeCoverage` | boolean | `true` | Add one coverage row per advertiser/creator |\r\n| `proxyConfiguration` | object | – | Optional; the public API normally works without a proxy |\r\n\r\n### Example: multiple active advertisers in France, Germany and Turkey\r\n\r\n```json\r\n{\r\n  \"mode\": \"adSearch\",\r\n  \"payingAdvertiserNames\": [\"nike\", \"adidas\"],\r\n  \"advertiserMatch\": \"contains\",\r\n  \"countries\": [\"fr\", \"de\", \"tr\"],\r\n  \"status\": \"ACTIVE\",\r\n  \"maxResults\": 200\r\n}\r\n```\r\n\r\n### Example: exact payer match\r\n\r\n```json\r\n{\r\n  \"mode\": \"adSearch\",\r\n  \"payingAdvertiserNames\": [\"Nike, Inc.\"],\r\n  \"advertiserMatch\": \"exact\",\r\n  \"countries\": [\"fr\"]\r\n}\r\n```\r\n\r\n### Example: browse all sponsored content\r\n\r\n```json\r\n{\r\n  \"mode\": \"sponsoredContent\",\r\n  \"maxResults\": 500\r\n}\r\n```\r\n\r\n### Example: sponsored content by a creator\r\n\r\n```json\r\n{\r\n  \"mode\": \"creatorSearch\",\r\n  \"creatorName\": \"beauty\",\r\n  \"maxResults\": 100\r\n}\r\n```\r\n\r\n## Output per ad (`recordType = \"ad\"`)\r\n\r\n### Identity, advertiser and delivery\r\n\r\n- `adId`, `adName`, `adAccountName` — ad identifier, internal ad name and ad-account name\r\n- `payingAdvertiserName` — paying entity as disclosed by Snap (whitespace-normalized)\r\n- `brandName`, `profileName`, `profileLogoUrl` — brand (`brand_name` or profile fallback) and Snap public profile\r\n- `status`, `reviewStatus`, `rejectionReasons`, `startDate`, `endDate` (when published)\r\n- `daysActive` — days from `startDate` to `endDate` or now\r\n- `languages`\r\n- `searchAdvertiser`, `matchMode` — which input name/match mode produced the record\r\n- `matchedAdvertisers` — added only when the same ad matched more than one input advertiser\r\n\r\n### URLs and media\r\n\r\n- `adUrl` — public Ads Gallery detail page (`https://adsgallery.snap.com/?adId=...`), verified to open the ad\r\n- `adDetailApiUrl` — public API detail endpoint (`/v1/ads_library/ads/{adId}`)\r\n- `landingUrl` — web-view, deep-link or story-snap destination\r\n- `domain` — hostname of the HTTP(S) landing URL\r\n- `mediaUrls`, `mediaType` — all top-level and story-snap creative media URLs and their type\r\n- `topSnapMediaDownloadLink`, `mediaDownloadUrl`, `topSnapMediaType`, `topSnapCropPosition`\r\n- `webViewProperties`, `deepLinkProperties`, `compositePreview`, `dpaPreview`, `collectionPreview`, `lensPreview`, `stickers` — raw API objects, retained for completeness\r\n\r\n### Impressions\r\n\r\n- `impressionsTotal` — lifetime impressions from Snap (falls back to the per-country sum if Snap omits the total)\r\n- `impressionsByCountry` — only countries with a **nonzero** impression count\r\n- `countries` — those countries, largest first\r\n- `topCountry`, `topCountryImpressions`\r\n\r\n### Targeting\r\n\r\n- `targeting` — flat normalized targeting: `minAge`, `maxAge`, `ageRange`, `genders`, `languages`, `devices`, `regulatedContent`\r\n- `targetingV2` — raw `targeting_v2` object\r\n\r\n### Catalog, story, collection and lens\r\n\r\n- `products`, `productCount`, `dpaTemplate` — dynamic product-ad items with flattened image URLs\r\n- `story` — composite/story ads: `titleHeadline`, `shouldLoop`, `previewCreativeRenderType`, `snapCount`, and per-snap `snaps` (type, headline, CTA, media, landing URL)\r\n- `collection` — collection ads: `itemCount`, `items` (including app-install properties when present), `landingUrl`\r\n- `appInstall` — app-install properties when Snap publishes them\r\n- `lens` — lens preview (`iconUrl`)\r\n- `recordType` — always `ad`\r\n- `scrapedAt` — ISO-8601 UTC scrape timestamp\r\n\r\n## Output per sponsored content item (`recordType = \"sponsoredContent\"`)\r\n\r\n- `contentType`, `contentUrl`, `thumbnailUrl`\r\n- `creatorName`, `creatorUrl`\r\n- `sponsorName`, `sponsorUrl`, `brandName`\r\n- `recordType`, `scrapedAt`\r\n\r\n## Coverage rows and run summary\r\n\r\nWith `includeCoverage` enabled (default), the dataset also contains one row per advertiser/creator:\r\n\r\n- `recordType = \"coverage\"`, `mode`, `target`\r\n- `status` — `ok`, `no_ads`, `partial`, `rationed`, `blocked`, `invalid`, or `error`\r\n- `recordCount`, `rawRecordCount`, `duplicatesRemoved`, `pagesFetched`\r\n- `payerNames` — every payer name actually seen for that search, including non-matching names in `exact` mode\r\n- `countries`, `topCountry`, `impressionsTotal`\r\n- `recordsWithImpressions`, `recordsWithLandingUrl`, `recordsWithMedia`\r\n- `error`, `notes`, `requestIds`\r\n- Sponsored-content coverage also includes `creatorNames`, `sponsorNames`, `contentTypes`\r\n\r\nThe key-value store record `RUN_SUMMARY` contains the overall run status, counts by status, errors, notes, duration, input echo, source, scope and freshness.\r\n\r\n## No-results semantics\r\n\r\nEmpty results never produce a placeholder `{mode, error}` row. If Snap returns no matching ads, the run finishes with `status = \"no_ads\"` and writes no ad rows (coverage rows still show the search). If Snap rate-limits, blocks, rejects or partially fails a request, the summary reports `rationed`, `blocked`, `invalid`, `partial` or `error`, and any records already collected are kept.\r\n\r\n## Pagination and limits\r\n\r\n- **Advertiser search:** Snap serves **10 ads per request**. The actor POSTs the returned `paging.next_link` with the same JSON body; pagination is real and advances page by page.\r\n- **Creator search:** Snap serves up to 200 items per page. The actor POSTs `paging.next_link` with the same body. Pages can overlap; records are deduplicated by `contentUrl`.\r\n- **Sponsored content browse:** GET with `limit=200`, following GET `paging.next_link`.\r\n- **Rate limits:** Snap applies server-side limits (HTTP 429 and occasional 500/E4001 BigQuery rate-limit errors). The actor throttles requests and retries with exponential backoff plus `Retry-After`.\r\n- **Ad detail:** `GET /v1/ads_library/ads/{ad_id}` returns a complete `ad_preview`, verified live.\r\n- **Hard limits:** 12-month window, 24-hour impression refresh, no spend/reach, exact end dates are usually unpublished, no UK/US, and creator content has fewer fields.\r\n\r\n## Use cases\r\n\r\n- **Competitive ad monitoring** — track competitor creatives, CTAs, landing pages and per-country lifetime impressions\r\n- **Regulatory/transparency research** — study disclosed EU/Turkey ad targeting and impressions\r\n- **Creator partnership discovery** — find brands sponsoring a creator's content\r\n- **Creative benchmarking** — compare formats, CTAs and catalog/story/collection usage\r\n- **Impressions analysis** — use `impressionsByCountry`, `topCountry` and coverage rows\r\n\r\n## FAQ\r\n\r\n**Is this official Snapchat data?** Yes. It reads Snapchat's public Ads Gallery API, which Snap publishes under transparency rules; no private pages or user data are accessed.\r\n\r\n**Why does advertiser search return 10 ads at a time?** Ten is Snap's page size, not a total cap. This actor follows `paging.next_link` until `maxResults` per advertiser or the end of the result set.\r\n\r\n**Which countries are supported?** The 27 EU member states and Turkey. `gr` is mapped to `el`; unsupported codes are dropped with a warning instead of filtering out all results.\r\n\r\n**How current are impressions?** Snap updates the gallery at most every 24 hours, and the counts are lifetime impressions for each ad.\r\n\r\n**Can I download creatives?** Yes — `mediaUrls` and `topSnapMediaDownloadLink` are direct Snap CDN links. CDN URLs can expire, so download soon after scraping.\r\n\r\n**What is the difference between `sponsoredContent` and `creatorSearch`?** `sponsoredContent` pages through the whole live sponsored-content library. `creatorSearch` narrows it to one creator's name. Both return the same record shape.\r\n\r\n**Is this affiliated with Snapchat?** No. This is an independent third-party actor reading Snap's publicly mandated Ads Gallery API.\r\n"
    },
    "buildNumber": "1.0.2",
    "imageDigest": "e1c35f7fe3eeaba84fa8a46bbb8682f6f4088a3a6bcc670ccdbfbe74537689c0",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "1.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.00984
    }
  }
}