Systems Library / Marketing Automation / How to Automate Ad Compliance and Policy Checks
Marketing Automation paid advertising

How to Automate Ad Compliance and Policy Checks

Pre-screen ads for policy violations before submission to reduce rejections.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

Getting an ad rejected on Meta after a campaign launch is one of the most avoidable problems in paid advertising. The rejection kills delivery, the ad enters review again, and you lose hours of momentum during a launch window. Building an automate ad compliance policy check review system into my creative workflow stopped 90% of rejections before they happened. The AI screens every ad against platform policies before I submit anything.

This matters beyond the obvious time savings. Repeated policy rejections flag your ad account. Enough of them and you're looking at account-level restrictions. A pre-submission compliance check is cheap insurance against that outcome.

What You Need Before Starting

Step 1: Build Your Policy Rule Set

Start with the most commonly violated policies. You don't need to encode everything — focus on the rules that cause 80% of rejections.

from dataclasses import dataclass, field

@dataclass
class PolicyRule:
    id: str
    platform: str         # "meta", "google", "tiktok"
    category: str
    description: str
    forbidden_patterns: list[str]   # exact strings to flag
    risk_level: str                 # "hard_block", "warning", "review"
    example_violation: str
    example_compliant: str

META_POLICIES = [
    PolicyRule(
        id="meta_personal_attributes",
        platform="meta",
        category="Personal Attributes",
        description="Cannot imply knowledge of personal characteristics",
        forbidden_patterns=[
            "are you struggling with", "do you have diabetes",
            "if you're overweight", "do you suffer from",
            "you have anxiety", "you're going through a divorce"
        ],
        risk_level="hard_block",
        example_violation="Are you struggling with debt?",
        example_compliant="Debt solutions for people who want a fresh start"
    ),
    PolicyRule(
        id="meta_misleading_claims",
        platform="meta",
        category="Misleading Claims",
        description="No guaranteed results or exaggerated claims",
        forbidden_patterns=[
            "guaranteed results", "100% success",
            "you will lose", "proven to cure",
            "miracle", "instant results",
            "make $10,000 in your first week"
        ],
        risk_level="hard_block",
        example_violation="Guaranteed to lose 20lbs in 2 weeks",
        example_compliant="Clients average 8lbs lost in their first month"
    ),
    PolicyRule(
        id="meta_before_after",
        platform="meta",
        category="Health Claims",
        description="Before/after imagery in health/weight loss ads restricted",
        forbidden_patterns=[
            "before and after", "before & after",
            "transformation tuesday", "look at my results"
        ],
        risk_level="warning",
        example_violation="See my before and after transformation",
        example_compliant="See how our program helped Sarah reach her goals"
    ),
    PolicyRule(
        id="meta_financial_guarantees",
        platform="meta",
        category="Financial Products",
        description="Cannot guarantee investment returns",
        forbidden_patterns=[
            "guaranteed return", "risk-free investment",
            "you will make money", "no risk",
            "can't lose"
        ],
        risk_level="hard_block",
        example_violation="Risk-free investment with guaranteed 20% returns",
        example_compliant="Investment strategies for long-term wealth building"
    ),
    PolicyRule(
        id="meta_adult_content",
        platform="meta",
        category="Adult Content",
        description="Sexual content and excessive skin not permitted in general placements",
        forbidden_patterns=[
            "sexy", "hot singles", "find a date tonight",
            "hookup", "explicit"
        ],
        risk_level="hard_block",
        example_violation="Find sexy singles near you tonight",
        example_compliant="Meet new people in your area"
    ),
]

Step 2: Build the Rule-Based Pre-Screen

Fast pattern matching runs first. No API calls needed for obvious violations.

import re

def rule_based_check(ad_copy: str, platform: str = "meta") -> list[dict]:
    violations = []
    copy_lower = ad_copy.lower()
    
    rules = [r for r in META_POLICIES if r.platform == platform]
    
    for rule in rules:
        for pattern in rule.forbidden_patterns:
            if pattern.lower() in copy_lower:
                violations.append({
                    "rule_id":     rule.id,
                    "category":    rule.category,
                    "risk":        rule.risk_level,
                    "trigger":     pattern,
                    "description": rule.description,
                    "fix":         f"Example of compliant copy: {rule.example_compliant}"
                })
                break  # one violation per rule is enough
    
    return violations

Step 3: Build the AI Policy Reviewer

The AI catches nuanced violations that pattern matching misses — implied personal attributes, borderline medical claims, misleading framing that doesn't use banned keywords.

import anthropic
import json

_client = anthropic.Anthropic()

POLICY_SUMMARY = """
META ADVERTISING POLICIES SUMMARY (Key Rules):

1. Personal Attributes: Never directly address or imply knowledge of personal 
   characteristics like health conditions, finances, relationship status, or identity.
   BAD: "Are you struggling with debt?" GOOD: "Debt solutions that actually work"

2. Misleading Claims: No guaranteed results, miracle cures, or exaggerated claims 
   without substantiation. All income claims need qualification.
   BAD: "Guaranteed to lose 20lbs" GOOD: "Clients average 8lbs in month one"

3. Health/Medical: No claims of curing diseases. Weight loss ads cannot use 
   before/after imagery or imply impossible/dangerous results.

4. Financial: No guaranteed investment returns or risk-free claims.

5. Adult/Sensitive: No sexual content, shock content, or graphic images.

6. Discrimination: Ads cannot discriminate on protected characteristics.

7. Engagement Bait: No "like this if", "tag a friend who", vote baiting.
"""

def ai_policy_review(ad_copy: str, headline: str = "",
                      platform: str = "meta") -> dict:
    prompt = f"""You are a Meta Ads compliance expert. Review this ad for policy violations.

{POLICY_SUMMARY}

Ad to review:
Headline: {headline}
Body Copy: {ad_copy}

Return JSON only:
{{
  "approved": true/false,
  "risk_level": "safe|warning|likely_rejected",
  "violations": [
    {{"rule": "rule name", "issue": "specific problem", "fix": "how to rewrite"}}
  ],
  "overall_assessment": "one sentence"
}}"""

    response = _client.messages.create(
        model="claude-haiku-3", max_tokens=600,
        messages=[{"role": "user", "content": prompt}]
    )
    
    try:
        return json.loads(response.content[0].text.strip())
    except json.JSONDecodeError:
        return {"approved": None, "risk_level": "review",
                "violations": [], "overall_assessment": "Review manually"}

Step 4: Build the Combined Compliance Checker

Combine rule-based and AI checks into one function that returns a final verdict.

@dataclass
class ComplianceResult:
    approved: bool
    risk_level: str   # "safe", "warning", "likely_rejected", "blocked"
    violations: list[dict]
    suggestions: list[str]
    confidence: float

def check_ad_compliance(
    headline: str,
    body_copy: str,
    platform: str = "meta"
) -> ComplianceResult:
    full_copy = f"{headline} {body_copy}"
    
    # Stage 1: Rule-based check
    rule_violations = rule_based_check(full_copy, platform)
    
    hard_blocks = [v for v in rule_violations if v["risk"] == "hard_block"]
    if hard_blocks:
        return ComplianceResult(
            approved=False,
            risk_level="blocked",
            violations=rule_violations,
            suggestions=[v["fix"] for v in hard_blocks],
            confidence=0.99
        )
    
    # Stage 2: AI review for nuanced issues
    ai_result = ai_policy_review(body_copy, headline, platform)
    
    all_violations = rule_violations + ai_result.get("violations", [])
    risk = ai_result.get("risk_level", "safe")
    
    return ComplianceResult(
        approved=risk == "safe" and not hard_blocks,
        risk_level=risk,
        violations=all_violations,
        suggestions=[v.get("fix","") for v in ai_result.get("violations",[])],
        confidence=0.85 if ai_result.get("approved") is not None else 0.5
    )

Step 5: Build a Batch Screener for Creative Reviews

Screen multiple ad variants before a campaign launch.

def screen_creative_batch(ads: list[dict]) -> list[dict]:
    """
    ads = list of {"id": str, "headline": str, "copy": str}
    """
    results = []
    
    for ad in ads:
        result = check_ad_compliance(
            headline=ad.get("headline", ""),
            body_copy=ad.get("copy", "")
        )
        results.append({
            "id":         ad["id"],
            "approved":   result.approved,
            "risk":       result.risk_level,
            "violations": result.violations,
            "suggestions":result.suggestions
        })
        print(f"Ad {ad['id']}: {result.risk_level.upper()} — "
              f"{len(result.violations)} violation(s)")
    
    approved = sum(1 for r in results if r["approved"])
    print(f"\n{approved}/{len(ads)} ads cleared for submission")
    return results

Step 6: Generate a Compliant Rewrite for Flagged Ads

When an ad fails, give the copywriter a compliant version to work from, not just a list of problems.

def rewrite_for_compliance(headline: str, body_copy: str,
                            violations: list[dict]) -> dict:
    issues = "\n".join(f"- {v['rule']}: {v['issue']}" for v in violations[:3])
    
    prompt = f"""Rewrite this ad to comply with Meta's advertising policies.

Original headline: {headline}
Original copy: {body_copy}

Issues to fix:
{issues}

Rules:
- Keep the same core offer and message
- Fix the specific policy violations
- Maintain persuasive language and emotional appeal
- Do not add fake claims or guarantees

Return JSON:
{{"headline": "rewritten headline", "copy": "rewritten body copy",
 "what_changed": "brief explanation of changes"}}"""
    
    response = _client.messages.create(
        model="claude-sonnet-4-5", max_tokens=400,
        messages=[{"role": "user", "content": prompt}]
    )
    
    try:
        return json.loads(response.content[0].text.strip())
    except Exception:
        return {"headline": headline, "copy": body_copy, "what_changed": "Review manually"}

What to Build Next

Related Reading

Want this system built for your business?

Get a free assessment. We will map every system your business needs and show you the ROI.

Get Your Free Assessment

Related Systems