Marketing agencies · Creatives

Creative performance

Which ad holds attention, which one converts and which one is wearing out, by client, with the creative image next to the number.

UsageCommon
EffortMedium
ForAgencies that produce and test creatives for several clients and need to say which one works.
Source

Insights by ad, ads, creatives and images

Rule

Attention yardstick and result by objective

Outcome

Daily curve, ranking and fatigue

Activation

Creative dashboard, alerts and AI agent

What it solves

  • The best creative is picked by the campaign objective, not by everyone's CTR.
  • Hook rate and hold rate have one definition per client and add up correctly in any cut.
  • The tired creative shows up before cost rises, with a thumbnail that does not break on the dashboard.

Business questions it answers

Ask your agent these questions once the case is live.

What is the best creative in each campaign this month?
Which videos hold attention after the first seconds?
Which ads are worn out and need to be replaced?
Video, carousel or static: what converts best for this client?
Should we produce more short or long videos?

What you need

  • Meta Ads with ads, creatives and images synced, plus TikTok or Google when present
  • The hook rate and hold rate definition agreed with the creative team
  • A place to store each ad's thumbnail with a stable URL

What you get

  • A daily curve per ad with age, frequency and cumulative impressions
  • Creative ranking by objective, with thumbnail and link
  • Tired creative alert with a stable key
  • An AI agent that answers which creative to replace and why

Where to activate

Creative review meeting

Each creative's curve and the ranking by objective, with the thumbnail.

Tired creative alert

One task per ad, with a stable key, reassessed after a week.

AI agent via MCP

Answers which creatives to replace and which to scale, with the reason.

Ready to build?

The metrics are well defined. The work is the stable thumbnail, the real format of each ad and agreeing on the yardstick with the creative team. The detailed view has the business rules, the pitfalls and the acceptance test. Or send everything straight to your agent with the Nekt MCP.

The problem

Meta delivers video metrics as lists inside each row, the thumbnail URL expires at every sync and the same name shows up on different ads. Each agency defines hook rate its own way, and whoever stores the rate per day and averages it later delivers a number that matches no cut. Without the daily curve there is no fatigue, only a total.

How it is usually done, and the rule

Each row is a mistake that already happened in practice.

The common wayThe rule
01
Grouping by ad_name.
The key is ad_id

Aggregate by ad_id, never by ad_name: the same name appears on different ads, and merging them changes the ranking. The name is for display and for extracting attributes agreed with the creative team (format, length, script number) by position in a standard naming convention.

02
Switching definitions between clients and comparing the numbers.
Hook and hold with a declared definition

Pick one definition per client and keep it. The most common: hook rate = 3-second views (action_type video_view) / impressions, or 25% views / impressions; hold rate = ThruPlay or 15 seconds / 3-second views, or 100% views / 25% views. Write in the context which one was chosen.

03
Storing hook_rate per day and averaging it.
Store numerator and denominator

Rates are not stored per row. The table keeps impressions, plays, 25, 50, 75, 95 and 100% views, ThruPlay and clicks, and the rate is computed at read time from period sums. Averaging daily rates gives the wrong number when aggregating by week or campaign.

04
Comparing Meta quartiles directly with YouTube quartiles.
Quartiles have a different base per platform

On Meta, video metrics are lists (video_p25_watched_actions and similar) and the quartile rate uses video_plays as the base. On YouTube, the quartile rate is over impressions, and Google delivers a rate, not a count: rebuild the count by multiplying by views before combining. TikTok has 2 and 6-second views and p25 to p100.

05
One ranking by CTR for every ad.
Best creative by objective

Compare creatives within the same campaign or objective: cost per result for conversion, CPM for reach, CPC or cost per landing page view for traffic, cost per ThruPlay for video. Only creatives with spend in the period and a declared minimum of impressions count. Cost in a reach campaign reflects frequency, not the creative.

06
Trusting only the creative's object_type or video_id.
Format by delivery

If the ad recorded video plays on any day, it is a video, even if the creative says SHARE (boosted post) or has no video_id. Evaluate over the ad's whole history, not per day, or a day with no plays reclassifies the same creative.

07
Only the month's ranking, with no time axis.
Fatigue is a curve, not a total

Keep the table by ad and day with days since launch (first day with impressions), frequency and cumulative impressions. Fatigue is results falling while saturation rises. A rule used in practice: last 7 days CTR at least 35% below the previous 7, with 5,000 impressions or more in both windows.

08
Storing Meta's URL in the dashboard.
Thumbnail with a stable URL

Meta image URLs are temporary and reissued at every sync. The creative's thumbnail_url and image_url are often empty: get the image from adimages, linked through the creative (adimages.creatives contains the ad's creative.id). For an external dashboard, copy the image right after the sync and store ad_id and your own URL.

09
Flagging it as a creative with no content.
No preview is not an ad without art

Carousels and videos are almost never in adimages; a sponsored post that never went to the feed has no embed; a LinkedIn sponsored message has no image or impressions and is compared by sends and opens; a Google ad brings no text or image through the connector. Say it is a source limitation and never make up the ad text.

10
Spend with tax in the total and without tax in the ranking.
Cost with or without tax, declared

If the client reports Meta with a tax markup on spend, CPM, CPC and cost per view in the creative report use the same criterion as the media report. Mixing the two makes Meta video look more expensive than YouTube.

Attention metrics

Pick one hook definition and one hold definition and declare them in the client's context.

Meta · video start3-second viewactions: video_view
Meta · playbackPlaysvideo_play_actions
Meta · quartiles25%, 50%, 75%, 95% and 100%video_p25_watched_actions to video_p100_watched_actions
Meta · 15 seconds or completeThruPlayvideo_thruplay_watched_actions
Hook rateInitial attentionvideo_view / impressions or p25 / impressions
Hold rateRetentionThruPlay / video_view or p100 / p25
YouTube · quartilesRate over impressionsmetrics_video_quartile_p25_rate x views
TikTok · start2 and 6-second viewsvideo_watched_2s, video_watched_6s

Definitions

Hook rate
sum of the declared initial attention (3-second video_view or p25) / sum of the ad's impressions in the period
Hold rate
sum of ThruPlay (or p100) / sum of initial attention (video_view or p25), over the same period
Full retention
sum of p100 / sum of impressions
Quartile rate
Meta: pXX / video_plays; YouTube: pXX / impressions
Days since launch
date minus the ad_id's first day with impressions
Period frequency
impressions / reach for the same ad and period, never the average of daily frequencies
Creative cost per result
ad spend / result of the campaign objective, in the period
Tired creative
last 7 days CTR at or below 65% of the previous 7 days CTR, with at least 5,000 impressions in each window

Pitfalls that already happened

Broken thumbnail

The dashboard showed images that stopped loading within a day, because Meta's URL is reissued at every sync.

Copy the image and store ad_id and your own URL.

Reels in the static ranking

Boosted posts came as SHARE with no video_id, and reels entered the image ranking.

Format by video delivery over the ad's history.

Two ads with the same name

Grouping by name summed different ads, and the ranking winner was the sum of two.

Group by ad_id.

Average of averages

Hook rate stored per day and then averaged gave different numbers by week and by campaign.

Store the components and divide at read time.

Reach champion

The single ranking put reach ads with a low CPM at the top, ads that generated no leads at all.

Ranking within the campaign objective.

Leads counted twice

The cost per lead ranking added lead to its mirror types, and the best creative had half the real cost per lead.

Use the objective result, as in the Meta results case.

Validated on real data. In Nekt's own Meta Ads account, 14 ad names appear on more than one ad_id (376 ads for 362 names), and the creative's video_id is empty on every ad, including video ads. The ranking must aggregate by ad_id and the format must come from video delivery.

Acceptance test

The case is done when every item passes.

Agent package

Paste into Claude, ChatGPT or any client with the Nekt MCP connected.

Full Markdown
Creative performance
- The creative key is ad_id. Never group by ad_name.
- Hook rate and hold rate follow the client's definition (below). Always recompute from period sums; do not average rates.
- Meta: video metrics are lists; quartile rate = pXX / video_plays. YouTube: quartile rate over impressions.
- Format: video if the ad had plays on any day; otherwise, the creative's media type.
- Best creative = lowest cost for the campaign objective (conversion: cost per result; reach: CPM; traffic: CPC). Only creatives with spend and at least <n> impressions in the period.
- Fatigue: last 7 days CTR at least 35% below the previous 7, with 5,000 or more impressions in each window, or results falling while frequency and cumulative impressions rise.
- No preview is a source limitation (Meta video and carousel, posts outside the feed, Google). Do not make up ad text.
- Meta results follow the rules of the Meta Ads results by objective case.
Per-client exceptions:
- <client>: hook rate = <video_view / impressions | p25 / impressions>; hold rate = <ThruPlay / video_view | p100 / p25>.
- <client>: ad_name follows <format>_<length>_<script>, separated by _.
- <client>: Meta costs in the creative report <with | without> a <x>% tax.

Variations

Creative to sale

Link the ad_id to the CRM deal and rank by cost per sale.

Pillar and script

Extract the content pillar or script number from the caption or name and compare by group.

Paid and organic

Link the ad to the matching organic post by post ID to compare the same content in both.