Ad Library Angle Log is a small Python script for e-commerce marketers. Give it one or more store names and it pulls matching public records from the Facebook Ad Library, then writes an angle log per store: which hooks, offers and themes the store is running, and how long each ad has been live.
The problem
The Facebook Ad Library is public, but reading it by hand is slow. Each version of a creative shows up as its own ad, offers are buried in the copy, and there is no easy way to see what changed since last week. Marketers who watch a few competitors need a short, repeatable summary instead of scrolling.
What the app does
- Takes one or more store or brand names.
- Pulls matching Ad Library records: ad copy, start date, advertiser page and media.
- Separates ads from the store itself from ads by other advertisers that mention it.
- Groups identical copies and tags angles such as offer, new arrival, motivation, comfort, community, seasonal and social proof.
- Pulls offers from the copy, such as percent off, codes and free shipping.
- Saves a snapshot and writes a diff against an earlier run: new ads, ads that stopped, ads unchanged.
How it works
- Probe. A
count: 1call toPOST /desearch/facebook/searchchecks the keyword matches anything, so an empty keyword costs nothing more. - Search. A second call with
count: 30returns up to 30 ad records with copy, start time and advertiser. - Normalize and group. Start dates become "days since start". Ads with identical copy are grouped as versions of one creative.
- Tag angles. Keyword rules (English plus several European languages) tag each copy with angles and offers.
- Optional landing pages. When an ad names a URL,
GET /web/extractreads that page as text. - Write the angle log, the snapshot and, if asked, the diff.
The code
import os, requests
API = "https://api.desearch.ai"
headers = {"Authorization": os.environ["DESEARCH_API_KEY"]}
r = requests.post(f"{API}/desearch/facebook/search",
headers={**headers, "Content-Type": "application/json"},
json={"query": "Gymshark", "count": 30}, timeout=60)
ads = r.json()
for ad in ads[:5]:
print(ad["createTime"], ad["author"]["name"], ad["text"][:80])
print(len(ads), "ads, cost $", r.headers.get("X-Desearch-Cost-Usd"))
The folder has one script, adlog.py (commands run, diff and render), an offline test for the diff logic in test_diff.py, and a full sample in sample-output.md.
Example output
From a live run on 2026-10-05 for one sportswear store, count: 30:
| Measure | Value |
|---|---|
| Ads returned | 30 (24 from the store, 6 from other advertisers) |
| Distinct ad copies from the store | 10 |
| Ads tagged "offer / discount" | 17 (4 distinct copies) |
| Ads tagged "motivation / identity" | 16 (3 distinct copies) |
| Ads tagged "new arrival / launch" | 10 (3 distinct copies) |
A second run 20 minutes later showed 0 new and 0 stopped ads, which is what the diff is for: run it daily or weekly and only read the changes.
Run it yourself
git clone https://github.com/Desearch-ai/desearch-py-examples && cd desearch-py-examples/ad-library-angle-log
pip install -r requirements.txt
export DESEARCH_API_KEY=... # from console.desearch.ai
python adlog.py run --store Gymshark --store Allbirds
python adlog.py run --store Gymshark --diff-against latest # later run, with a diff
Useful flags: --count (ads per store, up to 30 per request), --extract N (read up to N landing pages named in ads), --diff-against latest (compare with the newest earlier snapshot).
What it costs
Each ad returned cost $0.00207 on 2026-10-05, read from the X-Desearch-Cost-Usd header. One store with the defaults came to $0.064 and two stores to $0.128. A keyword with no ads costs $0. See pricing.
Ideas to extend it
- Run it weekly with cron and send only the diff to your team chat.
- Track a whole category (5 to 10 stores) and compare which angles each one leans on.
- Add an LLM step that rewrites the top angles as briefs for your own creative team.