Case study

Competitor ad research with an LLM:
what meal-kit brands are running

A real run: 150 Meta ads and 100 Google ads from the US meal-kit market, sorted by an LLM into angles, offers and formats, for $0.78. Mistakes included.

Prepaid, no subscriptionREST or MCPOne key for models, data and agents
Meta Ad LibraryGoogle Adslovelyjsonfindings"unique_creatives": 105"meal_kit_creatives": 20"lead_with_price": "12 of 20""google_text_ads": "85 of 100""median_days_running": 155"cost": "$0.78"

Before a new brand spends its first dollar on ads, it wants to know what the incumbents say, what they offer and how long they keep an ad running. Both big ad libraries are public, so the answer is out there; the work is reading hundreds of ads. We pointed our ad library tools at the US meal-kit market and let a model do the reading. Everything below is from that run on 26 October 2026: $0.78 in total, about ten minutes of run time, and three things we had to correct along the way.

01

The question

?

A new meal-kit or prepared-meal brand is planning its first US campaigns. Who is it competing with for attention, what do their ads promise, and how long do they run them?

02

The data we collected

SourceToolWhat we asked forResultsCost
Meta Ad LibraryFacebook Ad LibraryActive US ads for the keyword "meal kit"150 ads$0.169
Google Ads Transparency CenterGoogle Ads Transparency20 ads each from five big meal-kit sites100 ads$0.240

The Meta ads come with their copy, headline, call to action and format. The Google ads come with their format and how many days each has been served, but not their text. The two sources answer different questions, which is why we used both.

03

How the model was used

claude-sonnet-5.5 read all 150 Meta ads in one call. For each it named the advertiser type (meal kit, grocery, diet shake, kitchen product, creator…), up to two angles (price, convenience, health, freshness, family…), the offer (percent off, free shipping, first-box deal, none…) and one short quote copied from the ad. Code checked every quote against the ad text (all 150 matched) and did all the counting. A last call turned the counts into a brief.

04

What we found

{}

Most ads for "meal kit" aren't from meal kits. Of 105 unique creatives (more on that number below), only 20 came from meal-kit or prepared-meal sellers, run by 13 advertisers. The rest: 15 diet shakes and supplements, 15 kitchen products, 12 creators and media, and 40 others, from pet food to deal sites. A new brand bidding on this keyword competes with all of them for the same feed.

Meal kits lead with price. 12 of the 20 meal-kit creatives lead with a price or discount, 6 with fresh ingredients, 5 with a health goal and only 4 with saving time. 14 of 20 carry an offer: percent off (6), free shipping (4), a first-box deal (2) or dollars off (2). Diet shakes do the opposite: 10 of 15 lead with a health goal and 9 of 15 have no offer at all.

Video wins on Meta, text on Google. 50 of the 105 Meta creatives are video, 21 dynamic creative, 19 single images. "Shop now" is the call to action on 54. On Google, 85 of the 100 ads are text search ads.

On Google, winners run for months. All 100 Google ads were still running. Their median age was 155 days, 69 had run for more than 90 days, and the oldest text ad had been running since February 2023, 1,356 days. The two brands whose oldest ad dates from August 2025 had medians of 84 and 91 days; the three with ads from 2023 had 135, 182 and 198.

05

Three things we had to correct

Duplicates

The library returned 150 ads, but 45 repeated another ad's copy from the same advertiser: one grocer's "Get Oven-Ready meals delivered with EVERYTHING included" appeared 8 times. Counted as is, that single advertiser made price look like 18 of 28 meal-kit ads instead of 12 of 20. We counted unique creatives (same advertiser, same copy, once) and redid every number.

Neighbours in the keyword

"Get 50% OFF Your First Box" sounds like a meal kit, and one meal kit did run it, but so did two dog-food brands. Keyword searches pull in neighbours; tag the advertiser type before you count anything.

A brief that drifted

The model's second brief was weaker than its first: it suggested test budgets and a "CTR drops 30%" rule that appear nowhere in the data, and it quoted "up to 52% off while supplies last" as meal-kit copy when it came from a deal site. We kept its evidence-backed moves below and dropped the rest. Asking the model to cite a number for every claim catches most of this, not all of it, so a person still reads the brief.

06

The moves the data supports

Stand out on time, not price. 12 of 20 meal-kit creatives lead with price and only 4 with saving time. Test: the same offer with a price headline against a time headline ("Dinner in 30 minutes, no planning needed" is the one real example), and compare cost per first order.

Try a first-box deal. Only 2 of 20 meal-kit creatives use one; percent off and free shipping are the crowded offers. Test: one creative, two offers.

Plan for long-lived search ads. 69 of 100 Google ads have run for more than 90 days. Write a few search ads you'd be happy to keep for months rather than a new set every week.

What the data can't say: spend, impressions, clicks or sales. A long-running ad is probably working, but the libraries don't prove it.

07

Run it yourself

With an API key in LOVELY_API_KEY, the same run_tool and ask helpers as in the market research case study:

Python
meta = run_tool("facebook-ads", {"urls": [{"url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&q=meal%20kit&search_type=keyword_unordered"}], "count": 150}, 150)
google = run_tool("google-ads-transparency", {"startUrls": [{"url": f"https://adstransparency.google.com/?region=US&domain={d}"} for d in ["example-brand.com", "another-brand.com"]], "resultsLimit": 20}, 40)

ads = [{"id": i, "page": a["page_name"], "title": a["snapshot"].get("title"), "body": (a["snapshot"].get("body") or {}).get("text"), "cta": a["snapshot"].get("cta_text")} for i, a in enumerate(meta)]
# Count each (advertiser, copy) once before tagging, then:
tags = ask("Tag each ad: advertiser_type, 1-2 angles, offer, and a quote copied exactly. Return a JSON array.", ads)

Swap the keyword and the domains for your own category. To have an agent run the whole thing and come back with the brief, connect it to the MCP server.

08

Frequently asked questions

?
How much does competitor ad research with AI cost?+

This run cost $0.78: $0.41 for 250 ads from the two libraries and $0.37 for the model calls, including the second brief. Ad tools bill per ad returned; see each tool's page for its price.

Can I see a competitor's ads for a specific brand?+

Yes. Send a brand's Facebook Page or Ad Library search URL to the Facebook Ad Library tool, or its website domain to Google Ads Transparency. LinkedIn's library works the same way with the LinkedIn Ad Library tool.

Does this show how well an ad performs?+

No. The libraries show what runs, where and for how long, not spend or results. How long an ad has run is the best public signal, and it is still only a signal.

Can I track competitors every week?+

Yes. Run the same calls on a schedule, keep the ad ids, and have the model describe only what is new since last week. The ad intelligence use case covers the tools for it.

One prepaid key for models, data and agents

No subscription. Top up, use what you need, see every charge in your logs.