Read-only: audits email and SMS marketing consent status across the customer base for compliance and segmentation.
Scans all customer records and reports the breakdown of email and SMS marketing consent status (subscribed, unsubscribed, pending, never asked). Used for compliance audits, GDPR/CAN-SPAM reviews, and understanding the addressable marketing audience. Read-only — no mutations.
shopify store auth --store <domain> --scopes read_customersread_customers| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| store | string | yes | — | Store domain (e.g., mystore.myshopify.com) |
| channel | string | no | both | Consent channel to audit: email, sms, or both |
| format | string | no | human | Output format: human or json |
ℹ️ Read-only skill — no mutations are executed. Safe to run at any time.
OPERATION: customers — query
Inputs: first: 250, select emailMarketingConsent { marketingState, consentUpdatedAt }, smsMarketingConsent { marketingState, consentUpdatedAt }, pagination cursor
Expected output: All customers with consent states; paginate until hasNextPage: false
Count customers by consent state for each channel
Calculate: addressable audience (subscribed), at-risk (pending), unreachable (unsubscribed/not asked)
# customers:query — validated against api_version 2025-01
query MarketingConsentAudit($after: String) {
customers(first: 250, after: $after) {
edges {
node {
id
displayName
defaultEmailAddress {
emailAddress
}
emailMarketingConsent {
marketingState
consentUpdatedAt
marketingOptInLevel
}
smsMarketingConsent {
marketingState
consentUpdatedAt
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
Claude MUST emit the following output at each stage. This is mandatory.
On start, emit:
╔══════════════════════════════════════════════╗
║ SKILL: Marketing Consent Report ║
║ Store: <store domain> ║
║ Started: <YYYY-MM-DD HH:MM UTC> ║
╚══════════════════════════════════════════════╝
After each step, emit:
[N/TOTAL] <QUERY|MUTATION> <OperationName>
→ Params: <brief summary of key inputs>
→ Result: <count or outcome>
On completion, emit:
For format: human (default):
══════════════════════════════════════════════
MARKETING CONSENT REPORT
Total customers: <n>
Email Marketing:
Subscribed: <n> (<pct>%) ← addressable
Unsubscribed: <n> (<pct>%)
Pending: <n> (<pct>%)
Not asked: <n> (<pct>%)
SMS Marketing:
Subscribed: <n> (<pct>%)
Unsubscribed: <n> (<pct>%)
Not asked: <n> (<pct>%)
Output: consent_audit_<date>.csv
══════════════════════════════════════════════
For format: json, emit:
{
"skill": "marketing-consent-report",
"store": "<domain>",
"total_customers": 0,
"email": { "subscribed": 0, "unsubscribed": 0, "pending": 0, "not_asked": 0 },
"sms": { "subscribed": 0, "unsubscribed": 0, "not_asked": 0 },
"output_file": "consent_audit_<date>.csv"
}
CSV file consent_audit_<YYYY-MM-DD>.csv with columns:
customer_id, email, email_marketing_state, email_consent_updated_at, sms_marketing_state, sms_consent_updated_at
| Error | Cause | Recovery |
|---|---|---|
THROTTLED | API rate limit exceeded | Wait 2 seconds, retry up to 3 times |
| No customers | Empty store | Exit with 0 results |
marketingOptInLevel: SINGLE_OPT_IN may require a re-consent campaign depending on your legal basis for processing.