Marketing

Extracting the Ad's Promises: A Prompt and a Fallback Ladder

Antonio Evans8 min read

A clean desk viewed from above: a printed ad torn into four labeled strips (offer, proof, audience, urgency) laid out next to a notebook page showing a JSON object with the same four keys.
Key points

Key points

  1. 1Extraction turns each ad's text into a fixed JSON record (offer, proof, audience, urgency) before any matching, clustering or scoring runs.
  2. 2The prompt should look at one ad at a time and return strict JSON only, because extraction is a deterministic task and should not be mixed with judgment calls.
  3. 3Every extracted field needs a validation rule, and "unknown" must be an allowed value so the model has a legal way to say nothing was promised.
  4. 4When an ad makes no explicit promise, walk a fallback ladder instead of forcing a value: implicit offer detection first, then a partial record, then a null record that routes the ad to a different pipeline.

Why extraction happens before comparison

A comparison step has one job: decide whether two records agree. It cannot do that job if it is also guessing what the records mean. When you paste a batch of ad headlines into a model and ask it to summarize the selling points, you get aggregate adjectives that are true and useless, because the model skipped ad-by-ad extraction and summarized a wall of text on impression ad copy clustering at scale. The result cannot be traced to individual ads, cannot be counted, and shifts when you rerun it.

Splitting the work fixes this. Step one extracts fields from each ad on its own into a fixed schema. Step two operates on those structured records, which is a counting and grouping task rather than a semantic one ad copy clustering at scale.

The same logic already governs the page side of the handoff. Message-match audits ask the team to record product, problem, promise, proof, offer and action for the ad and again for the landing page, then compare the two lists message match checklist. The extraction record is that list, made machine-readable and reproducible.

There is a content lesson here too. Web users scan rather than read, which eye-tracking research has shown consistently since the late 1990s, when 79 percent of test users were observed scanning any new page and only 16 percent read word by word how users read on the web. Those findings held across five studies spanning 13 years and over 500 participants how people read online. Ad copy inherits the same compression: the promise is carried in a headline and a short description, so the extraction schema has to be tolerant of very small text.

A schema with four required keys and typed optional fields

Use a schema that is small enough that the model cannot get lost and specific enough that every field can be checked in code. The four core keys map to the questions a comparison will later ask.

KeyWhat it capturesRequiredAllowed shapeValidation rule
offerThe thing the ad says you getYesObject with type, value, conditionstype from a fixed enum; value a string; empty conditions allowed
proofThe evidence the ad leans onYesEnum: testimonial, data/numbers, authority, before/after, demo, none, unknownMust be one of the enum values
audienceWho the ad is talking toYesShort lowercase phraseTen words or fewer, no brand names
urgencyAny pressure to act nowYesEnum: time limit, scarcity, price-rise warning, fear of missing out, none, unknownMust be one of the enum values
offer.termsPrice, discount, shipping, expiryNoStringOnly fill if literally present
notesFree text for ambiguityNoStringNever used by the comparison step
record_statusHow the record was producedYesEnum: explicit, implicit, partial, nullControls which pipeline runs next

Three design decisions matter more than the field list.

First, the enums come from the ad-analysis pattern that extracts the core promise, evidence type, urgency device and implied audience, and instructs the model to pick unknown when unsure rather than invent a value ad copy clustering at scale. Give the model an exit.

Second, keep descriptions inside the schema explicit. Research on schema-driven extraction found that JSON schemas written as human contracts, with ambiguous descriptions and incomplete validation rules, produce frequent hallucinations and schema non-adherence, and that optimizing the schema itself improved extraction accuracy substantially on a web extraction benchmark PARSE schema optimization. You do not need the full framework to take the lesson: write field descriptions the model can act on.

Third, the offer object should echo a real vocabulary where one exists. Schema.org's Offer type carries properties for availability, validity dates and price terms schema.org Offer, and borrowing those names costs nothing and makes later export easier.

The extraction prompt

Extraction and classification are different kinds of task, and one prompt that tries both will quietly merge them ad copy clustering at scale. This prompt does extraction only, on one ad at a time.

You extract advertising promises. You will receive one ad's text.

<ad>
{{ad_text}}
</ad>

Return JSON only. No prose, no markdown fences, no explanation.

Fill exactly these fields:

- offer: the concrete thing the reader is promised. Use null if the ad
  names no tangible thing, benefit, price or action.
  Include:
    type: one of [discount, free_trial, free_resource, price_cut,
          bundle, service_booking, content_access, none, unknown]
    value: the promised thing in the ad's own words, short
    conditions: list of stated limits, or []
- proof: the evidence the ad itself supplies. One of [testimonial,
  data/numbers, authority, before/after, demo, none, unknown].
- audience: a short lowercase phrase for who the ad addresses, ten
  words or fewer. Empty string if no audience is discernible.
- urgency: any pressure to act now. One of [time limit, scarcity,
  price-rise warning, fear of missing out, none, unknown].

Rules:
1. Use only what the ad text states. Do not add outside knowledge.
2. If a field is not present in the text, choose none or unknown.
   Never guess a plausible value.
3. If the ad makes a claim indirectly rather than literally,
   still record the field, and set record_status to "implicit".
4. Set record_status to "explicit" when at least offer and one other
   field are literally stated, "implicit" when the promise is only
   implied, "partial" when only one field is present, and "null" when
   the text contains no promise at all.

Output shape:
{"offer":{"type":"...","value":"...","conditions":[]},
 "proof":"...","audience":"...","urgency":"...",
 "record_status":"..."}

Two habits keep the prompt honest. Instruct the model to quote the ad's own words for offer.value rather than paraphrasing into marketing language; Nielsen's research found users detested marketese, the boastful promotional register that marks exaggeration how users read on the web, and a model asked to paraphrase will slide into it. And log the raw text next to the record, so any disagreement downstream can be traced to a specific sentence.

For a worked example, take an ad that says: "Tax season is coming. Get your books clean before the deadline with a free 30 minute review, rated 4.8 by 900 clients." The record would read:

{"offer":{"type":"service_booking",
          "value":"free 30 minute review",
          "conditions":["before the deadline"]},
 "proof":"data/numbers",
 "audience":"small business owners preparing taxes",
 "urgency":"time limit",
 "record_status":"explicit"}

The conditions list matters because the message-match research treats offer terms (price, discount, shipping, expiration) as a match point in their own right message match checklist. A deadline buried in the ad but dropped from the landing page is exactly the drift the comparison should catch.

Validating the JSON before anything else runs

Do not send a record to the comparison step because it parsed as JSON. Send it because it passed checks.

1. Parse. If the model wrapped output in prose or fences, reject and retry.
2. Enum check. proof and urgency must be in their allowed sets.
3. Null check. offer may be null, but only when record_status is
   "null" or "partial".
4. Length check. audience is ten words or fewer.
5. Grounding check. offer.value should appear, approximately, in the
   ad text. Flag records where it does not.
6. Status check. record_status must be present on every record.

Tie the checks to what you can measure. In a study of web usage, users had time to read at most 28 percent of the words on an average page, with 20 percent more likely how little do users read, so a schema that assumes the reader, or the model, absorbed every sentence will over-extract. The grounded-value check is the cheapest defense against that.

Validation tooling you already trust can be reused. Google recommends validating structured data with its Rich Results Test and generic schema validation with the Schema Markup Validator structured data tools. Those tools test schema.org markup rather than your own JSON contract, but the habit (validate the contract before you depend on the data) transfers directly. The same pattern appears in local-marketing practice, where each location page gets its own validated JSON-LD block with a unique identifier to avoid conflicting duplicates location page schema. Your rule is the mirror image: one record per ad per run, with the ad ID stored alongside.

The fallback ladder for ads that promise nothing

Some ads genuinely make no offer. A brand film, a recruiting spot, a public-service message. Forcing the model to manufacture an offer is how you get plausible fabrications. Walk down the ladder instead, and stop at the first rung that produces defensible output.

RungTriggerWhat the pipeline doesStatus set
1. Explicit parseOffer and at least one other field stated literallyCompare on all fieldsexplicit
2. Implicit offer detectionNo literal offer, but a discount, deadline, testimonial, guarantee or hard call to action appearsRecord the cue, mark the offer type as inferred, route to comparison with a flagimplicit
3. Partial recordOnly one field is present (for example, audience only)Compare on the field that exists; block offer-based scoringpartial
4. Null recordNo promise, no cue, no audienceDo not compare; route to the brand or awareness pipelinenull

The legal reason for rung 2 existing at all is that regulators treat implied claims as claims. The FTC reads an ad in context, looks at both express and implied claims, and requires advertisers to have a reasonable basis before an ad runs, including for claims a consumer would reasonably infer FTC advertising guide. An ad that says "kills the germs that cause colds" carries an implied prevention claim FTC advertising guide. So implicit-offer detection is not over-reading; it is recording what the ad actually conveys.

Rung 4 is not a failure state. Ads with no promise usually belong to a different question: brand consistency, creative quality, or reach. Sending them into a promise comparison produces noise that will look like a match failure. Route them out by status, and keep the count as a metric in its own right. If a large share of a campaign's ads land at rung 4, that is a finding about the campaign, not a bug in the extractor.

The message-match literature offers a useful calibration. B2B landing pages commonly see bounce rates between 40 and 60 percent, and a consistent rate above 70 percent suggests a match problem rather than a product problem message match framework. A high null-record share in a paid-search campaign is the same kind of signal: the creative is not carrying a promise the landing page can continue.

What the comparison gains from typed fields

Once records are typed, comparison becomes arithmetic rather than opinion. You can compute how often the ad's offer type appears on the landing page, how often the proof type survives the click, and how often urgency in the ad is absent from the page. The 2024 benchmark that measured landing-page behavior across more than 464 million visitors and 41,000 pages is the kind of aggregate a typed dataset lets you build over your own traffic paid search promise audit.

A worked example shows the payoff. Suppose you extract 500 ads and find that 120 carry urgency: "time limit" and offer.type: "discount". You then extract the same fields from the landing pages those ads point at. If only 74 of the 120 destinations state a deadline, you have 46 ads whose promise breaks at the click, and you can list them by ad ID with the exact sentence from each ad. That is a reviewable artifact. A summary saying "the ads emphasize urgency" is not.

The same discipline protects against a subtle trap. A page can be attractive, fast and technically correct while still creating message drift message match checklist. Typed fields make drift visible as a field-level disagreement rather than a vague sense that the page feels off.

If you are running this across several model providers or large ad libraries, a single endpoint simplifies the plumbing: Quanta Inference (https://quantaintelligence.ai/inference) puts text, image, video, audio and embedding models behind one OpenAI-compatible API key, priced in US dollars, so the extraction prompt does not change when the model behind it does.

A short operating checklist

Run this before the comparison step goes live, and again whenever you change the prompt.

  • Schema versioned and stored next to the prompt, with descriptions detailed enough that the model cannot misread a field PARSE schema optimization.
  • Enums frozen, with unknown and none available on every enum field ad copy clustering at scale.
  • One ad per call, JSON only, no prose.
  • Validation script that rejects unparseable output, off-enum values, missing record_status, and ungrounded offer.value.
  • Fallback ladder documented, with the routing rule for null records agreed before launch.
  • Raw ad text retained next to each record for traceability.
  • A sample of 30 records read by a human each time the prompt changes, scored against the ad text.
FAQ

FAQ

Why not ask the model to extract and compare in one prompt?

Because the two steps are different kinds of task. Extraction is deterministic and has essentially one right answer per ad, while comparison is a judgment call about boundaries ad copy clustering at scale. Combining them removes the intermediate artifact, so you cannot trace a mismatch back to a specific ad or sentence, and rerunning produces different conclusions.

What should the model output when an ad has no offer?

It should set record_status to partial or null and leave offer empty rather than inventing a value. The prompt gives it unknown and none precisely so it has a legal way to report absence ad copy clustering at scale. The pipeline then routes the record down the fallback ladder instead of comparing a fabricated offer.

Is implicit-offer detection just guessing?

No, it is recording what the ad conveys. Regulators treat implied claims as claims that must be substantiated, and read ads in context rather than word by word FTC advertising guide. The distinction is that rung 2 records the specific cue (a deadline, a testimonial, a guarantee) next to the inferred offer type, so a reviewer can check the inference against the text.

How many fields should the schema have?

Four required keys plus a small set of optional ones is usually enough for promise comparison. The risk of a larger schema is that it becomes a human contract with ambiguous descriptions, which research links to hallucination and schema non-adherence PARSE schema optimization. Add a field only when a specific comparison needs it and you can write a validation rule for it.

How do I know the extractor is working?

Spot-check a fixed sample of records against the ad text every time the prompt or schema changes, and watch the share of records landing at each ladder rung. A rising null share usually means the creative changed, not the extractor, while a rising share of ungrounded offer.value strings usually means the prompt needs tightening. If the site-side work is also on your plate, describing the pages and the extraction review you need to Quanta (https://quantaintelligence.ai/) hands it to a specialist who builds it with you.

Sources

Sources

  1. Feed 300 Competitor Ads to a Model and You Get Four ...
  2. Ad-to-Landing-Page Message Match Checklist
  3. How Users Read on the Web - NN/G
  4. How People Read Online: New and Old Findings - NN/G
  5. PARSE: LLM Driven Schema Optimization for Reliable ...
  6. Offer - Schema.org Type
  7. How Little Do Users Read? - Nielsen Norman Group
  8. Schema Markup Testing Tool | Google Search Central
  9. Schema Markup for Location Pages Guide
  10. Advertising FAQ's: A Guide for Small Business
  11. Ad to Landing Page Message Match: The B2B Framework
  12. Paid Search Landing Page Promise Audit | That'sGonnaHelp
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles