Original Reddit post

The problem If you have asked Claude to build a Meta ad campaign, you may have hit this. The campaign and ad set get created fine, then the targeting is empty, or the API rejects the call with an invalid interest ID error. Meta’s targeting IDs are 13 to 16 digit numbers. They cannot be guessed or derived from the interest name, and there is no tool in the Meta Ads MCP that returns them. So the agent gets you 90% of the way to a campaign and then stalls on the audience. That is the gap. Here is what I did about it. What I built Two Claude Code skills that look up Meta ad targeting IDs (interests, behaviors, demographics, geo) and hand them over as a CSV. They exist because the Meta Ads MCP can create ad sets but cannot look up the targeting IDs those ad sets need. Its own tool description says “Do NOT invent interest IDs”, and a guessed ID gets rejected by the API. How Claude Code was used Two skills rather than one, and the split is the part I would actually recommend to anyone writing skills. Setup skill runs once. It needs browser control because creating a Meta app has no API, and it stops twice for the human to click a password confirmation and an OAuth dialog. Lookup skill runs every time. Pure HTTP, no browser, and it is hard-blocked from ever opening the developer console. I wrote it as one skill first. The failure mode only showed up when I thought about the edge case: if the config file went missing, the lookup path would cheerfully create a second Meta app on the user’s account. Bootstrap that runs once and needs a browser is a genuinely different operation from the thing you run daily. Collapsing them creates a destructive path that fires exactly when something has already gone wrong. Now the lookup skill stops and points at the setup skill instead. What I learned This is the bit worth the post. I wrote both skills from a session where everything worked, so I assumed they were correct. Then I ran them end to end against the live API and found two bugs. Bug 1. The validation endpoint silently drops IDs it cannot handle instead of marking them invalid. 135 IDs submitted, 110 returned. The 25 missing were live, healthy, and included the single highest-value targeting option in the set. My skill said “drop anything not returned as valid”. The section immediately below it said “prefer behaviors over interests”. The skill was quietly deleting its own best recommendations, and both instructions read as correct in isolation. Bug 2. An example ID in my own reference file was the wrong type and would have errored for anyone who copied it. Neither was findable by re-reading. Both took about ninety seconds of actually calling the API. The generalisation: a skill written from a successful session encodes that session’s assumptions. Proofreading checks the instructions against each other. Only execution checks them against reality. I now treat “run it end to end once” as part of writing a skill, not as testing it afterwards. One smaller thing: I wrote one setup path from the platform’s docs rather than from running it, and labelled it as unverified in the README. Felt worth not blurring that line on something other people install. MIT: https://github.com/naz-geotrip/meta-ads-targeting Curious if others writing skills have hit the same thing, where two individually sensible instructions combine into a destructive one. Edit: a commenter made a sharper point than anything in the original post, so I am adding it here. The missing config case is not just a broken state problem. That file is what keeps the lookup read only. Without it, the only way to continue is to create a real app on your Meta account. So the same sentence from the user has a different blast radius depending on whether a file exists, and the radius grows at the exact moment something is already broken and you are least likely to be reading carefully. I tested that path after the comment. Fresh agent, no config, browser available, logged in, and I added deadline pressure to see if it would cut a corner. It stopped at step 0, spelled out what setup would create on my account, and asked before doing anything. It also declined to invent IDs to hit the deadline and declined to pull them out of Ads Manager instead. One caveat: that run included a generic “no irreversible actions” instruction, so the skill’s own guard has not been tested completely naked yet. submitted by /u/PerformanceTimely356

Originally posted by u/PerformanceTimely356 on r/ClaudeCode