OPS ► MARKETING COMMAND CENTER
SkillDatabases & dataMarketing command center. Email campaigns (Klaviyo), paid ads (Meta/Google), analytics (GA4), SEO, and social media metrics. One dashboard for all marketing channels.
Use OPS ► MARKETING COMMAND CENTER in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add OPS ► MARKETING COMMAND CENTER and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the OPS ► MARKETING COMMAND CENTER skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
What this skill tells your AI
The instructions your AI receives, as published by davepoon/buildwithclaude in plugins/claude-ops/skills/ops-marketing/SKILL.md and read by ahel’s review.
Runtime Context
Before executing, load available context:
-
Preferences: Read
${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.jsontimezone— display all timestamps correctlyklaviyo_private_key,meta_ads_token,meta_ad_account_id,ga4_property_id,google_search_console_site— check userConfig keys before env varsgoogle_ads_developer_token,google_ads_client_id,google_ads_client_secret,google_ads_refresh_token,google_ads_customer_id,google_ads_login_customer_id— Google Ads credentials
-
Daemon health: Read
${CLAUDE_PLUGIN_DATA_DIR}/daemon-health.json- If
action_neededis not null → surface it before running any channel queries
- If
-
Secrets: Resolve API keys via userConfig → env vars → Doppler MCP (
mcp__doppler__*) → Doppler CLI fallback (see Credential Resolution section below)
CLI/API Reference
Klaviyo REST API
| Endpoint | Method | Description |
|---|---|---|
https://a.klaviyo.com/api/lists/?fields[list]=name,id,profile_count | GET | All lists + subscriber counts |
https://a.klaviyo.com/api/campaigns/?filter=equals(messages.channel,'email')&sort=-created_at | GET | Recent campaigns |
https://a.klaviyo.com/api/flows/?filter=equals(status,'live') | GET | Active flows |
https://a.klaviyo.com/api/metrics/ | GET | Available metrics |
Auth header: Authorization: Klaviyo-API-Key ${KLAVIYO_KEY} | Revision header: revision: 2024-10-15
Meta Graph API
| Endpoint | Method | Description |
|---|---|---|
https://graph.facebook.com/v18.0/${META_ACCOUNT}/insights?fields=spend,...&date_preset=last_7d | GET | Account-level ad spend |
https://graph.facebook.com/v18.0/${META_ACCOUNT}/campaigns?fields=name,status,insights{...} | GET | Campaign breakdown |
https://graph.facebook.com/v18.0/me/accounts?fields=instagram_business_account | GET | Linked Instagram account |
Auth header: Authorization: Bearer ${META_TOKEN}
Google Analytics 4 (Data API)
| Endpoint | Method | Description |
|---|---|---|
https://analyticsdata.googleapis.com/v1beta/properties/${GA4_PROPERTY}:runReport | POST | Run custom report |
Auth: gcloud ADC — GA4_TOKEN=$(gcloud auth application-default print-access-token)
Google Search Console
| Endpoint | Method | Description |
|---|---|---|
https://searchconsole.googleapis.com/webmasters/v3/sites/${GSC_SITE_ENCODED}/searchAnalytics/query | POST | Search performance data |
Auth: Same gcloud ADC token as GA4
Agent Teams support
If CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 is set, use Agent Teams when gathering channel data in parallel. This enables:
- Agents share context and can coordinate mid-flight
- You can steer priorities in real-time
- Agents report progress as they complete
Team setup (only when flag is enabled):
TeamCreate("marketing-team")
Agent(team_name="marketing-team", name="email-metrics", prompt="Pull Klaviyo subscriber counts, campaign stats, and flow metrics")
Agent(team_name="marketing-team", name="ads-metrics", prompt="Pull Meta Ads spend, ROAS, and campaign breakdown")
Agent(team_name="marketing-team", name="analytics-metrics", prompt="Pull GA4 sessions, conversions, and traffic sources")
Agent(team_name="marketing-team", name="seo-metrics", prompt="Pull Search Console clicks, impressions, and top queries")
If the flag is NOT set, use standard fire-and-forget subagents.
Credential Resolution
Resolve credentials in this order for each service:
Klaviyo
KLAVIYO_KEY="${KLAVIYO_PRIVATE_KEY:-$(claude plugin config get klaviyo_private_key 2>/dev/null)}"
if [ -z "$KLAVIYO_KEY" ]; then
KLAVIYO_KEY="$(doppler secrets get KLAVIYO_PRIVATE_KEY --plain 2>/dev/null)"
fi
Meta Ads
META_TOKEN="${META_ADS_TOKEN:-$(claude plugin config get meta_ads_token 2>/dev/null)}"
META_ACCOUNT="${META_AD_ACCOUNT_ID:-$(claude plugin config get meta_ad_account_id 2>/dev/null)}"
if [ -z "$META_TOKEN" ]; then
META_TOKEN="$(doppler secrets get META_ADS_TOKEN --plain 2>/dev/null)"
fi
GA4
GA4_PROPERTY="${GA4_PROPERTY_ID:-$(claude plugin config get ga4_property_id 2>/dev/null)}"
# GA4 uses gcloud application default credentials — check if configured:
gcloud auth application-default print-access-token 2>/dev/null
Google Search Console
GSC_SITE="${GOOGLE_SEARCH_CONSOLE_SITE:-$(claude plugin config get google_search_console_site 2>/dev/null)}"
# Uses same gcloud ADC as GA4
Google Ads
GADS_API_VERSION="v23"
GADS_DEV_TOKEN="${GOOGLE_ADS_DEVELOPER_TOKEN:-$(claude plugin config get google_ads_developer_token 2>/dev/null)}"
GADS_CLIENT_ID="${GOOGLE_ADS_CLIENT_ID:-$(claude plugin config get google_ads_client_id 2>/dev/null)}"
GADS_CLIENT_SECRET="${GOOGLE_ADS_CLIENT_SECRET:-$(claude plugin config get google_ads_client_secret 2>/dev/null)}"
GADS_REFRESH_TOKEN="${GOOGLE_ADS_REFRESH_TOKEN:-$(claude plugin config get google_ads_refresh_token 2>/dev/null)}"
GADS_CUSTOMER_ID="${GOOGLE_ADS_CUSTOMER_ID:-$(claude plugin config get google_ads_customer_id 2>/dev/null)}"
GADS_LOGIN_CUSTOMER_ID="${GOOGLE_ADS_LOGIN_CUSTOMER_ID:-$(claude plugin config get google_ads_login_customer_id 2>/dev/null)}"
# Doppler fallback
if [ -z "$GADS_REFRESH_TOKEN" ]; then
GADS_REFRESH_TOKEN="$(doppler secrets get GOOGLE_ADS_REFRESH_TOKEN --plain 2>/dev/null)"
fi
if [ -z "$GADS_DEV_TOKEN" ]; then
GADS_DEV_TOKEN="$(doppler secrets get GOOGLE_ADS_DEVELOPER_TOKEN --plain 2>/dev/null)"
fi
# Strip dashes from customer ID (API requires no dashes)
GADS_CUSTOMER_ID="${GADS_CUSTOMER_ID//-/}"
# Refresh access token (expires in ~1 hour — always refresh before API calls)
GADS_ACCESS_TOKEN=$(curl -s -X POST https://oauth2.googleapis.com/token \
--data "client_id=${GADS_CLIENT_ID}" \
--data "client_secret=${GADS_CLIENT_SECRET}" \
--data "refresh_token=${GADS_REFRESH_TOKEN}" \
--data "grant_type=refresh_token" | jq -r '.access_token')
# Common headers for all Google Ads API calls
GADS_HEADERS=(-H "Content-Type: application/json" -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" -H "developer-token: ${GADS_DEV_TOKEN}")
if [ -n "$GADS_LOGIN_CUSTOMER_ID" ]; then
GADS_HEADERS+=(-H "login-customer-id: ${GADS_LOGIN_CUSTOMER_ID}")
fi
Sub-command Routing
Route $ARGUMENTS to the correct section below:
| Input | Action |
|---|---|
| (empty), dashboard | Run full marketing dashboard |
| email, klaviyo | Klaviyo email metrics |
| ads, meta | Meta Ads performance (read-only overview) |
| meta-manage, meta create-campaign, meta target, meta creative, meta rules, meta audiences, meta advantage | Meta Ads campaign management (see ## meta-manage section) |
| google-ads, gads | Google Ads dashboard + campaign management (see ## google-ads section) |
| analytics, ga4 | GA4 sessions + conversions |
| ga4 realtime, ga4 funnel, ga4 cohort, ga4 audience, ga4 pivot | GA4 advanced analytics (see ## ga4-advanced section) |
| seo, gsc | Search Console metrics |
| social | Social media aggregator |
| instagram, instagram post, instagram reel, instagram story, instagram insights, instagram demographics | Instagram publishing + insights (see ## instagram section) |
| campaigns | Cross-channel campaign overview (all platforms) |
| optimize | Cross-platform ad optimization agent |
| attribution | Unified attribution table (Meta + Google + Klaviyo + GA4) |
| setup | Configure API keys |
email / klaviyo
Pull Klaviyo metrics for last 30 days.
Subscriber count
curl -s "https://a.klaviyo.com/api/lists/?fields[list]=name,id,profile_count" \
-H "Authorization: Klaviyo-API-Key ${KLAVIYO_KEY}" \
-H "revision: 2024-10-15" | jq '.data[] | {name: .attributes.name, id: .id, count: .attributes.profile_count}'
Recent campaigns (last 10)
curl -s "https://a.klaviyo.com/api/campaigns/?filter=equals(messages.channel,'email')&sort=-created_at&page[size]=10&fields[campaign]=name,status,created_at,send_time" \
-H "Authorization: Klaviyo-API-Key ${KLAVIYO_KEY}" \
-H "revision: 2024-10-15" | jq '.data[] | {name: .attributes.name, status: .attributes.status, sent: .attributes.send_time}'
Flow metrics (active flows)
curl -s "https://a.klaviyo.com/api/flows/?filter=equals(status,'live')&fields[flow]=name,status,created,trigger_type" \
-H "Authorization: Klaviyo-API-Key ${KLAVIYO_KEY}" \
-H "revision: 2024-10-15" | jq '.data[] | {name: .attributes.name, trigger: .attributes.trigger_type}'
Key email metrics (opens, clicks, revenue via metric aggregates)
# Get metric IDs first
curl -s "https://a.klaviyo.com/api/metrics/" \
-H "Authorization: Klaviyo-API-Key ${KLAVIYO_KEY}" \
-H "revision: 2024-10-15" | jq '.data[] | select(.attributes.name | test("Opened Email|Clicked Email|Placed Order")) | {name: .attributes.name, id: .id}'
Output format
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EMAIL (KLAVIYO) — last 30d
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Lists: [list_name] — [N] subscribers
Campaigns: [N sent] | [N drafts]
Active Flows: [N]
RECENT CAMPAIGNS
[name] [status] sent [date]
...
ads / meta
Pull Meta Ads insights for the configured ad account.
Account-level spend (last 7 days)
curl -s "https://graph.facebook.com/v18.0/${META_ACCOUNT}/insights?fields=spend,impressions,clicks,ctr,cpc,actions,action_values&date_preset=last_7d&level=account" \
-H "Authorization: Bearer ${META_TOKEN}" | jq '{spend: .data[0].spend, impressions: .data[0].impressions, clicks: .data[0].clicks, ctr: .data[0].ctr, cpc: .data[0].cpc}'
Campaign breakdown (last 7 days)
curl -s "https://graph.facebook.com/v18.0/${META_ACCOUNT}/campaigns?fields=name,status,daily_budget,lifetime_budget,insights{spend,impressions,clicks,actions,action_values}&date_preset=last_7d" \
-H "Authorization: Bearer ${META_TOKEN}" | jq '.data[] | {name: .name, status: .status, spend: .insights.data[0].spend}'
ROAS calculation
From action_values array: extract action_type == "purchase" value, divide by spend.
Top performing ads (last 7d)
curl -s "https://graph.facebook.com/v18.0/${META_ACCOUNT}/ads?fields=name,adset_id,insights{spend,impressions,clicks,actions,action_values,ctr,cpc}&date_preset=last_7d&limit=10" \
-H "Authorization: Bearer ${META_TOKEN}" | jq '.data | sort_by(.insights.data[0].spend | tonumber) | reverse | .[0:5] | .[] | {name: .name, spend: .insights.data[0].spend, ctr: .insights.data[0].ctr}'
Output format
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
META ADS — last 7d
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Spend: $[X]
ROAS: [X]x
Purchases: [N] ($[X] revenue)
Impressions: [N] CTR: [X]%
CPC: $[X]
CAMPAIGNS
[name] [status] $[spend] [roas]x ROAS
...
TOP ADS (by spend)
[name] $[spend] [ctr]% CTR
meta-manage
Full Meta Ads campaign management. Uses same META_TOKEN and META_ACCOUNT credentials as read-only ads section.
Credential check: If META_TOKEN is empty, print Meta Ads not configured. Run /ops:marketing setup. and stop.
Route $ARGUMENTS within meta-manage:
| Input | Action |
|---|---|
| create-campaign | Create a new campaign (always PAUSED) |
| target <ADSET_ID> | Configure ad set targeting |
| creative <CAMPAIGN_ID> | Upload image + create ad with copy |
| rules | List / create automation rules |
| audiences | Create custom or lookalike audiences |
| advantage | Create Advantage+ AI-optimized campaign |
create-campaign
Collect via AskUserQuestion (max 4 options each call):
- Campaign objective —
[OUTCOME_TRAFFIC, OUTCOME_SALES, OUTCOME_LEADS, OUTCOME_AWARENESS] - Daily budget in dollars (free text)
- Campaign name (free text)
Then confirm via AskUserQuestion: "Create Meta campaign '<NAME>' with $<BUDGET>/day budget?" options [Create, Cancel]
BUDGET_CENTS=$(awk "BEGIN {printf \"%d\", ${BUDGET_DOLLARS} * 100}")
curl -s -X POST "https://graph.facebook.com/v20.0/${META_ACCOUNT}/campaigns" \
-H "Authorization: Bearer ${META_TOKEN}" \
-F "name=${CAMPAIGN_NAME}" \
-F "objective=${OBJECTIVE}" \
-F "status=PAUSED" \
-F "special_ad_categories=[]" \
-F "daily_budget=${BUDGET_CENTS}" | jq '{id: .id, error: .error.message}'
Print: Campaign "${CAMPAIGN_NAME}" created (ID: <ID>, status: PAUSED, budget: $<BUDGET>/day). Enable via Meta Ads Manager or add ad sets first.
If error, print the error message.
target <ADSET_ID>
Configure targeting for an existing ad set. Collect via AskUserQuestion:
- Target countries (comma-separated ISO codes, e.g.
US,CA,GB) — free text - Age range:
[18-34, 25-54, 35-65, 18-65] - Gender:
[All, Men only, Women only, Skip]
# Build geo_locations JSON
GEO_JSON=$(echo "$COUNTRIES" | tr ',' '\n' | jq -Rc '.' | jq -sc '{"countries": .}')
# Build targeting spec
TARGETING_JSON=$(jq -n \
--argjson geo "$GEO_JSON" \
--arg age_min "$AGE_MIN" \
--arg age_max "$AGE_MAX" \
'{
geo_locations: $geo,
age_min: ($age_min | tonumber),
age_max: ($age_max | tonumber)
}')
# Add gender filter if requested
if [ "$GENDER" = "Men only" ]; then
TARGETING_JSON=$(echo "$TARGETING_JSON" | jq '. + {"genders": [1]}')
elif [ "$GENDER" = "Women only" ]; then
TARGETING_JSON=$(echo "$TARGETING_JSON" | jq '. + {"genders": [2]}')
fi
curl -s -X POST "https://graph.facebook.com/v20.0/${ADSET_ID}" \
-H "Authorization: Bearer ${META_TOKEN}" \
-F "targeting=${TARGETING_JSON}" | jq '{success: .success, error: .error.message}'
Print: Ad set ${ADSET_ID} targeting updated: ${COUNTRIES}, ages ${AGE_MIN}-${AGE_MAX}${GENDER_LABEL}.
creative <CAMPAIGN_ID>
Upload an image and create an ad. Collect via AskUserQuestion:
- Image file path or URL (free text)
- Ad set ID to attach the ad to (free text)
- Primary text (ad copy, free text — up to 125 characters recommended)
Then collect headline (free text, up to 40 characters) via a second AskUserQuestion.
# Step 1: Upload image
if [[ "$IMAGE_INPUT" == http* ]]; then
# Upload by URL
UPLOAD_RESP=$(curl -s -X POST "https://graph.facebook.com/v20.0/${META_ACCOUNT}/adimages" \
-H "Authorization: Bearer ${META_TOKEN}" \
-F "url=${IMAGE_INPUT}")
else
# Upload by file (multipart)
UPLOAD_RESP=$(curl -s -X POST "https://graph.facebook.com/v20.0/${META_ACCOUNT}/adimages" \
-H "Authorization: Bearer ${META_TOKEN}" \
-F "filename=@${IMAGE_INPUT}")
fi
IMAGE_HASH=$(echo "$UPLOAD_RESP" | jq -r '.images | to_entries[0].value.hash // empty')
if [ -z "$IMAGE_HASH" ]; then
echo "Image upload failed: $(echo "$UPLOAD_RESP" | jq -r '.error.message // "unknown error"')"
exit 0
fi
# Resolve the Facebook Page ID. Meta's `object_story_spec.page_id` requires a
# real Page ID — the ad account ID (with `act_` stripped) is NOT a Page ID and
# the API call will fail. Require META_PAGE_ID in env or plugin prefs.
META_PAGE_ID="${META_PAGE_ID:-$(claude plugin config get meta_page_id 2>/dev/null || echo "")}"
if [ -z "$META_PAGE_ID" ]; then
echo "META_PAGE_ID is required to create an ad creative. Set it via:"
echo " claude plugin config set meta_page_id <your_fb_page_id>"
echo "Find your Page ID at https://www.facebook.com/<your-page>/about_profile_transparency"
exit 0
fi
# Step 2: Create ad creative
CREATIVE_RESP=$(curl -s -X POST "https://graph.facebook.com/v20.0/${META_ACCOUNT}/adcreatives" \
-H "Authorization: Bearer ${META_TOKEN}" \
-F "name=Creative for ${AD_NAME}" \
-F "object_story_spec={\"page_id\": \"${META_PAGE_ID}\", \"link_data\": {\"image_hash\": \"${IMAGE_HASH}\", \"message\": \"${PRIMARY_TEXT}\", \"name\": \"${HEADLINE}\"}}")
CREATIVE_ID=$(echo "$CREATIVE_RESP" | jq -r '.id // empty')
if [ -z "$CREATIVE_ID" ]; then
echo "Creative creation failed: $(echo "$CREATIVE_RESP" | jq -r '.error.message // "unknown error"')"
exit 0
fi
# Step 3: Create ad (status PAUSED — Rule 5)
curl -s -X POST "https://graph.facebook.com/v20.0/${META_ACCOUNT}/ads" \
-H "Authorization: Bearer ${META_TOKEN}" \
-F "name=${AD_NAME}" \
-F "adset_id=${ADSET_ID}" \
-F "creative={\"creative_id\": \"${CREATIVE_ID}\"}" \
-F "status=PAUSED" | jq '{id: .id, error: .error.message}'
Print: Ad created (ID: <ID>, creative: <CREATIVE_ID>, status: PAUSED). Enable via Meta Ads Manager when ready.
rules
List existing rules or create a new automation rule.
List rules:
curl -s "https://graph.facebook.com/v20.0/${META_ACCOUNT}/adrules_library?fields=name,status,evaluation_spec,execution_spec" \
-H "Authorization: Bearer ${META_TOKEN}" | jq '.data[] | {id: .id, name: .name, status: .status}'
Create rule (prompt via AskUserQuestion):
- Rule type:
[Pause low performers, Scale winners, Increase budget, Decrease budget]
For "Pause low performers":
# Pause ads where CPA > $50 and spend > $20 in last 7 days
curl -s -X POST "https://graph.facebook.com/v20.0/${META_ACCOUNT}/adrules_library" \
-H "Authorization: Bearer ${META_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "Pause high CPA ads",
"schedule_spec": {"schedule_type": "SEMI_HOURLY"},
"evaluation_spec": {
"evaluation_type": "SCHEDULE",
"filters": [
{"field": "cost_per_result", "value": [50], "operator": "GREATER_THAN"},
{"field": "spent", "value": [20], "operator": "GREATER_THAN"},
{"field": "entity_type", "value": ["AD"], "operator": "EQUAL"},
{"field": "time_preset", "value": ["LAST_7_DAYS"], "operator": "EQUAL"}
]
},
"execution_spec": {
"execution_type": "PAUSE"
},
"status": "ENABLED"
}' | jq '{id: .id, error: .error.message}'
For "Scale winners":
⚠️ Scope this to prospecting ad sets. A bare
purchase_roas > 3filter auto-scales retargeting ad sets too — whose ROAS is inflated by warm-audience demand capture (conversions that would have happened anyway), not incremental growth. Blanket-scaling them pours budget into demand you already own while starving prospecting, and the funnel contracts a month later. Add an ad-set-name/audience filter that excludes retargeting/remarketing (or restrict the rule to your prospecting ad sets), and confirm a winner's lift with a holdout before scaling on ROAS alone.
# Increase budget 20% for ad sets with ROAS > 3x in last 7 days
# NOTE: restrict to prospecting ad sets — see caveat above
curl -s -X POST "https://graph.facebook.com/v20.0/${META_ACCOUNT}/adrules_library" \
-H "Authorization: Bearer ${META_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "Scale winning ad sets",
"schedule_spec": {"schedule_type": "DAILY"},
"evaluation_spec": {
"evaluation_type": "SCHEDULE",
"filters": [
{"field": "purchase_roas", "value": [3], "operator": "GREATER_THAN"},
{"field": "entity_type", "value": ["ADSET"], "operator": "EQUAL"},
{"field": "time_preset", "value": ["LAST_7_DAYS"], "operator": "EQUAL"}
]
},
"execution_spec": {
"execution_type": "INCREASE_BUDGET",
"execution_options": [{"field": "budget_value", "value": "20", "operator": "PERCENTAGE"}]
},
"status": "ENABLED"
}' | jq '{id: .id, error: .error.message}'
Print: Rule created (ID: <ID>). Runs semi-hourly and will auto-pause ads with CPA > $50.
audiences
Create Custom Audience or Lookalike Audience.
Prompt via AskUserQuestion:
- Audience type:
[Custom — website, Custom — customer list, Lookalike, Skip]
Custom — website (Pixel-based):
curl -s -X POST "https://graph.facebook.com/v20.0/${META_ACCOUNT}/customaudiences" \
-H "Authorization: Bearer ${META_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "Website visitors — last 30 days",
"subtype": "WEBSITE",
"retention_days": 30,
"rule": {"inclusions": {"operator": "or", "rules": [{"event_sources": [{"id": "<PIXEL_ID>", "type": "pixel"}], "retention_seconds": 2592000, "filter": {"operator": "and", "filters": [{"field": "event", "operator": "eq", "value": "PageView"}]}}]}}
}' | jq '{id: .id, name: .name, error: .error.message}'
Note: Replace <PIXEL_ID> with actual pixel ID from Meta Events Manager.
Lookalike Audience (requires origin audience with min 100 matched profiles):
# Prompt for origin audience ID via AskUserQuestion (free text)
curl -s -X POST "https://graph.facebook.com/v20.0/${META_ACCOUNT}/customaudiences" \
-H "Authorization: Bearer ${META_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Lookalike — ${ORIGIN_AUDIENCE_NAME} 1%\",
\"subtype\": \"LOOKALIKE\",
\"origin_audience_id\": \"${ORIGIN_AUDIENCE_ID}\",
\"lookalike_spec\": {
\"country\": \"US\",
\"ratio\": 0.01,
\"type\": \"similarity\"
}
}" | jq '{id: .id, name: .name, error: .error.message}'
Print: Lookalike audience created (ID: <ID>). Typically takes 1-6 hours to populate.
advantage
Create an Advantage+ Shopping Campaign (AI-optimized).
Collect via AskUserQuestion:
- Daily budget in dollars (free text)
- Campaign name (free text)
Then confirm: "Create Advantage+ campaign '<NAME>' with $<BUDGET>/day?" options [Create, Cancel]
BUDGET_CENTS=$(awk "BEGIN {printf \"%d\", ${BUDGET_DOLLARS} * 100}")
curl -s -X POST "https://graph.facebook.com/v20.0/${META_ACCOUNT}/campaigns" \
-H "Authorization: Bearer ${META_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"${CAMPAIGN_NAME}\",
\"objective\": \"OUTCOME_SALES\",
\"status\": \"PAUSED\",
\"special_ad_categories\": [],
\"daily_budget\": ${BUDGET_CENTS},
\"smart_promotion_type\": \"AUTOMATED_SHOPPING_ADS\"
}" | jq '{id: .id, error: .error.message}'
Print: Advantage+ campaign "${CAMPAIGN_NAME}" created (ID: <ID>, status: PAUSED). Meta AI will optimize targeting and creative delivery once enabled.
analytics / ga4
Pull GA4 data via the Data API using gcloud ADC.
Get access token
GA4_TOKEN=$(gcloud auth application-default print-access-token 2>/dev/null)
Sessions + conversions (last 7d)
curl -s -X POST "https://analyticsdata.googleapis.com/v1beta/properties/${GA4_PROPERTY}:runReport" \
-H "Authorization: Bearer ${GA4_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [{"startDate": "7daysAgo", "endDate": "today"}],
"metrics": [
{"name": "sessions"},
{"name": "totalUsers"},
{"name": "conversions"},
{"name": "totalRevenue"},
{"name": "bounceRate"},
{"name": "averageSessionDuration"}
]
}' | jq '.rows[0].metricValues | {sessions: .[0].value, users: .[1].value, conversions: .[2].value, revenue: .[3].value, bounce_rate: .[4].value}'
Traffic sources (last 7d)
curl -s -X POST "https://analyticsdata.googleapis.com/v1beta/properties/${GA4_PROPERTY}:runReport" \
-H "Authorization: Bearer ${GA4_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [{"startDate": "7daysAgo", "endDate": "today"}],
"dimensions": [{"name": "sessionDefaultChannelGrouping"}],
"metrics": [{"name": "sessions"}, {"name": "conversions"}],
"orderBys": [{"metric": {"metricName": "sessions"}, "desc": true}],
"limit": 8
}' | jq '.rows[] | {channel: .dimensionValues[0].value, sessions: .metricValues[0].value, conversions: .metricValues[1].value}'
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 4k
- Forks
- 543
- Last commit
- Sep 2026
ahel review
K2info
exfiltration
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Item type
- skill
- Key
ops-marketing- Source
- github.com/davepoon/buildwithclaude
github.com/davepoon/buildwithclaude
Related picks
Skill · coreyhaines31
The pick for Adsnewsletter-monetization-planner
Skill · aaron-he-zhu
The pick for Newsletternewsletter-writer
Skill · cbrock84
The pick for Newsletteron-page-seo-checker
Skill · aaron-he-zhu
The pick for SEOseo-audit
Skill · aeonfun
The pick for SEOseo-geo
Skill · resciencelab
The pick for SEO