update_ad_creative
Modify existing Meta ad creative content and settings, including copy, headlines, descriptions, and call-to-action elements.
Instructions
Update an existing ad creative with new content or settings.
Args:
creative_id: Meta Ads creative ID to update
access_token: Meta API access token (optional - will use cached token if not provided)
name: New creative name
message: New ad copy/text
headline: Single headline for simple ads (cannot be used with headlines)
headlines: New list of headlines for dynamic creative testing (cannot be used with headline)
description: Single description for simple ads (cannot be used with descriptions)
descriptions: New list of descriptions for dynamic creative testing (cannot be used with description)
dynamic_creative_spec: New dynamic creative optimization settings
call_to_action_type: New call to action button type
lead_gen_form_id: Lead generation form ID for lead generation campaigns. Required when using
lead generation CTAs like 'SIGN_UP', 'GET_OFFER', 'SUBSCRIBE', etc.
Returns:
JSON response with updated creative details
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| creative_id | Yes | ||
| access_token | No | ||
| name | No | ||
| message | No | ||
| headline | No | ||
| headlines | No | ||
| description | No | ||
| descriptions | No | ||
| dynamic_creative_spec | No | ||
| call_to_action_type | No | ||
| lead_gen_form_id | No |
Implementation Reference
- meta_ads_mcp/core/ads.py:963-1118 (handler)The primary handler implementation for the update_ad_creative MCP tool. It performs validation on inputs like headlines and descriptions, constructs the appropriate object_story_spec or asset_feed_spec for dynamic creatives, and makes a POST request to the Meta Ads API to update the creative. Includes decorators for MCP registration (@mcp_server.tool()) and API handling (@meta_api_tool).@mcp_server.tool() @meta_api_tool async def update_ad_creative( creative_id: str, access_token: Optional[str] = None, name: Optional[str] = None, message: Optional[str] = None, headline: Optional[str] = None, headlines: Optional[List[str]] = None, description: Optional[str] = None, descriptions: Optional[List[str]] = None, dynamic_creative_spec: Optional[Dict[str, Any]] = None, call_to_action_type: Optional[str] = None, lead_gen_form_id: Optional[str] = None ) -> str: """ Update an existing ad creative with new content or settings. Args: creative_id: Meta Ads creative ID to update access_token: Meta API access token (optional - will use cached token if not provided) name: New creative name message: New ad copy/text headline: Single headline for simple ads (cannot be used with headlines) headlines: New list of headlines for dynamic creative testing (cannot be used with headline) description: Single description for simple ads (cannot be used with descriptions) descriptions: New list of descriptions for dynamic creative testing (cannot be used with description) dynamic_creative_spec: New dynamic creative optimization settings call_to_action_type: New call to action button type lead_gen_form_id: Lead generation form ID for lead generation campaigns. Required when using lead generation CTAs like 'SIGN_UP', 'GET_OFFER', 'SUBSCRIBE', etc. Returns: JSON response with updated creative details """ # Check required parameters if not creative_id: return json.dumps({"error": "No creative ID provided"}, indent=2) # Validate headline/description parameters - cannot mix simple and complex if headline and headlines: return json.dumps({"error": "Cannot specify both 'headline' and 'headlines'. Use 'headline' for single headline or 'headlines' for multiple."}, indent=2) if description and descriptions: return json.dumps({"error": "Cannot specify both 'description' and 'descriptions'. Use 'description' for single description or 'descriptions' for multiple."}, indent=2) # Validate dynamic creative parameters (plural forms only) if headlines: if len(headlines) > 5: return json.dumps({"error": "Maximum 5 headlines allowed for dynamic creatives"}, indent=2) for i, h in enumerate(headlines): if len(h) > 40: return json.dumps({"error": f"Headline {i+1} exceeds 40 character limit"}, indent=2) if descriptions: if len(descriptions) > 5: return json.dumps({"error": "Maximum 5 descriptions allowed for dynamic creatives"}, indent=2) for i, d in enumerate(descriptions): if len(d) > 125: return json.dumps({"error": f"Description {i+1} exceeds 125 character limit"}, indent=2) # Prepare the update data update_data = {} if name: update_data["name"] = name # Choose between asset_feed_spec (dynamic creative) or object_story_spec (traditional) # ONLY use asset_feed_spec when user explicitly provides plural parameters (headlines/descriptions) if headlines or descriptions or dynamic_creative_spec: # Handle dynamic creative assets via asset_feed_spec asset_feed_spec = {} # Add required ad_formats field for dynamic creatives asset_feed_spec["ad_formats"] = ["SINGLE_IMAGE"] # Handle headlines - Meta API uses "titles" not "headlines" in asset_feed_spec if headlines: asset_feed_spec["titles"] = [{"text": headline_text} for headline_text in headlines] # Handle descriptions if descriptions: asset_feed_spec["descriptions"] = [{"text": description_text} for description_text in descriptions] # Add message as bodies - Meta API uses "bodies" not "primary_texts" in asset_feed_spec if message: asset_feed_spec["bodies"] = [{"text": message}] # Add call_to_action_types if provided if call_to_action_type: asset_feed_spec["call_to_action_types"] = [call_to_action_type] update_data["asset_feed_spec"] = asset_feed_spec else: # Use traditional object_story_spec with link_data for simple creatives if message or headline or description or call_to_action_type or lead_gen_form_id: update_data["object_story_spec"] = {"link_data": {}} if message: update_data["object_story_spec"]["link_data"]["message"] = message # Add headline (singular) to link_data if headline: update_data["object_story_spec"]["link_data"]["name"] = headline # Add description (singular) to link_data if description: update_data["object_story_spec"]["link_data"]["description"] = description # Add call_to_action to link_data for simple creatives if call_to_action_type or lead_gen_form_id: cta_data = {} if call_to_action_type: cta_data["type"] = call_to_action_type # Add lead form ID to value object if provided (required for lead generation campaigns) if lead_gen_form_id: cta_data["value"] = {"lead_gen_form_id": lead_gen_form_id} if cta_data: update_data["object_story_spec"]["link_data"]["call_to_action"] = cta_data # Add dynamic creative spec if provided if dynamic_creative_spec: update_data["dynamic_creative_spec"] = dynamic_creative_spec # Prepare the API endpoint for updating the creative endpoint = f"{creative_id}" try: # Make API request to update the creative data = await make_api_request(endpoint, access_token, update_data, method="POST") # If successful, get more details about the updated creative if "id" in data: creative_endpoint = f"{creative_id}" creative_params = { "fields": "id,name,status,thumbnail_url,image_url,image_hash,object_story_spec,url_tags,link_url,dynamic_creative_spec" } creative_details = await make_api_request(creative_endpoint, access_token, creative_params) return json.dumps({ "success": True, "creative_id": creative_id, "details": creative_details }, indent=2) return json.dumps(data, indent=2) except Exception as e: return json.dumps({ "error": "Failed to update ad creative", "details": str(e), "update_data_sent": update_data }, indent=2)