@thenavidm/facebook-ad-library-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +359 -0
- package/SKILL.md +115 -0
- package/dist/adlibrary/harvest.d.ts +35 -0
- package/dist/adlibrary/harvest.js +153 -0
- package/dist/adlibrary/harvest.js.map +1 -0
- package/dist/adlibrary/normalize.d.ts +25 -0
- package/dist/adlibrary/normalize.js +221 -0
- package/dist/adlibrary/normalize.js.map +1 -0
- package/dist/adlibrary/types.d.ts +101 -0
- package/dist/adlibrary/types.js +17 -0
- package/dist/adlibrary/types.js.map +1 -0
- package/dist/adlibrary/url.d.ts +10 -0
- package/dist/adlibrary/url.js +29 -0
- package/dist/adlibrary/url.js.map +1 -0
- package/dist/archive/client.d.ts +45 -0
- package/dist/archive/client.js +124 -0
- package/dist/archive/client.js.map +1 -0
- package/dist/backends/apify.d.ts +37 -0
- package/dist/backends/apify.js +152 -0
- package/dist/backends/apify.js.map +1 -0
- package/dist/backends/browser.d.ts +51 -0
- package/dist/backends/browser.js +202 -0
- package/dist/backends/browser.js.map +1 -0
- package/dist/backends/index.d.ts +8 -0
- package/dist/backends/index.js +25 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/scrapecreators.d.ts +29 -0
- package/dist/backends/scrapecreators.js +185 -0
- package/dist/backends/scrapecreators.js.map +1 -0
- package/dist/config.d.ts +18 -0
- package/dist/config.js +33 -0
- package/dist/config.js.map +1 -0
- package/dist/doctor.d.ts +10 -0
- package/dist/doctor.js +131 -0
- package/dist/doctor.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.js +25 -0
- package/dist/errors.js.map +1 -0
- package/dist/format/ads.d.ts +16 -0
- package/dist/format/ads.js +97 -0
- package/dist/format/ads.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.js +156 -0
- package/dist/server.js.map +1 -0
- package/dist/store/snapshots.d.ts +29 -0
- package/dist/store/snapshots.js +83 -0
- package/dist/store/snapshots.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.js +14 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/kit.d.ts +70 -0
- package/dist/tools/kit.js +90 -0
- package/dist/tools/kit.js.map +1 -0
- package/dist/tools/search.d.ts +5 -0
- package/dist/tools/search.js +165 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/session.d.ts +3 -0
- package/dist/tools/session.js +23 -0
- package/dist/tools/session.js.map +1 -0
- package/dist/tools/track.d.ts +9 -0
- package/dist/tools/track.js +68 -0
- package/dist/tools/track.js.map +1 -0
- package/dist/tools/transparency.d.ts +5 -0
- package/dist/tools/transparency.js +53 -0
- package/dist/tools/transparency.js.map +1 -0
- package/dist/transport/http.d.ts +23 -0
- package/dist/transport/http.js +88 -0
- package/dist/transport/http.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harvest.js","sourceRoot":"","sources":["../../src/adlibrary/harvest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning each source's payload into one `Ad`.
|
|
3
|
+
*
|
|
4
|
+
* Field shapes here were verified against a live capture on 2026-08-31: 40 ads
|
|
5
|
+
* spanning every display format Meta serves (DCO, DPA, VIDEO, IMAGE, CAROUSEL).
|
|
6
|
+
* Creatives arrive in three disjoint places depending on that format, which is
|
|
7
|
+
* the single most common thing other scrapers get wrong.
|
|
8
|
+
*/
|
|
9
|
+
import type { Ad, BackendName } from "./types.js";
|
|
10
|
+
type Json = Record<string, unknown>;
|
|
11
|
+
/** Unix seconds to an ISO date. Meta sends integers, providers sometimes send strings. */
|
|
12
|
+
export declare function isoDate(value: unknown): string | undefined;
|
|
13
|
+
/** Meta wraps copy as {"text": "..."}. Providers send a bare string. */
|
|
14
|
+
export declare function text(value: unknown): string | undefined;
|
|
15
|
+
/** `l.facebook.com/l.php?u=<real>` to `<real>`. */
|
|
16
|
+
export declare function unwrapRedirect(url: string | undefined): string | undefined;
|
|
17
|
+
export declare function domainOf(url: string | undefined): string | undefined;
|
|
18
|
+
/** Normalise one `collated_results` entry from Meta's Ad Library GraphQL. */
|
|
19
|
+
export declare function adFromGraphql(node: Json, source?: BackendName): Ad;
|
|
20
|
+
/**
|
|
21
|
+
* Apify flattens the card into its own field names. Where it passes Meta's
|
|
22
|
+
* shape through untouched, reuse the Meta path rather than mapping twice.
|
|
23
|
+
*/
|
|
24
|
+
export declare function adFromApify(item: Json): Ad;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning each source's payload into one `Ad`.
|
|
3
|
+
*
|
|
4
|
+
* Field shapes here were verified against a live capture on 2026-08-31: 40 ads
|
|
5
|
+
* spanning every display format Meta serves (DCO, DPA, VIDEO, IMAGE, CAROUSEL).
|
|
6
|
+
* Creatives arrive in three disjoint places depending on that format, which is
|
|
7
|
+
* the single most common thing other scrapers get wrong.
|
|
8
|
+
*/
|
|
9
|
+
const AD_DETAILS = "https://www.facebook.com/ads/library/?id=";
|
|
10
|
+
function obj(value) {
|
|
11
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
12
|
+
? value
|
|
13
|
+
: undefined;
|
|
14
|
+
}
|
|
15
|
+
function str(value) {
|
|
16
|
+
return typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
17
|
+
}
|
|
18
|
+
function num(value) {
|
|
19
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
20
|
+
}
|
|
21
|
+
function arr(value) {
|
|
22
|
+
return Array.isArray(value) ? value.filter((v) => obj(v) !== undefined) : [];
|
|
23
|
+
}
|
|
24
|
+
function strArray(value) {
|
|
25
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
26
|
+
}
|
|
27
|
+
/** Unix seconds to an ISO date. Meta sends integers, providers sometimes send strings. */
|
|
28
|
+
export function isoDate(value) {
|
|
29
|
+
if (value === null || value === undefined || value === "" || value === 0)
|
|
30
|
+
return undefined;
|
|
31
|
+
let seconds;
|
|
32
|
+
if (typeof value === "number")
|
|
33
|
+
seconds = value;
|
|
34
|
+
else if (typeof value === "string") {
|
|
35
|
+
if (!/^\d+$/.test(value))
|
|
36
|
+
return value.length >= 10 ? value.slice(0, 10) : value;
|
|
37
|
+
seconds = Number(value);
|
|
38
|
+
}
|
|
39
|
+
if (seconds === undefined || !Number.isFinite(seconds))
|
|
40
|
+
return undefined;
|
|
41
|
+
const date = new Date(seconds * 1000);
|
|
42
|
+
return Number.isNaN(date.getTime()) ? undefined : date.toISOString().slice(0, 10);
|
|
43
|
+
}
|
|
44
|
+
/** Meta wraps copy as {"text": "..."}. Providers send a bare string. */
|
|
45
|
+
export function text(value) {
|
|
46
|
+
if (typeof value === "string")
|
|
47
|
+
return str(value);
|
|
48
|
+
const wrapper = obj(value);
|
|
49
|
+
return wrapper ? str(wrapper["text"]) : undefined;
|
|
50
|
+
}
|
|
51
|
+
/** `l.facebook.com/l.php?u=<real>` to `<real>`. */
|
|
52
|
+
export function unwrapRedirect(url) {
|
|
53
|
+
if (!url || !url.includes("l.facebook.com"))
|
|
54
|
+
return url;
|
|
55
|
+
try {
|
|
56
|
+
const target = new URL(url).searchParams.get("u");
|
|
57
|
+
return target ? decodeURIComponent(target) : url;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return url;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function domainOf(url) {
|
|
64
|
+
if (!url)
|
|
65
|
+
return undefined;
|
|
66
|
+
try {
|
|
67
|
+
const host = new URL(url).hostname.toLowerCase();
|
|
68
|
+
return host.startsWith("www.") ? host.slice(4) : host || undefined;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** `FACEBOOK` to `Facebook`, `AUDIENCE_NETWORK` to `Audience Network`. */
|
|
75
|
+
function platformLabel(value) {
|
|
76
|
+
return value
|
|
77
|
+
.split("_")
|
|
78
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
|
|
79
|
+
.join(" ");
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Creatives live in three disjoint places depending on ad format:
|
|
83
|
+
* images: IMAGE ads videos: VIDEO ads
|
|
84
|
+
* cards: DCO, DPA, CAROUSEL, and these carry per-card copy and links
|
|
85
|
+
*/
|
|
86
|
+
function creativesFrom(snapshot) {
|
|
87
|
+
const out = [];
|
|
88
|
+
for (const image of arr(snapshot["images"])) {
|
|
89
|
+
out.push({
|
|
90
|
+
kind: "image",
|
|
91
|
+
imageUrl: str(image["original_image_url"]) ?? str(image["resized_image_url"]),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
for (const video of arr(snapshot["videos"])) {
|
|
95
|
+
out.push({
|
|
96
|
+
kind: "video",
|
|
97
|
+
videoHdUrl: str(video["video_hd_url"]),
|
|
98
|
+
videoSdUrl: str(video["video_sd_url"]),
|
|
99
|
+
previewImageUrl: str(video["video_preview_image_url"]),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
for (const card of arr(snapshot["cards"])) {
|
|
103
|
+
const hd = str(card["video_hd_url"]);
|
|
104
|
+
const sd = str(card["video_sd_url"]);
|
|
105
|
+
out.push({
|
|
106
|
+
kind: hd || sd ? "video" : "image",
|
|
107
|
+
imageUrl: str(card["original_image_url"]) ?? str(card["resized_image_url"]),
|
|
108
|
+
videoHdUrl: hd,
|
|
109
|
+
videoSdUrl: sd,
|
|
110
|
+
previewImageUrl: str(card["video_preview_image_url"]),
|
|
111
|
+
title: text(card["title"]),
|
|
112
|
+
body: text(card["body"]),
|
|
113
|
+
caption: text(card["caption"]),
|
|
114
|
+
ctaText: str(card["cta_text"]),
|
|
115
|
+
linkUrl: unwrapRedirect(str(card["link_url"])),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
function daysBetween(startIso, endIso) {
|
|
121
|
+
const start = Date.parse(startIso);
|
|
122
|
+
const end = endIso ? Date.parse(endIso) : Date.now();
|
|
123
|
+
if (!Number.isFinite(start) || !Number.isFinite(end))
|
|
124
|
+
return undefined;
|
|
125
|
+
return Math.max(0, Math.floor((end - start) / 86_400_000));
|
|
126
|
+
}
|
|
127
|
+
/** Normalise one `collated_results` entry from Meta's Ad Library GraphQL. */
|
|
128
|
+
export function adFromGraphql(node, source = "browser") {
|
|
129
|
+
const snapshot = obj(node["snapshot"]) ?? {};
|
|
130
|
+
const linkUrl = unwrapRedirect(str(snapshot["link_url"]));
|
|
131
|
+
const startedRunning = isoDate(node["start_date"]);
|
|
132
|
+
const stoppedRunning = isoDate(node["end_date"]);
|
|
133
|
+
const libraryId = String(node["ad_archive_id"] ?? node["adArchiveId"] ?? "");
|
|
134
|
+
// Meta gives total_active_time in seconds when it gives it at all; otherwise
|
|
135
|
+
// measure from the start date, and only to the stop date once it has stopped.
|
|
136
|
+
const activeSeconds = num(node["total_active_time"]);
|
|
137
|
+
const daysActive = activeSeconds && activeSeconds > 0
|
|
138
|
+
? Math.floor(activeSeconds / 86_400)
|
|
139
|
+
: startedRunning
|
|
140
|
+
? daysBetween(startedRunning, node["is_active"] === true ? undefined : stoppedRunning)
|
|
141
|
+
: undefined;
|
|
142
|
+
const impressionsWrapper = obj(node["impressions_with_index"]);
|
|
143
|
+
return {
|
|
144
|
+
libraryId,
|
|
145
|
+
adDetailsUrl: libraryId ? AD_DETAILS + libraryId : "",
|
|
146
|
+
pageId: node["page_id"] !== undefined ? String(node["page_id"]) : undefined,
|
|
147
|
+
pageName: str(node["page_name"]) ?? str(snapshot["page_name"]),
|
|
148
|
+
pageUrl: str(snapshot["page_profile_uri"]),
|
|
149
|
+
pageLikes: num(snapshot["page_like_count"]),
|
|
150
|
+
pageCategories: strArray(snapshot["page_categories"]),
|
|
151
|
+
pageProfilePictureUrl: str(snapshot["page_profile_picture_url"]),
|
|
152
|
+
isActive: typeof node["is_active"] === "boolean" ? node["is_active"] : undefined,
|
|
153
|
+
startedRunning,
|
|
154
|
+
stoppedRunning,
|
|
155
|
+
daysActive,
|
|
156
|
+
platforms: strArray(node["publisher_platform"]).map(platformLabel),
|
|
157
|
+
countries: strArray(node["targeted_or_reached_countries"]),
|
|
158
|
+
categories: strArray(node["categories"]),
|
|
159
|
+
displayFormat: str(snapshot["display_format"]),
|
|
160
|
+
title: text(snapshot["title"]),
|
|
161
|
+
body: text(snapshot["body"]),
|
|
162
|
+
caption: text(snapshot["caption"]),
|
|
163
|
+
linkDescription: text(snapshot["link_description"]),
|
|
164
|
+
ctaText: str(snapshot["cta_text"]),
|
|
165
|
+
ctaType: str(snapshot["cta_type"]),
|
|
166
|
+
linkUrl,
|
|
167
|
+
linkDomain: domainOf(linkUrl),
|
|
168
|
+
creatives: creativesFrom(snapshot),
|
|
169
|
+
variantsUsingCreative: num(node["collation_count"]),
|
|
170
|
+
spend: node["spend"] ?? undefined,
|
|
171
|
+
currency: str(node["currency"]),
|
|
172
|
+
reachEstimate: node["reach_estimate"] ?? undefined,
|
|
173
|
+
impressions: impressionsWrapper ? impressionsWrapper["impressions_text"] : undefined,
|
|
174
|
+
source,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Apify flattens the card into its own field names. Where it passes Meta's
|
|
179
|
+
* shape through untouched, reuse the Meta path rather than mapping twice.
|
|
180
|
+
*/
|
|
181
|
+
export function adFromApify(item) {
|
|
182
|
+
if (obj(item["snapshot"]) && item["ad_archive_id"])
|
|
183
|
+
return adFromGraphql(item, "apify");
|
|
184
|
+
const linkUrl = unwrapRedirect(str(item["link_url"]) ?? str(item["linkUrl"]));
|
|
185
|
+
const libraryId = String(item["ad_archive_id"] ?? item["adArchiveId"] ?? item["id"] ?? "");
|
|
186
|
+
return {
|
|
187
|
+
libraryId,
|
|
188
|
+
adDetailsUrl: libraryId ? AD_DETAILS + libraryId : "",
|
|
189
|
+
pageId: item["page_id"] !== undefined || item["pageId"] !== undefined
|
|
190
|
+
? String(item["page_id"] ?? item["pageId"])
|
|
191
|
+
: undefined,
|
|
192
|
+
pageName: str(item["page_name"]) ?? str(item["pageName"]),
|
|
193
|
+
pageUrl: str(item["page_profile_uri"]) ?? str(item["pageUrl"]),
|
|
194
|
+
pageLikes: num(item["page_like_count"]) ?? num(item["pageLikes"]),
|
|
195
|
+
pageCategories: [],
|
|
196
|
+
isActive: typeof item["is_active"] === "boolean"
|
|
197
|
+
? item["is_active"]
|
|
198
|
+
: typeof item["isActive"] === "boolean"
|
|
199
|
+
? item["isActive"]
|
|
200
|
+
: undefined,
|
|
201
|
+
startedRunning: isoDate(item["start_date"] ?? item["startDate"]),
|
|
202
|
+
stoppedRunning: isoDate(item["end_date"] ?? item["endDate"]),
|
|
203
|
+
platforms: strArray(item["publisher_platform"] ?? item["publisherPlatform"]).map(platformLabel),
|
|
204
|
+
countries: [],
|
|
205
|
+
categories: [],
|
|
206
|
+
displayFormat: str(item["display_format"]) ?? str(item["displayFormat"]),
|
|
207
|
+
title: text(item["title"]),
|
|
208
|
+
body: text(item["body"]) ?? text(item["adText"]),
|
|
209
|
+
caption: text(item["caption"]),
|
|
210
|
+
ctaText: str(item["cta_text"]) ?? str(item["ctaText"]),
|
|
211
|
+
ctaType: str(item["cta_type"]) ?? str(item["ctaType"]),
|
|
212
|
+
linkUrl,
|
|
213
|
+
linkDomain: domainOf(linkUrl),
|
|
214
|
+
creatives: [],
|
|
215
|
+
spend: item["spend"] ?? undefined,
|
|
216
|
+
currency: str(item["currency"]),
|
|
217
|
+
reachEstimate: item["reach_estimate"] ?? item["reach"] ?? undefined,
|
|
218
|
+
source: "apify",
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/adlibrary/normalize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one Ad shape every backend returns.
|
|
3
|
+
*
|
|
4
|
+
* Three sources feed this: Meta's own GraphQL payload, ScrapeCreators and Apify.
|
|
5
|
+
* They disagree about field names and nesting. Everything downstream, including
|
|
6
|
+
* every tool, sees only the types here.
|
|
7
|
+
*/
|
|
8
|
+
/** One image or video inside an ad. A carousel has several. */
|
|
9
|
+
export type Creative = {
|
|
10
|
+
kind: "image" | "video";
|
|
11
|
+
imageUrl?: string;
|
|
12
|
+
videoHdUrl?: string;
|
|
13
|
+
videoSdUrl?: string;
|
|
14
|
+
previewImageUrl?: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
body?: string;
|
|
17
|
+
caption?: string;
|
|
18
|
+
ctaText?: string;
|
|
19
|
+
linkUrl?: string;
|
|
20
|
+
};
|
|
21
|
+
export type Ad = {
|
|
22
|
+
libraryId: string;
|
|
23
|
+
adDetailsUrl: string;
|
|
24
|
+
pageId?: string;
|
|
25
|
+
pageName?: string;
|
|
26
|
+
pageUrl?: string;
|
|
27
|
+
pageLikes?: number;
|
|
28
|
+
pageCategories: string[];
|
|
29
|
+
pageProfilePictureUrl?: string;
|
|
30
|
+
isActive?: boolean;
|
|
31
|
+
startedRunning?: string;
|
|
32
|
+
stoppedRunning?: string;
|
|
33
|
+
daysActive?: number;
|
|
34
|
+
platforms: string[];
|
|
35
|
+
countries: string[];
|
|
36
|
+
categories: string[];
|
|
37
|
+
displayFormat?: string;
|
|
38
|
+
title?: string;
|
|
39
|
+
body?: string;
|
|
40
|
+
caption?: string;
|
|
41
|
+
linkDescription?: string;
|
|
42
|
+
ctaText?: string;
|
|
43
|
+
ctaType?: string;
|
|
44
|
+
linkUrl?: string;
|
|
45
|
+
linkDomain?: string;
|
|
46
|
+
creatives: Creative[];
|
|
47
|
+
/** Meta's "N ads use this creative". How many variants share this asset. */
|
|
48
|
+
variantsUsingCreative?: number;
|
|
49
|
+
spend?: unknown;
|
|
50
|
+
currency?: string;
|
|
51
|
+
reachEstimate?: unknown;
|
|
52
|
+
impressions?: unknown;
|
|
53
|
+
source: BackendName;
|
|
54
|
+
};
|
|
55
|
+
export type BackendName = "browser" | "scrapecreators" | "apify";
|
|
56
|
+
export type Advertiser = {
|
|
57
|
+
pageId: string;
|
|
58
|
+
pageName?: string;
|
|
59
|
+
pageUrl?: string;
|
|
60
|
+
pageLikes?: number;
|
|
61
|
+
verified?: boolean;
|
|
62
|
+
category?: string;
|
|
63
|
+
profilePictureUrl?: string;
|
|
64
|
+
adCount?: number;
|
|
65
|
+
};
|
|
66
|
+
export type SearchResult = {
|
|
67
|
+
backend: BackendName;
|
|
68
|
+
count: number;
|
|
69
|
+
hasMore: boolean;
|
|
70
|
+
cursor?: string;
|
|
71
|
+
/** Meta's own count of matching ads for this search, when it tells us. */
|
|
72
|
+
totalAvailable?: number;
|
|
73
|
+
url?: string;
|
|
74
|
+
note?: string;
|
|
75
|
+
ads: Ad[];
|
|
76
|
+
};
|
|
77
|
+
export declare const ACTIVE_STATUS: readonly ["active", "inactive", "all"];
|
|
78
|
+
export declare const MEDIA_TYPE: readonly ["all", "image", "meme", "video", "none"];
|
|
79
|
+
export declare const AD_TYPE: readonly ["all", "political_and_issue_ads", "employment_ads", "housing_ads", "financial_products_and_services_ads"];
|
|
80
|
+
export type ActiveStatus = (typeof ACTIVE_STATUS)[number];
|
|
81
|
+
export type MediaType = (typeof MEDIA_TYPE)[number];
|
|
82
|
+
export type AdType = (typeof AD_TYPE)[number];
|
|
83
|
+
export type SearchParams = {
|
|
84
|
+
query?: string;
|
|
85
|
+
pageId?: string;
|
|
86
|
+
country?: string;
|
|
87
|
+
activeStatus?: ActiveStatus;
|
|
88
|
+
adType?: AdType;
|
|
89
|
+
mediaType?: MediaType;
|
|
90
|
+
limit?: number;
|
|
91
|
+
cursor?: string;
|
|
92
|
+
};
|
|
93
|
+
export interface Backend {
|
|
94
|
+
readonly name: BackendName;
|
|
95
|
+
readonly needsKey: boolean;
|
|
96
|
+
search(params: SearchParams): Promise<SearchResult>;
|
|
97
|
+
listAdvertisers(query: string, country?: string): Promise<Advertiser[]>;
|
|
98
|
+
getAd(libraryId: string, country?: string): Promise<Ad | undefined>;
|
|
99
|
+
transcribe?(libraryId: string): Promise<string | undefined>;
|
|
100
|
+
close(): Promise<void>;
|
|
101
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one Ad shape every backend returns.
|
|
3
|
+
*
|
|
4
|
+
* Three sources feed this: Meta's own GraphQL payload, ScrapeCreators and Apify.
|
|
5
|
+
* They disagree about field names and nesting. Everything downstream, including
|
|
6
|
+
* every tool, sees only the types here.
|
|
7
|
+
*/
|
|
8
|
+
export const ACTIVE_STATUS = ["active", "inactive", "all"];
|
|
9
|
+
export const MEDIA_TYPE = ["all", "image", "meme", "video", "none"];
|
|
10
|
+
export const AD_TYPE = [
|
|
11
|
+
"all",
|
|
12
|
+
"political_and_issue_ads",
|
|
13
|
+
"employment_ads",
|
|
14
|
+
"housing_ads",
|
|
15
|
+
"financial_products_and_services_ads",
|
|
16
|
+
];
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adlibrary/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsFH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAU,CAAC;AACpE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAU,CAAC;AAC7E,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,KAAK;IACL,yBAAyB;IACzB,gBAAgB;IAChB,aAAa;IACb,qCAAqC;CAC7B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public Ad Library URL for a set of filters.
|
|
3
|
+
*
|
|
4
|
+
* Shared, because the browser backend navigates to it and Apify takes the same
|
|
5
|
+
* URL as its actor input. One builder means the two cannot drift.
|
|
6
|
+
*/
|
|
7
|
+
import type { SearchParams } from "./types.js";
|
|
8
|
+
export declare const AD_LIBRARY = "https://www.facebook.com/ads/library/";
|
|
9
|
+
export declare function buildUrl(params: SearchParams): string;
|
|
10
|
+
export declare function adDetailsUrl(libraryId: string): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public Ad Library URL for a set of filters.
|
|
3
|
+
*
|
|
4
|
+
* Shared, because the browser backend navigates to it and Apify takes the same
|
|
5
|
+
* URL as its actor input. One builder means the two cannot drift.
|
|
6
|
+
*/
|
|
7
|
+
export const AD_LIBRARY = "https://www.facebook.com/ads/library/";
|
|
8
|
+
export function buildUrl(params) {
|
|
9
|
+
const search = new URLSearchParams({
|
|
10
|
+
active_status: params.activeStatus ?? "active",
|
|
11
|
+
ad_type: params.adType ?? "all",
|
|
12
|
+
country: params.country ?? "US",
|
|
13
|
+
media_type: params.mediaType ?? "all",
|
|
14
|
+
});
|
|
15
|
+
if (params.pageId) {
|
|
16
|
+
search.set("view_all_page_id", params.pageId);
|
|
17
|
+
search.set("search_type", "page");
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
search.set("search_type", "keyword_unordered");
|
|
21
|
+
}
|
|
22
|
+
if (params.query)
|
|
23
|
+
search.set("q", params.query);
|
|
24
|
+
return `${AD_LIBRARY}?${search.toString()}`;
|
|
25
|
+
}
|
|
26
|
+
export function adDetailsUrl(libraryId) {
|
|
27
|
+
return `${AD_LIBRARY}?id=${encodeURIComponent(libraryId)}`;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url.js","sourceRoot":"","sources":["../../src/adlibrary/url.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,CAAC,MAAM,UAAU,GAAG,uCAAuC,CAAC;AAElE,MAAM,UAAU,QAAQ,CAAC,MAAoB;IAC3C,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,aAAa,EAAE,MAAM,CAAC,YAAY,IAAI,QAAQ;QAC9C,OAAO,EAAE,MAAM,CAAC,MAAM,IAAI,KAAK;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI;QAC/B,UAAU,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK;KACtC,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,MAAM,CAAC,KAAK;QAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAEhD,OAAO,GAAG,UAAU,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,OAAO,GAAG,UAAU,OAAO,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meta's official Ad Library API (`ads_archive`).
|
|
3
|
+
*
|
|
4
|
+
* This is not a backend. It cannot find ordinary commercial ads, so it can never
|
|
5
|
+
* replace the browser or a provider. It does the one thing none of them can:
|
|
6
|
+
* return real spend, impressions, reach and demographic breakdowns, published
|
|
7
|
+
* under transparency law.
|
|
8
|
+
*
|
|
9
|
+
* Coverage, stated plainly because it is the whole catch:
|
|
10
|
+
* - Political and issue ads: worldwide, with spend and impression ranges.
|
|
11
|
+
* - Every ad delivered in the EU: covered by the DSA, with reach attached.
|
|
12
|
+
* - An ordinary commercial ad in the US: not in here at all.
|
|
13
|
+
*
|
|
14
|
+
* So this returning nothing for a US brand is the correct answer, not a failure.
|
|
15
|
+
*
|
|
16
|
+
* The Graph version defaults to v26.0, which was the highest version accepting
|
|
17
|
+
* requests when this was written on 2026-08-31 (v27.0 and above answered
|
|
18
|
+
* "does not exist"). Override with META_GRAPH_VERSION when Meta moves on.
|
|
19
|
+
*/
|
|
20
|
+
export type ArchiveQuery = {
|
|
21
|
+
query?: string;
|
|
22
|
+
pageIds?: string[];
|
|
23
|
+
country?: string;
|
|
24
|
+
limit?: number;
|
|
25
|
+
adType?: string;
|
|
26
|
+
};
|
|
27
|
+
export type ArchiveResult = {
|
|
28
|
+
count: number;
|
|
29
|
+
country: string;
|
|
30
|
+
fieldsReturned: "full" | "core";
|
|
31
|
+
next?: string;
|
|
32
|
+
ads: unknown[];
|
|
33
|
+
note?: string;
|
|
34
|
+
};
|
|
35
|
+
export declare class ArchiveClient {
|
|
36
|
+
private readonly token;
|
|
37
|
+
private readonly version;
|
|
38
|
+
constructor(token: string, options?: {
|
|
39
|
+
version?: string;
|
|
40
|
+
timeoutMs?: number;
|
|
41
|
+
});
|
|
42
|
+
private readonly timeoutMs;
|
|
43
|
+
private request;
|
|
44
|
+
search(query: ArchiveQuery): Promise<ArchiveResult>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meta's official Ad Library API (`ads_archive`).
|
|
3
|
+
*
|
|
4
|
+
* This is not a backend. It cannot find ordinary commercial ads, so it can never
|
|
5
|
+
* replace the browser or a provider. It does the one thing none of them can:
|
|
6
|
+
* return real spend, impressions, reach and demographic breakdowns, published
|
|
7
|
+
* under transparency law.
|
|
8
|
+
*
|
|
9
|
+
* Coverage, stated plainly because it is the whole catch:
|
|
10
|
+
* - Political and issue ads: worldwide, with spend and impression ranges.
|
|
11
|
+
* - Every ad delivered in the EU: covered by the DSA, with reach attached.
|
|
12
|
+
* - An ordinary commercial ad in the US: not in here at all.
|
|
13
|
+
*
|
|
14
|
+
* So this returning nothing for a US brand is the correct answer, not a failure.
|
|
15
|
+
*
|
|
16
|
+
* The Graph version defaults to v26.0, which was the highest version accepting
|
|
17
|
+
* requests when this was written on 2026-08-31 (v27.0 and above answered
|
|
18
|
+
* "does not exist"). Override with META_GRAPH_VERSION when Meta moves on.
|
|
19
|
+
*/
|
|
20
|
+
import { AdLibraryError } from "../errors.js";
|
|
21
|
+
const BASE = "https://graph.facebook.com";
|
|
22
|
+
/**
|
|
23
|
+
* Requested in full first. If the token lacks access to some of these, Meta
|
|
24
|
+
* rejects the whole call rather than omitting the field, so we retry with CORE.
|
|
25
|
+
*/
|
|
26
|
+
const FULL_FIELDS = [
|
|
27
|
+
"id", "page_id", "page_name", "ad_snapshot_url",
|
|
28
|
+
"ad_creation_time", "ad_delivery_start_time", "ad_delivery_stop_time",
|
|
29
|
+
"ad_creative_bodies", "ad_creative_link_titles",
|
|
30
|
+
"ad_creative_link_captions", "ad_creative_link_descriptions",
|
|
31
|
+
"publisher_platforms", "languages", "bylines",
|
|
32
|
+
"currency", "spend", "impressions",
|
|
33
|
+
"demographic_distribution", "delivery_by_region",
|
|
34
|
+
"eu_total_reach", "age_country_gender_reach_breakdown",
|
|
35
|
+
"target_ages", "target_gender", "target_locations",
|
|
36
|
+
"beneficiary_payers",
|
|
37
|
+
];
|
|
38
|
+
const CORE_FIELDS = [
|
|
39
|
+
"id", "page_id", "page_name", "ad_snapshot_url",
|
|
40
|
+
"ad_delivery_start_time", "ad_delivery_stop_time",
|
|
41
|
+
"ad_creative_bodies", "ad_creative_link_titles",
|
|
42
|
+
"publisher_platforms", "currency", "spend", "impressions",
|
|
43
|
+
];
|
|
44
|
+
export class ArchiveClient {
|
|
45
|
+
token;
|
|
46
|
+
version;
|
|
47
|
+
constructor(token, options = {}) {
|
|
48
|
+
this.token = token;
|
|
49
|
+
if (!token) {
|
|
50
|
+
throw new AdLibraryError("Meta's Ad Library API needs a token.", {
|
|
51
|
+
hint: "Create a Meta app, generate a token, and set META_ADS_ARCHIVE_TOKEN. It is free. " +
|
|
52
|
+
"Without it every other tool still works, they just cannot return spend or reach.",
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
this.version = options.version ?? process.env["META_GRAPH_VERSION"] ?? "v26.0";
|
|
56
|
+
this.timeoutMs = options.timeoutMs ?? 60_000;
|
|
57
|
+
}
|
|
58
|
+
timeoutMs;
|
|
59
|
+
async request(params) {
|
|
60
|
+
const url = new URL(`/${this.version}/ads_archive?${params.toString()}`, BASE);
|
|
61
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(this.timeoutMs) });
|
|
62
|
+
let payload;
|
|
63
|
+
try {
|
|
64
|
+
payload = (await response.json());
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw new AdLibraryError("The Ad Library API returned a body that is not JSON.");
|
|
68
|
+
}
|
|
69
|
+
const error = payload["error"];
|
|
70
|
+
if (error && typeof error === "object") {
|
|
71
|
+
const err = error;
|
|
72
|
+
throw new AdLibraryError(`Ad Library API error ${err["code"]}: ${err["message"]}`, {
|
|
73
|
+
hint: "Check META_ADS_ARCHIVE_TOKEN is valid and has not expired.",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return payload;
|
|
77
|
+
}
|
|
78
|
+
async search(query) {
|
|
79
|
+
if (!query.query && !(query.pageIds && query.pageIds.length > 0)) {
|
|
80
|
+
throw new AdLibraryError("Pass either query or page_ids.");
|
|
81
|
+
}
|
|
82
|
+
const country = (query.country ?? "DE").toUpperCase();
|
|
83
|
+
const build = (fields) => {
|
|
84
|
+
const params = new URLSearchParams({
|
|
85
|
+
access_token: this.token,
|
|
86
|
+
ad_reached_countries: JSON.stringify([country]),
|
|
87
|
+
ad_type: query.adType ?? "ALL",
|
|
88
|
+
limit: String(Math.min(Math.max(query.limit ?? 25, 1), 100)),
|
|
89
|
+
fields: fields.join(","),
|
|
90
|
+
});
|
|
91
|
+
if (query.query)
|
|
92
|
+
params.set("search_terms", query.query);
|
|
93
|
+
if (query.pageIds?.length)
|
|
94
|
+
params.set("search_page_ids", JSON.stringify(query.pageIds));
|
|
95
|
+
return params;
|
|
96
|
+
};
|
|
97
|
+
let payload;
|
|
98
|
+
let fieldsReturned = "full";
|
|
99
|
+
try {
|
|
100
|
+
payload = await this.request(build(FULL_FIELDS));
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Most often a permissions problem on the EU-only fields. Retry with the
|
|
104
|
+
// set every token can read rather than failing the whole call.
|
|
105
|
+
payload = await this.request(build(CORE_FIELDS));
|
|
106
|
+
fieldsReturned = "core";
|
|
107
|
+
}
|
|
108
|
+
const ads = Array.isArray(payload["data"]) ? payload["data"] : [];
|
|
109
|
+
const paging = payload["paging"];
|
|
110
|
+
return {
|
|
111
|
+
count: ads.length,
|
|
112
|
+
country,
|
|
113
|
+
fieldsReturned,
|
|
114
|
+
next: typeof paging?.["next"] === "string" ? paging["next"] : undefined,
|
|
115
|
+
ads,
|
|
116
|
+
note: ads.length === 0
|
|
117
|
+
? "Empty is a valid answer. This API covers political and issue ads worldwide, plus " +
|
|
118
|
+
"every ad delivered in the EU. Ordinary commercial ads outside the EU are not in " +
|
|
119
|
+
"it at all. Use search_ads for those."
|
|
120
|
+
: undefined,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/archive/client.ts"],"names":[],"mappings":"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"}
|