Facebook Ad Library Search API

Beta

Searches Meta's public Ad Library by keyword and returns the matching ads that ran on Facebook, Instagram, Messenger, Threads and the Audience Network: the advertiser's page, the days the ad first and last ran, whether it is still active, where it ran, and each creative's headline, text, link, call to action, images and videos. Political and social-issue ads also carry the disclosed payer and Meta's impressions, reach and spend ranges. Filter by country, language, active status and the day an ad first ran; results come in the Ad Library's own order, most impressions first.

Get 100 free creditsAPI referenceTry it

Price
From 1 credit per page$0.75–$1.45 per 1,000 pages
Request
GET /v1/facebook/search_adsOne API key, one JSON schema
Input
querye.g. coffee
Page size
Up to 10 ads

Use cases

What teams build with it. From one request.

  • Monitor competitors' ad creatives and offers
  • Research ad copy in a market or niche
  • Track political and issue ad spending
  • Find the advertisers running ads on a topic

What you get

Ads in one schema. The same on every platform.

platformstring
Library owner's platform ID (facebook for Meta's library, tiktok, google, linkedin).
idstring
Library ad ID (string).
urlstring
Public library page of the ad.
advertiserobject
The advertising page, business or account.
paid_bystring
Disclosed payer ("Paid for by").
is_activeboolean
True while the ad is running.
first_shown_atstring
First delivery, RFC 3339 UTC (often date-only: see approximate_fields).
last_shown_atstring
Last delivery, RFC 3339 UTC; null while active.

Every field, its type and when it is null: the response reference and the ad schema.

Example request

cURL
curl -G 'https://staging-fly.socialtap.dev/v1/facebook/search_ads' \
  --data-urlencode 'country=US' \
  --data-urlencode 'query=coffee' \
  --data-urlencode 'status=all' \
  -H "x-api-key: $SOCIALTAP_API_KEY"
Node.js
const params = new URLSearchParams({
  country: "US",
  query: "coffee",
  status: "all",
});
const res = await fetch(`https://staging-fly.socialtap.dev/v1/facebook/search_ads?${params}`, {
  headers: { "x-api-key": process.env.SOCIALTAP_API_KEY ?? "" },
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const { data, page, meta } = body;
console.log(data, meta.credits_charged);
Python
import os

import requests

res = requests.get(
    "https://staging-fly.socialtap.dev/v1/facebook/search_ads",
    params={"country": "US", "query": "coffee", "status": "all"},
    headers={"x-api-key": os.environ["SOCIALTAP_API_KEY"]},
)
body = res.json()
if not res.ok:
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
data, page, meta = body["data"], body["page"], body["meta"]
print(data, meta["credits_charged"])
Go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
)

func main() {
	q := url.Values{}
	q.Set("country", "US")
	q.Set("query", "coffee")
	q.Set("status", "all")
	req, err := http.NewRequest("GET", "https://staging-fly.socialtap.dev/v1/facebook/search_ads?"+q.Encode(), nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("x-api-key", os.Getenv("SOCIALTAP_API_KEY"))
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	var body struct {
		Data  json.RawMessage `json:"data"`
		Page  json.RawMessage `json:"page"`
		Meta  map[string]any  `json:"meta"`
		Error *struct {
			Code    string `json:"code"`
			Message string `json:"message"`
		} `json:"error"`
	}
	if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
		log.Fatal(err)
	}
	if body.Error != nil {
		log.Fatalf("%s: %s", body.Error.Code, body.Error.Message)
	}
	fmt.Println(string(body.Data), body.Meta["credits_charged"])
}
PHP
<?php

$query = http_build_query([
    'country' => 'US',
    'query' => 'coffee',
    'status' => 'all',
]);
$ch = curl_init('https://staging-fly.socialtap.dev/v1/facebook/search_ads?' . $query);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['x-api-key: ' . getenv('SOCIALTAP_API_KEY')],
]);
$body = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) >= 400) {
    throw new RuntimeException($body['error']['code'] . ': ' . $body['error']['message']);
}
print_r($body['data']);
echo $body['meta']['credits_charged'], PHP_EOL;
Ruby
require "json"
require "net/http"

uri = URI("https://staging-fly.socialtap.dev/v1/facebook/search_ads")
uri.query = URI.encode_www_form('country' => 'US', 'query' => 'coffee', 'status' => 'all')
req = Net::HTTP::Get.new(uri)
req["x-api-key"] = ENV.fetch("SOCIALTAP_API_KEY")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
body = JSON.parse(res.body)
raise "#{body["error"]["code"]}: #{body["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
pp body["data"]
puts body["meta"]["credits_charged"]
Java
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class Main {
    public static void main(String[] args) throws Exception {
        String query = "country=" + encode("US")
            + "&query=" + encode("coffee")
            + "&status=" + encode("all");
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://staging-fly.socialtap.dev/v1/facebook/search_ads?" + query))
            .header("x-api-key", System.getenv("SOCIALTAP_API_KEY"))
            .GET()
            .build();
        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());
        // An error is {"error": {"code", "message", ...}}; success is {data, meta}, meta.credits_charged its price.
        if (response.statusCode() >= 400) throw new RuntimeException(response.body());
        System.out.println(response.body());
    }

    static String encode(String value) {
        return URLEncoder.encode(value, StandardCharsets.UTF_8);
    }
}
.NET
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", Environment.GetEnvironmentVariable("SOCIALTAP_API_KEY"));

var query = string.Join("&",
    "country=" + Uri.EscapeDataString("US"),
    "query=" + Uri.EscapeDataString("coffee"),
    "status=" + Uri.EscapeDataString("all"));
var res = await http.GetAsync("https://staging-fly.socialtap.dev/v1/facebook/search_ads?" + query);
using var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());
if (!res.IsSuccessStatusCode)
{
    var error = body.RootElement.GetProperty("error");
    throw new Exception($"{error.GetProperty("code")}: {error.GetProperty("message")}");
}
Console.WriteLine(body.RootElement.GetProperty("data"));
Console.WriteLine(body.RootElement.GetProperty("meta").GetProperty("credits_charged"));
Rust
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }, serde_json = "1"
use std::env;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let res = reqwest::blocking::Client::new()
        .get("https://staging-fly.socialtap.dev/v1/facebook/search_ads")
        .query(&[("country", "US"), ("query", "coffee"), ("status", "all")])
        .header("x-api-key", env::var("SOCIALTAP_API_KEY")?)
        .send()?;
    let ok = res.status().is_success();
    let body: serde_json::Value = res.json()?;
    if !ok {
        return Err(format!("{}: {}", body["error"]["code"], body["error"]["message"]).into());
    }
    println!("{} {}", body["data"], body["meta"]["credits_charged"]);
    Ok(())
}
200 OK
{
  "data": [
    {
      "advertiser": {
        "avatar_url": "https://scontent-atl3-2.xx.fbcdn.net/v/t39.35426-6/739782028_1533198008291919_1079542453788497101_n.jpg?stp=dst-jpg_s60x60_tt6&_nc_cat=104&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=14&_nc_ht=scontent-atl3-2.xx&_nc_gid=SCRUBBED&_nc_ss=7b289&oh=SCRUBBED&…",
        "display_name": "American Health Support Community",
        "id": "966175593248497",
        "is_verified": null,
        "url": "https://www.facebook.com/61588018263996",
        "username": null
      },
      "approximate_fields": [
        "first_shown_at"
      ],
      "audience_size": null,
      "country_codes": [],
      "creatives": [
        {
          "body": "My aunt called me a creep for putting a camera in Nana’s living room.\n\nNana called me practical.\n\nThen the camera caught something worse than a fall.\n\nI need to be clear about one thing before anyone decides what kind of grandson I am.\n\nNana asked for the camera.\n\nNot me.\n\nNot my…",
          "cta_text": "Learn more",
          "link_description": null,
          "link_url": "https://shop.pipitea.com/hbt/kd/sp-nm",
          "media": [
            {
              "alt_text": null,
              "duration_ms": null,
              "expires_at": "2026-10-25T18:00:00Z",
              "height": null,
              "thumbnail_url": "https://scontent-atl3-1.xx.fbcdn.net/v/t39.35426-6/742001725_2100792434176297_9060645049521596104_n.jpg?stp=dst-jpg_s600x600_tt6&_nc_cat=100&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=14&_nc_ht=scontent-atl3-1.xx&_nc_gid=SCRUBBED&_nc_ss=7b289&oh=SCRUBBE…",
              "type": "image",
              "url": "https://scontent-atl3-1.xx.fbcdn.net/v/t39.35426-6/742501415_1706621370582971_4085631001896338504_n.jpg?_nc_cat=103&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=14&_nc_ht=scontent-atl3-1.xx&_nc_gid=SCRUBBED&_nc_ss=7b289&oh=SCRUBBED&oe=F2A52380",
              "width": null
            }
          ],
          "title": "Natural Relief in Weeks"
        }
      ],
      "first_shown_at": "2026-07-18T07:00:00Z",
      "id": "2619351891814847",
      "impressions": null,
      "is_active": true,
      "is_political": false,
      "languages": [],
      "last_shown_at": null,
      "paid_by": null,
      "platform": "facebook",
      "platform_specific": {},
      "publisher_platforms": [
        "facebook",
        "instagram",
        "audience_network"
      ],
      "reach": null,
      "spend": null,
      "type": "image",
      "unknown_fields": [],
      "url": "https://www.facebook.com/ads/library/?id=2619351891814847"
    },
    {
      "advertiser": {
        "avatar_url": "https://scontent-atl3-1.xx.fbcdn.net/v/t39.35426-6/712623693_1599994994434095_1320701223312676781_n.jpg?stp=dst-jpg_s60x60_tt6&_nc_cat=110&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=14&_nc_ht=scontent-atl3-1.xx&_nc_gid=SCRUBBED&_nc_ss=7b289&oh=SCRUBBED&…",
        "display_name": "American Health Support Community",
        "id": "966175593248497",
        "is_verified": null,
        "url": "https://www.facebook.com/61588018263996",
        "username": null
      },
      "approximate_fields": [
        "first_shown_at"
      ],
      "audience_size": null,
      "country_codes": [],
      "creatives": [
        {
          "body": "I almost looked past the woman who saved my husband's life. She was seventy-nine, sitting alone at the booth next to ours at the Cracker Barrel off Highway 31. A glass of milk in front of her. She kept stirring it. She wasn't eating.\n\nIf I'd known, the night I leaned over and ask…",
          "cta_text": "Learn more",
          "link_description": "\"I've tried everything to support my kidney function naturally. Fish oil, CoQ10, cutting protein, stressing about every meal. Nothing moved the needle enough to satisfy my doctor. Hibiscus tea is the first thing that actually showed up in my numbers. It's been 3 months and my eGF…",
          "link_url": "https://shop.pipitea.com/hbt/kd/sp",
          "media": [
            {
              "alt_text": null,
              "duration_ms": null,
              "expires_at": "2026-10-25T18:00:00Z",
              "height": null,
              "thumbnail_url": "https://scontent-atl3-2.xx.fbcdn.net/v/t39.35426-6/711729685_1717035472767079_186136568392095276_n.jpg?stp=dst-jpg_s600x600_tt6&_nc_cat=104&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=14&_nc_ht=scontent-atl3-2.xx&_nc_gid=SCRUBBED&_nc_ss=7b289&oh=SCRUBBED…",
              "type": "image",
              "url": "https://scontent-atl3-1.xx.fbcdn.net/v/t39.35426-6/713729791_868879862958547_7409366389733397444_n.jpg?_nc_cat=107&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=14&_nc_ht=scontent-atl3-1.xx&_nc_gid=SCRUBBED&_nc_ss=7b289&oh=SCRUBBED&oe=F2A52380",
              "width": null
            }
          ],
          "title": "Natural Relief in Weeks"
        }
      ],
      "first_shown_at": "2026-06-01T07:00:00Z",
      "id": "1923645134954720",
      "impressions": null,
      "is_active": true,
      "is_political": false,
      "languages": [],
      "last_shown_at": null,
      "paid_by": null,
      "platform": "facebook",
      "platform_specific": {},
      "publisher_platforms": [
        "facebook",
        "instagram",
        "audience_network"
      ],
      "reach": null,
      "spend": null,
      "type": "image",
      "unknown_fields": [],
      "url": "https://www.facebook.com/ads/library/?id=1923645134954720"
    },
    {
      "advertiser": {
        "avatar_url": "https://scontent-atl3-1.xx.fbcdn.net/v/t39.35426-6/712025330_1303417705276292_736671271727941526_n.jpg?stp=dst-jpg_s60x60_tt6&_nc_cat=103&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=14&_nc_ht=scontent-atl3-1.xx&_nc_gid=SCRUBBED&_nc_ss=7b289&oh=SCRUBBED&o…",
        "display_name": "American Health Support Community",
        "id": "966175593248497",
        "is_verified": null,
        "url": "https://www.facebook.com/61588018263996",
        "username": null
      },
      "approximate_fields": [
        "first_shown_at"
      ],
      "audience_size": null,
      "country_codes": [],
      "creatives": [
        {
          "body": "I almost looked past the woman who saved my husband's life. She was seventy-nine, sitting alone at the booth next to ours at the Cracker Barrel off Highway 31. A glass of milk in front of her. She kept stirring it. She wasn't eating.\n\nIf I'd known, the night I leaned over and ask…",
          "cta_text": "Learn more",
          "link_description": "\"I've tried everything to support my kidney function naturally. Fish oil, CoQ10, cutting protein, stressing about every meal. Nothing moved the needle enough to satisfy my doctor. Hibiscus tea is the first thing that actually showed up in my numbers. It's been 3 months and my eGF…",
          "link_url": "https://shop.pipitea.com/hbt/kd/sp",
          "media": [
            {
              "alt_text": null,
              "duration_ms": null,
              "expires_at": "2026-10-25T18:00:00Z",
              "height": null,
              "thumbnail_url": "https://scontent-atl3-1.xx.fbcdn.net/v/t39.35426-6/711737708_4485707625086258_2353150069319301753_n.jpg?stp=dst-jpg_s600x600_tt6&_nc_cat=109&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=14&_nc_ht=scontent-atl3-1.xx&_nc_gid=SCRUBBED&_nc_ss=7b289&oh=SCRUBBE…",
              "type": "image",
              "url": "https://scontent-atl3-2.xx.fbcdn.net/v/t39.35426-6/710755472_911440771966686_1736050619245168045_n.jpg?_nc_cat=111&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=14&_nc_ht=scontent-atl3-2.xx&_nc_gid=SCRUBBED&_nc_ss=7b289&oh=SCRUBBED&oe=F2A52380",
              "width": null
            }
          ],
          "title": "Natural Relief in Weeks"
        }
      ],
      "first_shown_at": "2026-06-01T07:00:00Z",
      "id": "2140497416496021",
      "impressions": null,
      "is_active": true,
      "is_political": false,
      "languages": [],
      "last_shown_at": null,
      "paid_by": null,
      "platform": "facebook",
      "platform_specific": {},
      "publisher_platforms": [
        "facebook",
        "instagram",
        "audience_network"
      ],
      "reach": null,
      "spend": null,
      "type": "image",
      "unknown_fields": [],
      "url": "https://www.facebook.com/ads/library/?id=2140497416496021"
    }
  ],
  "page": {
    "has_more": true,
    "next_cursor": "c1.EXAMPLE_CURSOR",
    "next_cursor_expires_at": "2026-10-26T12:00:00Z",
    "end_reason": null
  },
  "meta": {
    "request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
    "platform": "facebook",
    "source": "api",
    "is_cached": false,
    "credits_charged": 1,
    "latency_ms": 0,
    "fetched_at": "2026-10-25T12:00:00Z",
    "input": null,
    "credits_remaining": 9999,
    "client_request_id": null,
    "warnings": [],
    "mode": "live"
  }
}

Long arrays and strings are shortened for display; real responses are complete.

Pricing

Pay per page. Only when it succeeds.

SourcePrice per successful pagePer 1,000 pages
Platform API api1 credit$0.75–$1.45
  • Failed requests are free: errors cost 0 credits.
  • Cache hits are free: responses served from the cache cost 0 credits.
  • Credits never expire.
  • One credit balance for every endpoint and platform.

Credit packs · How this endpoint is priced · How credits work

FAQ

Questions, answered.

How do I search for an exact phrase?
Wrap the query in double quotes, for example "cold brew"; without quotes every word must appear, in any order.
Which ads does it find?
Every ad in Meta's public Ad Library whose text matches the query: active and inactive ads on all of Meta's apps, from any advertiser.
How much does the Facebook Ad Library Search API cost?
1 credit for platform api results (meta.source = api) per page of up to 10 items, charged for every successful page, empty pages included. SocialTap credits cost $0.75–$1.45 per 1,000 depending on the pack.
How do I get the next page?
Repeat the same request with cursor set to page.next_cursor from the previous response, keeping the other parameters. When page.has_more is false there are no more items. Cursors expire after 1 hour.
Am I charged for failed requests?
No. Requests that return an error cost 0 credits. Responses served from the cache are free too.

Start with 100 free credits. No card required.

Test keys answer every endpoint from recorded responses, free, so you can build before you spend. Failed requests are always free.

Get your API keyRead the API reference