Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

meta-ad-preflight

A pre-flight check for Meta (Facebook / Instagram) ads that catches the silent "no image" delivery failure before you flip a campaign to ACTIVE.

The failure this prevents

A single Meta ad is delivered across many placements — Feed, Stories, Reels, and more. With placement asset customization you attach a different image to each surface (a 1:1 for Feed, a 9:16 for Reels/Stories) via asset_customization_rules. The trap: if a placement is enabled on the ad set but no rule matches it — or the matched image is too small for that surface — Meta does not error. It delivers the ad blank. Budget is spent on an image-less placement, and you usually find out days later from a bad report.

Ads Manager previews don't reliably surface this, and it is easy to reintroduce every time you add a placement or swap a creative. meta-ad-preflight turns the check into a machine gate: it reads the live account through the Marketing API and exits non-zero if any ad would deliver blank.

What it checks

For every deliverable ad (status = ACTIVE), it fails (exit 1) on any of:

  1. Placement coverage — every enabled (platform, position) on the ad set must match at least one asset_customization_rules entry. An uncovered placement delivers with no image.
  2. Image dimensions — each used label's image exists, is ACTIVE, and meets the minimum for its surface: square 1:1 ≥ 1080×1080, vertical 9:16 ≥ 1080×1920, portrait 4:5 ≥ 1080×1350. Undersized images are dropped on Reels/Stories. An ad with no asset_feed_spec at all (single 1:1) is flagged, because vertical surfaces fall back to a letterbox.
  3. Excluded placements — dead / low-quality surfaces such as instream_video, facebook_reels_overlay, audience_network, and threads must not be enabled.
  4. Auto-optimization opt-outadapt_to_placement and advantage_plus_creative must be OPT_OUT, so Meta does not re-crop or alter the creative and break the layout.

Only ads whose own status is ACTIVE are inspected — a PAUSED campaign still holds ACTIVE ads that deliver the moment it is resumed.

Install

git clone https://github.com/highdef-joetsu/meta-ad-preflight.git
cd meta-ad-preflight
pip install -r requirements.txt

Usage

Set two environment variables (copy .env.example and source it, or export them):

export META_ACCESS_TOKEN=...           # a token with ads_read on the account
export META_AD_ACCOUNT_ID=act_123456   # the ad account to inspect

python3 preflight.py                    # ACTIVE campaigns only (the default gate)
python3 preflight.py <campaign_id>      # inspect a single campaign
python3 preflight.py --all              # include PAUSED campaigns

The process exits 0 on PASS and 1 on any violation, so you can wire it into a deploy step or CI job that publishes ads:

python3 preflight.py && echo "safe to activate"

Sample output

== campaign: Spring Sale (120200000000000)
  o PASS  spring_sale_feed_reels (120210000000000)
  x FAIL  spring_sale_stories_only (120210000000001)
        - *coverage gap: instagram/reels matches no rule -> delivers with no image
        - *vertical image too small: 'story_a' 1080x1350 < required 1080x1920 (portrait(4:5)) -> may not render on Reels/Stories

============================================================
ads inspected: 2 / violations: 2
result: FAIL - do not flip ACTIVE until the above are fixed.

How it works

The tool pulls each ad's ad-set targeting and creative (asset_feed_spec / degrees_of_freedom_spec) from the Graph API, expands the enabled placements and the placements each customization rule covers into (platform, position) sets, and reports the set difference as coverage gaps. Image sizes are read from /adimages and classified by aspect ratio. The decision logic (classify_ratio, expand_placements, excluded_placements, coverage_gaps) is pure and unit-tested — see tests/.

pip install pytest && python3 -m pytest tests/ -q

Notes and limitations

  • Tested against Marketing API v21.0; override with META_API_VERSION.
  • The excluded-placement and minimum-size policies are opinionated defaults that suit static-image campaigns; edit BAD_POSITIONS, BAD_PLATFORMS, and the MIN_* constants for your own standards.
  • Read-only: it never mutates campaigns. It only reports.

License

MIT © HIGHDEF INC. — see LICENSE.

About

Pre-flight check for Meta (Facebook/Instagram) ads that catches silent 'no image' delivery before a campaign goes ACTIVE.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages