Raw Meta ads

Live ads from the public Meta Ad Library, normalized into one schema. Virlo reads the Ad Library when you call, and the answer comes back in the same request.

At a glance
What it does
Finds ads and advertisers in the Meta Ad Library as they are right now.
You send
A keyword, an ad ID, an advertiser name or an advertiser's Facebook page ID, plus optional filters.
You get back
Ads with their text, images, videos, dates and platforms, or advertisers with their page ID and follower counts.
Cost
$0.01 (1 credit) per call, including a call that finds nothing. Errors are free.
  • Synchronous. No job to poll. Each call returns one page. Most calls answer in 2 to 8 seconds, and a slow one can take about 25, so set your client timeout to at least 30 seconds.
  • Media links expire. Image and video URLs are Facebook CDN links that stop working after a few days. Download what you need to keep.
  • Spend and reach are ranges, and mostly null. The Ad Library shows reach for ads shown in the EU or UK, and spend, reach and impressions for political and issue ads. Every other ad has null there.
  • Unprocessed. No AI fields or history. To collect Meta ads next to TikTok, YouTube and Instagram research, turn on meta_ads_enabled on an agent. For live TikTok, YouTube and Instagram data, see Raw data.

Which one do I need?

Filters

Search ads and an advertiser's ads take three optional filters. Search advertisers takes country only.

  • Name
    country
    Type
    string
    Description

    Country where the ads were shown: a 2-letter ISO code such as US, GB or DE, or ALL. Default ALL. UK is read as GB.

  • Name
    status
    Type
    string
    Description

    active (running now), inactive (stopped) or all. Default active.

  • Name
    media_type
    Type
    string
    Description

    Ads that contain this media: image, video, meme, none (text only) or all. Default all.

The ad shape

A single ad comes back as { "data": { ... } }. A list comes back as { "data": [ ... ], "pagination": { "next_cursor": "...", "has_more": true } }. Timestamps are ISO 8601 in UTC. Counts are numbers or null, never strings.

Every ad, from any route, has these fields:

  • Name
    id
    Type
    string
    Description

    The Ad Library ID of the ad. Pass it to one ad.

  • Name
    url
    Type
    string
    Description

    The ad in the public Ad Library.

  • Name
    advertiser
    Type
    object
    Description

    page_id, name, avatar_url and url (the advertiser's Facebook page). name and avatar_url can be null.

  • Name
    is_active
    Type
    boolean | null
    Description

    true while the ad is running.

  • Name
    started_at
    Type
    string | null
    Description

    First day the ad ran.

In a range, a null bound is open. { "lower": 1000000, "upper": null } means more than 1 million.


GET/v1/raw/meta/ads/search

Ads whose text or advertiser matches a keyword, in the Ad Library's own order. The first page has about 30 ads and each later page about 10.

Cost per request:$0.01

Query parameters

  • Name
    q
    Type
    string
    Description

    Required. The keyword or phrase, 1 to 200 characters. It matches ad text and advertiser names.

  • Name
    country, status, media_type
    Type
    string
    Description

    Optional filters.

  • Name
    cursor
    Type
    string
    Description

    next_cursor from the previous page. See paging.

Request

GET
/v1/raw/meta/ads/search
curl -G "https://api.virlo.ai/v1/raw/meta/ads/search" \
  --data-urlencode "q=running shoes" \
  --data-urlencode "country=US" \
  --data-urlencode "media_type=video" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "data": [
    {
      "id": "1184620937415528",
      "url": "https://www.facebook.com/ads/library/?id=1184620937415528",
      "advertiser": {
        "page_id": "15087023444",
        "name": "Nike",
        "avatar_url": "https://scontent.xx.fbcdn.net/v/avatar.jpg",
        "url": "https://www.facebook.com/nike"
      },
      "is_active": true,
      "started_at": "2026-10-20T07:00:00.000Z",
      "ended_at": null,
      "publisher_platforms": ["facebook", "instagram"],
      "media_type": "video",
      "creatives": [
        {
          "body": "Built for the long run. More cushion, less weight.",
          "title": "Pegasus. Your everyday trainer.",
          "description": null,
          "caption": "nike.com",
          "cta_text": "Shop now",
          "cta_type": "shop_now",
          "link_url": "https://www.nike.com/running",
          "image_urls": [],
          "videos": [
            {
              "hd_url": "https://video.xx.fbcdn.net/v/example-hd.mp4",
              "sd_url": "https://video.xx.fbcdn.net/v/example-sd.mp4",
              "preview_image_url": "https://scontent.xx.fbcdn.net/v/poster.jpg"
            }
          ]
        }
      ],
      "variant_count": 3,
      "page_categories": ["Sportswear", "Product/service"],
      "reach": null,
      "spend": null,
      "impressions": null,
      "platform_data": {
        "display_format": "video",
        "collation_id": "2049316685821054",
        "page_like_count": 39494133
      }
    }
  ],
  "pagination": {
    "next_cursor": "eyJ2IjoxLCJjIjoiTTRuNXA2In0",
    "has_more": true
  }
}

GET/v1/raw/meta/ads/:ad_id

One ad by its Ad Library ID. An ad shown in the EU or UK also carries its exact reach and, in platform_data, its audience, payer and beneficiary.

Cost per request:$0.01

Path parameters

  • Name
    ad_id
    Type
    string
    Description

    The Ad Library ID, digits only: the id of an ad from any other route, or the id= in an Ad Library link.

Request

GET
/v1/raw/meta/ads/:ad_id
curl "https://api.virlo.ai/v1/raw/meta/ads/1096372158840215" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "data": {
    "id": "1096372158840215",
    "url": "https://www.facebook.com/ads/library/?id=1096372158840215",
    "advertiser": {
      "page_id": "15087023444",
      "name": "Nike",
      "avatar_url": "https://scontent.xx.fbcdn.net/v/avatar.jpg",
      "url": "https://www.facebook.com/nike"
    },
    "is_active": false,
    "started_at": "2026-10-06T07:00:00.000Z",
    "ended_at": "2026-10-24T07:00:00.000Z",
    "publisher_platforms": ["facebook", "instagram"],
    "media_type": "image",
    "creatives": [
      {
        "body": "New colours for the season. Free returns for members.",
        "title": "Air Max: new colours",
        "description": null,
        "caption": "nike.com",
        "cta_text": "Shop now",
        "cta_type": "shop_now",
        "link_url": "https://www.nike.com/gb/air-max",
        "image_urls": ["https://scontent.xx.fbcdn.net/v/creative.jpg"],
        "videos": []
      }
    ],
    "variant_count": null,
    "page_categories": ["Sportswear", "Product/service"],
    "reach": { "lower": 412890, "upper": 412890 },
    "spend": null,
    "impressions": null,
    "platform_data": {
      "display_format": "image",
      "page_like_count": 39494133,
      "audience": {
        "gender": "All",
        "age_min": 18,
        "age_max": 65,
        "locations": ["United Kingdom"]
      },
      "payer": "NIKE, Inc.",
      "beneficiary": "NIKE, Inc."
    }
  }
}

GET/v1/raw/meta/advertisers/search

Advertisers (Facebook pages) whose name matches, in the Ad Library's own order, usually 5 to 15. Use a result's page_id with an advertiser's ads.

This route returns one list with no pagination. A search that finds nothing returns { "data": [] } and costs $0.01.

Cost per request:$0.01

Query parameters

  • Name
    q
    Type
    string
    Description

    Required. The advertiser's name or part of it, 1 to 200 characters.

  • Name
    country
    Type
    string
    Description

    Optional. Changes which pages the Ad Library suggests. See filters.

Advertiser fields

  • Name
    page_id
    Type
    string
    Description

    The advertiser's Facebook page ID.

  • Name
    name, avatar_url
    Type
    string | null
    Description

    Page name and avatar. The avatar link expires.

  • Name
    url
    Type
    string
    Description

    The advertiser's Facebook page.

  • Name
    verified
    Type
    boolean | null
    Description

    Whether the page has a verified badge.

  • Name
    likes
    Type
    number | null
    Description

    Facebook page likes.

Request

GET
/v1/raw/meta/advertisers/search
curl -G "https://api.virlo.ai/v1/raw/meta/advertisers/search" \
  --data-urlencode "q=nike" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "data": [
    {
      "page_id": "15087023444",
      "name": "Nike",
      "avatar_url": "https://scontent.xx.fbcdn.net/v/avatar.jpg",
      "url": "https://www.facebook.com/nike",
      "verified": true,
      "likes": 39494133,
      "category": "Sportswear Store",
      "instagram_handle": "nike",
      "instagram_followers": 290887065,
      "platform_data": {
        "page_alias": "nike",
        "verification": "blue_verified",
        "instagram_verified": true
      }
    }
  ]
}

GET/v1/raw/meta/advertisers/:page_id/ads

An advertiser's ads

The ads of one advertiser. There are two routes, and each returns the same shape:

  • GET /v1/raw/meta/advertisers/:page_id/ads takes the advertiser's Facebook page ID. Use it when you know exactly which advertiser you want.
  • GET /v1/raw/meta/advertisers/ads?name= takes a name. Virlo uses the first live advertiser the Ad Library suggests for that name. The advertiser object in the response says which one it used. If it is the wrong one, call search advertisers and use the :page_id route.

The response adds advertiser next to data and pagination: { "data": [ ... ], "advertiser": { ... }, "pagination": { ... } }. It has the advertiser fields, plus platform_data.ad_count, the number of ads that match your filters as the Ad Library counts them (it stops at 50,001). Called with :page_id, category, instagram_handle and instagram_followers are null.

Cost per request:$0.01

Path parameters

  • Name
    page_id
    Type
    string
    Description

    The advertiser's Facebook page ID, digits only: page_id from advertiser search, or advertiser.page_id from any ad. Only on the :page_id route.

Query parameters

  • Name
    name
    Type
    string
    Description

    Required on /v1/raw/meta/advertisers/ads, and not accepted on the :page_id route. The advertiser's name, 1 to 200 characters.

  • Name
    country, status, media_type
    Type
    string
    Description

    Optional filters.

  • Name
    cursor
    Type
    string
    Description

    next_cursor from the previous page. See paging. With name, every later call reuses the advertiser the first call found.

Request

GET
/v1/raw/meta/advertisers/:page_id/ads
curl -G "https://api.virlo.ai/v1/raw/meta/advertisers/15087023444/ads" \
  --data-urlencode "country=US" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "data": [
    {
      "id": "1184620937415528",
      "url": "https://www.facebook.com/ads/library/?id=1184620937415528",
      "advertiser": {
        "page_id": "15087023444",
        "name": "Nike",
        "avatar_url": "https://scontent.xx.fbcdn.net/v/avatar.jpg",
        "url": "https://www.facebook.com/nike"
      },
      "is_active": true,
      "started_at": "2026-10-20T07:00:00.000Z",
      "ended_at": null,
      "publisher_platforms": ["facebook", "instagram"],
      "media_type": "video",
      "creatives": [
        {
          "body": "Built for the long run. More cushion, less weight.",
          "title": "Pegasus. Your everyday trainer.",
          "description": null,
          "caption": "nike.com",
          "cta_text": "Shop now",
          "cta_type": "shop_now",
          "link_url": "https://www.nike.com/running",
          "image_urls": [],
          "videos": [
            {
              "hd_url": "https://video.xx.fbcdn.net/v/example-hd.mp4",
              "sd_url": "https://video.xx.fbcdn.net/v/example-sd.mp4",
              "preview_image_url": "https://scontent.xx.fbcdn.net/v/poster.jpg"
            }
          ]
        }
      ],
      "variant_count": 3,
      "page_categories": ["Sportswear", "Product/service"],
      "reach": null,
      "spend": null,
      "impressions": null,
      "platform_data": {
        "display_format": "video",
        "page_like_count": 39494133
      }
    }
  ],
  "advertiser": {
    "page_id": "15087023444",
    "name": "Nike",
    "avatar_url": "https://scontent.xx.fbcdn.net/v/avatar.jpg",
    "url": "https://www.facebook.com/nike",
    "verified": true,
    "likes": 39494133,
    "category": "Sportswear Store",
    "instagram_handle": "nike",
    "instagram_followers": 290887065,
    "platform_data": {
      "page_alias": "nike",
      "verification": "blue_verified",
      "ad_count": 1240
    }
  },
  "pagination": {
    "next_cursor": "eyJ2IjoxLCJjIjoiSzJqM2g0In0",
    "has_more": true
  }
}

Paging through results

Search ads and an advertiser's ads return one page per call: about 30 ads on the first page, then about 10 on each page after it. Search advertisers does not page.

  • Keep going while has_more is true. Send the same request again with cursor set to next_cursor. On the last page next_cursor is null and has_more is false.
  • There is no limit. The Ad Library decides how many ads are on a page.
  • Keep the filters the same. A cursor works only with the request that produced it: the same route, input and filters. Send country=GB with a cursor from a country=US call and you get 400 with invalid_cursor.
  • Cursors are opaque and expire after 6 hours. Don't build or change one. A changed, expired or mismatched cursor returns 400 with invalid_cursor: start again from page 1.
  • Each page is a separate call and costs $0.01.

Page 2

curl -G "https://api.virlo.ai/v1/raw/meta/ads/search" \
  --data-urlencode "q=running shoes" \
  --data-urlencode "country=US" \
  --data-urlencode "media_type=video" \
  --data-urlencode "cursor=eyJ2IjoxLCJjIjoiTTRuNXA2In0" \
  -H "Authorization: Bearer YOUR_API_KEY"

Costs and errors

  • $0.01 (1 credit) per call on every route. A call that succeeds but finds nothing (an empty page or an empty advertiser list) is charged.
  • Errors cost nothing. That includes every 4xx and 5xx below. X-Cost shows the charge in dollars and X-Credits-Used in credits.
  • Not saved. Virlo does not keep these results for you. Call again to get fresh data, and download media you want to keep before the links expire.

Errors come back with message, error, statusCode and code (more on errors):

ErrorWhen it happens
400 validation_errorA missing or bad parameter: no q, a q or name over 200 characters, an ad_id or page_id that is not all digits, a country that is not ALL or a 2-letter ISO code, a status or media_type outside the list, name on the page ID route, or a parameter the route doesn't take.
400 invalid_cursorThe cursor was changed, has expired, belongs to a different request, or was sent with different filters. Start again from page 1.
402 insufficient_creditsYour balance is below $0.01.
404 not_foundNo ad has that ID, no advertiser has that page ID, or no live advertiser matches the name.
429 rate_limit_exceededYour key sent too many requests. Wait retry_after seconds.
502 upstream_errorVirlo could not get the data from the Ad Library this time. Retry after a few seconds.
503 service_unavailableRaw data is briefly unavailable. Retry later.
504 request_timeoutThe Ad Library took too long to answer. Retry after a few seconds.

Was this page helpful?