ChatbotX
Open-source ManyChat alternative, built for AI. Omnichannel marketing across WhatsApp, TikTok, Facebook, Instagram, Telegram, Zalo, Email, API, and Webchat 🤖
One REST API and MCP server for the ad libraries of Meta, Google, YouTube, Google Play, TikTok, LinkedIn, Pinterest, X, Snapchat, the Apple App Store, Amazon and Microsoft Bing. Resolve a domain to it
MarketingTypeScript · JavaScriptGitHub @AdLibAPIOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
n8n community node for the AdLib API (ad libraries of Meta, Google, TikTok, LinkedIn, Pinterest, X)
Taken from the repository README
Loading the full README.
Read the full README ↗An n8n community node for the AdLib API: one API for the public ad libraries of Meta (Facebook, Instagram), Google (incl. YouTube and Google Play), TikTok, LinkedIn, Pinterest, X, Snapchat, Apple, Amazon and Microsoft (Microsoft in beta), with its own ad history. Ads that disappear from a platform's library are still there, with their run time, marked with removed_from_library_at.
Get an API key at adlibapi.com; the free plan includes 5,000 credits a month.
With this package you can:
Not affiliated with Meta, Google, TikTok, LinkedIn, Pinterest, X, Snapchat, Apple, Amazon or Microsoft.
In n8n:
n8n-nodes-adlib and confirm.The AdLib and AdLib Trigger nodes then show up in the nodes panel. See the n8n guide on installing community nodes for manual installation with npm (queue mode, Docker).
Create an AdLib API credential:
X-API-Key header./v1. Default https://api.adlibapi.com; change it if your account uses a different host.When you save the credential, n8n tests it with GET /v1/usage?days=1.
| Resource | Operation | Endpoint |
|---|---|---|
| Advertiser | Resolve by Domain | GET /v1/advertisers/resolve?domain= |
| Advertiser | Get | GET /v1/advertisers/{id} |
| Advertiser | Get Ads (Return All) | GET /v1/advertisers/{id}/ads |
| Advertiser | Get Changes (Return All) | GET /v1/advertisers/{id}/changes?since= |
| Advertiser | Get Stats | GET /v1/advertisers/{id}/stats |
| Advertiser | Get Timeline (Return All) | GET /v1/advertisers/{id}/timeline |
| Advertiser | Report Resolve Match | POST /v1/advertisers/resolve/reports |
| Advertiser | List Resolve Reports | GET /v1/advertisers/resolve/reports |
| Ad | Search (Return All) | GET /v1/search |
| Ad | Get | GET /v1/ads/{id} |
| Ad | Get History | GET /v1/ads/{id}/history |
| Ad | Get Ad Features | GET /v1/ads/{id}/features |
| Ad | Parse Library URL | GET /v1/library-url?url= |
| Domain | Check if Advertising | GET /v1/domains/{domain}/check |
| Domain | Get Company Profile | GET /v1/companies/{domain} |
| Domain | Suggest Domains | GET /v1/domains/suggest?q= |
| Watchlist | Create | POST /v1/watchlists |
| Watchlist | Get | GET /v1/watchlists/{id} |
| Watchlist | List | GET /v1/watchlists |
| Watchlist | Add Advertisers | POST /v1/watchlists/{id}/advertisers |
| Watchlist | Remove Advertiser |
Notes:
<platform>:<id>, for example meta:15087023444 (advertiser) or meta:1234567890 (ad). Advertiser > Resolve by Domain gives you advertiser IDs; each candidate has a confidence score (0 to 1) and a match_reason. Use Options > Minimum Score to drop weak matches and Split Into Items to get one item per advertiser.nike.com or as a full URL; only the host is sent.meta.errors with Raw Pages and are not billed. Source: History searches the archive, including ads that are gone from the platforms; Sort: Days Running puts the longest-running ads (likely winners) first. Political Ads: Only or Exclude filters political and issue ads (only Meta labels them, so Only limits results to Meta). With Source: History, Removed Ads: Only returns ads the platforms' libraries no longer show (taken down, deleted or aged out) that AdLib kept, and Exclude leaves them out.google:. The other Platforms fields (resolve, domain check, company profile, batch, trigger) take the 10 libraries. In search, Options > Placement (Google Search, Shopping, Maps, Play or YouTube) limits a search to where Google ads ran. YouTube with Format: Video gives YouTube video ads.derived.signals (why it likely performs, from public facts: long_running, still_running_90d, scaled, wide_reach, multi_country) and derived.stage (testing, scaling or proven). List results carry meta.platform_totals with Raw Pages: the matching ads per platform, where the platform reports it.The trigger starts the workflow when watched advertisers start, stop, change or remove ads.
On activation it creates an AdLib watchlist whose webhook_url is this node's webhook URL, and stores its ID. On deactivation it deletes the watchlist. Every delivery is checked against the X-AdLib-Signature header (t=<unix>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">) with your webhook secret from GET /v1/webhooks/secret; deliveries with a wrong signature or a timestamp more than 5 minutes off are answered with 401 and do not start the workflow. If you rotate the secret, the trigger fetches the new one on the next delivery.
Each advertiser.changes event is one item:
{
"event": "advertiser.changes",
"watchlist_id": "…",
"advertiser_id": "meta:15087023444",
"crawled_at": "2026-10-26T06:00:00Z",
"summary": { "new": 2, "started": 0, "stopped": 1, "changed": 0, "removed": 0 },
"new": [{ "type": "discovered", "at": "…", "ad_id": "meta:…", "ad": { } }],
"started": [],
"stopped": [{ "type": "stopped", "at": "…", "ad_id": "meta:…", "ad": { } }],
"changed": [],
"removed": []
}
With Options > Split Into Ads, you get one item per ad instead, with change set to new, started, stopped, changed or removed, plus watchlist_id, advertiser_id and crawled_at.
Good to know:
POST /v1/webhooks/test and the test URL: pings start manual test runs only and are ignored in production.Single objects (an advertiser, an ad, a domain check, a watchlist) come out as one item: the API's data object, with meta kept as _meta where the API sends it.
List operations output one item per result (ad, event, watchlist). They have:
next_cursor page by page until the last page or Max Pages (default 10). Page Size sets the results per call.next_cursor you saved.next_cursor and meta, instead of one item per result.Batch > Get outputs one item: the job (status, counts, credits billed) with all fetched items.
The API can also answer in CSV (output=csv). The node does not use that: n8n passes JSON items between nodes, and Return All needs the JSON next_cursor. To get a CSV file, add n8n's Convert to File node after the AdLib node; Domain > Check if Advertising already has a flat columns object for spreadsheets.
The AdLib API bills credits per delivered result, not per call, and reports them in the X-Billing-Credits header. The free plan includes 5,000 credits a month.
| Platform | Credits per delivered ad |
|---|---|
| Meta, TikTok, Pinterest, X, Snapchat, Apple (App Store), Amazon, Microsoft | 1 |
| Google, YouTube, Google Play | 2 |
| 3 |
Return All can deliver many results, so keep Max Pages at a sensible value. Usage > Get shows what you used per day and endpoint.
The API answers errors as {"error": {"code", "message", "request_id", …}}. The node shows that message with a hint, for example:
401: wrong API key or Base URL.402: no credits left.403: the key may not use this endpoint, or history_limit: the ad is older than your plan's archive window (free 90 days, starter 365 days, growth and up unlimited).404: unknown advertiser, ad, watchlist or job ID.429: rate limit. Wait, or turn on Retry On Fail in the node settings.Enable Continue On Fail (or On Error: Continue) if a single bad domain should not stop the workflow.
The AdLib node is marked usableAsTool, so it can be attached to an AI Agent node as a tool, for example to let an agent look up a company's ads or check whether a lead is advertising. On self-hosted n8n, community nodes can only be used as tools when the environment variable N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true is set.
Import any of these via Workflows > Import from File, then pick your own credentials in each node.
templates/competitor-ads-to-slack.json
AdLib Trigger (Watch By: Domain competitor.com, Split Into Ads) → Filter (change is new or started) → Slack (post advertiser, platform, headline and library link to #competitor-ads). Activate the workflow; from the second crawl on, every new ad of the competitor is posted.
templates/domain-enrichment-google-sheets.json
Google Sheets (read rows with a domain column) → AdLib (Domain > Check if Advertising, {{ $json.domain }}) → Edit Fields (advertising yes/no/unknown, platforms with ads, active ad count, checked at) → Google Sheets (append or update, matched on domain). advertising is unknown when no platform could be checked; such checks are free.
npm install
npm run dev # starts n8n with these nodes loaded, rebuilds on change (http://localhost:5678)
npm run lint
npm test # builds, then runs the unit tests in test/
The operations and their fields live in nodes/AdLib/descriptions.ts, the requests in nodes/AdLib/AdLib.node.ts. Signature checking is in nodes/AdLibTrigger/signature.ts. No runtime dependencies.
DELETE /v1/watchlists/{id}/advertisers/{advertiser_id} |
| Watchlist | Update | PATCH /v1/watchlists/{id} |
| Watchlist | Delete | DELETE /v1/watchlists/{id} |
| Batch | Create | POST /v1/batch |
| Batch | Get (Return All) | GET /v1/batch/{job_id} |
| Webhook | List Deliveries (Return All) | GET /v1/webhooks/deliveries |
| Webhook | Get Delivery | GET /v1/webhooks/deliveries/{id} |
| Webhook | Redeliver | POST /v1/webhooks/deliveries/{id}/redeliver |
| Webhook | Send Test | POST /v1/webhooks/test |
| Webhook | Get Secret | GET /v1/webhooks/secret |
| Webhook | Rotate Secret | POST /v1/webhooks/secret/rotate |
| Platform | List | GET /v1/platforms |
| Platform | Get Status | GET /v1/status |
| Usage | Get | GET /v1/usage |
text.hook, offers, urgency, social_proof, guarantee and other tags (each with the exact text it matched), the measured format, media aspect, duration and scene cuts, and on-image text read with OCR. Costs 2 credits by default, plus the ad if it has to be fetched live.kind (ad or advertiser), id and href, the AdLib call that fetches it. Free.columns, a flat object (advertising, platforms_advertising, total_active_ads, latest_ad_at, and <platform>_advertising, <platform>_active_ads, <platform>_advertiser_id) that maps straight onto spreadsheet columns.accounts, with score at least Minimum Score, default 0.75), per-platform totals and combined stats. Agencies, resellers and partners running ads for the domain are listed under related (each account has a role) and left out of the totals unless Include Related Accounts is on. Accounts below the threshold are listed as candidates. It costs one resolve plus one stats call.advertiser_count, interval_hours and email_alerts; the advertisers and their crawl status are in Watchlist > Get. Options > Email Alerts on Create (or Update) mails a digest of each crawl's changes to your account's email. Watchlist > Update changes the name, webhook URL (an empty Webhook URL field removes the webhook) or email alerts.advertiser.changes events; Slack and Discord incoming webhook URLs get a readable message instead.removed events: the platform's library no longer shows the ad (AdLib keeps it).batch.completed event when it is done. Results are kept 30 days.webhook.ping to a URL. Get Secret returns the signing secret (it is stored in the execution data, so prefer the AdLib Trigger, which verifies signatures for you); Rotate Secret replaces it at once, and the AdLib Trigger picks up the new secret on its next delivery.