
Sms Marketing
- 65 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Launch SMS marketing campaigns with opt-in flows, audience segmentation, and TCPA/GDPR compliance to drive revenue via text.
About
Runs SMS marketing with compliant opt-in flows, audience segmentation, and TCPA/GDPR handling. A developer uses it to add a revenue-driving text-messaging channel.
- Opt-in flows with audience segmentation
- TCPA/GDPR compliance built in
Sms Marketing by the numbers
- 65 all-time installs (skills.sh)
- Ranked #525 of 853 Sales & Marketing skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill sms-marketingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 65 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Launch SMS marketing campaigns with opt-in flows, audience segmentation, and TCPA/GDPR compliance to drive revenue via text.
Files
SMS Marketing
Overview
SMS marketing achieves 98% open rates and click-through rates 5–10× higher than email, making it one of the highest-performing direct channels for ecommerce. However, SMS is heavily regulated — TCPA in the US requires explicit written consent, and violations carry fines up to $1,500 per message. Dedicated SMS apps (Postscript, Attentive, Klaviyo SMS) handle compliance, opt-in flows, and 10DLC registration automatically. Custom Twilio implementation is only needed for headless stores.
When to Use This Skill
- When launching an SMS marketing channel alongside existing email automation
- When needing TCPA-compliant opt-in flows at checkout and via pop-ups
- When wanting to segment SMS campaigns by purchase history, lifecycle stage, or location
- When sending transactional SMS (shipping updates) vs. marketing SMS to different opt-in lists
- When auditing an existing SMS program for compliance issues
Core Instructions
Step 1: Choose the right SMS platform
| Platform | Best For | Shopify | WooCommerce | BigCommerce | Price |
|---|---|---|---|---|---|
| Postscript | Shopify-native, segmentation + flows | App Store | — | — | Free tier; $100+/mo |
| Attentive | Mid-market, advanced A/B testing | App Store | Via integration | Via integration | $400+/mo |
| Klaviyo SMS | Already using Klaviyo for email | App Store | Plugin | App Marketplace | Adds to Klaviyo plan |
| SMSBump (Yotpo SMS) | WooCommerce + Shopify | App Store | Plugin | — | Free tier; $19+/mo |
| Twilio | Custom/headless, developer-controlled | Via API | Via API | Via API | Pay-per-message |
Recommendation: Use Postscript for Shopify and SMSBump for WooCommerce. If already using Klaviyo, add Klaviyo SMS to keep campaigns and flows in one platform. Use Twilio only for headless stores where you need full programmatic control.
Step 2: Set up SMS opt-in
---
Shopify with Postscript
1. Install Postscript from the Shopify App Store 2. Go to Postscript → Keywords and set up your opt-in keyword (e.g., "JOIN") — customers text this to your Postscript number to subscribe 3. Go to Postscript → Sign-up Units to add opt-in forms:
- Checkout opt-in: Postscript adds a checkbox at checkout automatically — configure the consent language under Settings → Checkout
- Pop-up: create a timed pop-up offering a discount (e.g., "Get 10% off — text JOIN to [number]")
4. Important compliance settings under Postscript → Settings → Compliance:
- Confirm the consent language is displayed: "By subscribing, you agree to receive marketing texts. Reply STOP to unsubscribe."
- Never pre-check the SMS opt-in box at checkout — TCPA requires un-checked by default
5. Go to Postscript → Flows to build automated sequences:
- Welcome series: triggered on opt-in — immediate welcome message + discount code
- Cart abandonment: triggered when Shopify detects an abandoned checkout (different from email; can send even without email)
- Browse abandonment: triggered by high-intent browsing + no purchase within 4 hours
---
WooCommerce with SMSBump
1. Install SMSBump (now Yotpo SMS) from the WordPress plugin directory 2. Go to SMSBump → Settings → Compliance and configure the checkout opt-in field 3. Go to SMSBump → Automations to enable:
- Cart abandonment SMS
- Order confirmation and shipping update SMS (transactional)
- Win-back SMS (customers who haven't purchased in 60+ days)
4. For GDPR compliance: SMSBump includes a double opt-in flow for EU subscribers — enable this under Settings → Compliance → Double Opt-in
---
BigCommerce with Klaviyo SMS
1. Install Klaviyo from the BigCommerce App Marketplace 2. Go to Klaviyo → SMS → Getting Started and complete the 10DLC registration (Klaviyo walks you through this) 3. Add an SMS opt-in field to your checkout via BigCommerce Admin → Store Setup → Checkout 4. Build SMS flows in Klaviyo → Flows — SMS can be added to any existing email flow as an additional channel
---
Custom / Headless
For headless stores, use Twilio. Compliance must be built into your application logic:
import twilio from 'twilio';
const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
async function sendMarketingSMS(phone: string, body: string, customerId: string): Promise<boolean> {
// ALWAYS check consent before sending — never skip this check
const consent = await db.smsConsent.findActive(phone, 'marketing');
if (!consent) {
console.warn(`SMS suppressed for ${phone} — no active marketing consent`);
return false;
}
// TCPA: no marketing SMS before 8am or after 9pm in recipient's local time
if (isQuietHours(phone, consent.zipCode)) {
await smsQueue.add('send', { phone, body, customerId }, { delay: msUntilMorning(phone, consent.zipCode) });
return false;
}
await client.messages.create({
from: process.env.TWILIO_PHONE_NUMBER,
to: phone,
body: `${body}\n\nReply STOP to unsubscribe`,
});
return true;
}
// Handle STOP/HELP/UNSTOP via Twilio webhook — required by carriers
export async function handleInboundSMS(req: Request, res: Response) {
const { From: from, Body: body } = req.body;
const keyword = body.trim().toUpperCase();
if (['STOP', 'STOPALL', 'UNSUBSCRIBE', 'CANCEL', 'END', 'QUIT'].includes(keyword)) {
await db.smsConsent.deactivateAll(from);
// Twilio also auto-handles STOP at the carrier level for registered numbers
} else if (keyword === 'HELP') {
// Required: explain how to opt out
await client.messages.create({
from: process.env.TWILIO_PHONE_NUMBER,
to: from,
body: `${process.env.STORE_NAME} alerts. Msg&Data rates apply. Reply STOP to unsubscribe.`,
});
} else if (['START', 'UNSTOP', 'YES'].includes(keyword)) {
await db.smsConsent.reactivate(from, 'marketing');
}
res.sendStatus(200);
}Important for custom Twilio implementations: Register your brand and campaign through the Campaign Registry (TCR) before sending. US carriers block unregistered 10DLC traffic. Twilio's console guides you through this under Messaging → Regulatory Compliance → 10DLC.
Step 3: Consent compliance requirements
TCPA (US) requirements — non-negotiable: 1. Opt-in checkbox must be unchecked by default at checkout 2. Consent language must appear adjacent to the checkbox (not in fine print) 3. Required consent language: "By checking this box, you agree to receive marketing texts from [Store Name] at the number provided. Message frequency varies. Message and data rates may apply. Reply STOP to unsubscribe." 4. You must honor STOP within 10 business days (dedicated SMS apps do this automatically) 5. No marketing SMS before 8am or after 9pm in the recipient's local timezone
GDPR (EU) requirements:
- Same opt-in standards as TCPA plus explicit consent documentation
- Provide a data export mechanism (consent record with timestamp, IP, exact consent language)
- Double opt-in is required for EU subscribers in many countries
All major SMS apps (Postscript, SMSBump, Klaviyo SMS) handle these compliance requirements automatically. If using Twilio directly, you must build this yourself.
Step 4: Campaign segmentation
The highest-ROI SMS segments:
| Segment | Message | Expected CTR |
|---|---|---|
| Cart abandoners (1–4 hours) | "You left something behind: [cart link]" | 15–25% |
| VIP customers (top 20% LTV) | Early access to sales and new arrivals | 20–30% |
| Lapsed customers (60–90 days) | Win-back offer with discount | 8–15% |
| Post-purchase cross-sell (7 days after delivery) | "Other customers who bought X also love Y" | 10–20% |
In Postscript: build segments under Postscript → Segments using order history, purchase frequency, and LTV filters. In Klaviyo SMS: add an SMS step to your existing email segments — the audience targeting is identical.
Step 5: Measure SMS performance
| Metric | Healthy Target | Where to Find |
|---|---|---|
| Opt-in rate at checkout | 5–15% of customers | App analytics |
| Click-through rate (campaigns) | 8–20% | App analytics |
| Opt-out rate per campaign | < 2% | App analytics — pause if above 3% |
| Revenue per subscriber per month | $3–$10 | Calculate: SMS-attributed revenue ÷ subscribers |
| Unsubscribe rate (total) | < 5% per month | App analytics |
Best Practices
- Separate marketing and transactional consent — customers who opt out of marketing SMS should still receive order confirmation and shipping texts; these are different consent types
- Never send more than 2–3 marketing SMS per week — SMS is the most intrusive channel; high frequency causes unsubscribes faster than any other channel
- Keep messages under 160 characters to avoid multi-part messages — emoji count as 2 characters and trigger UCS-2 encoding, halving the 160-character limit
- Always include STOP instructions in every marketing message — most apps do this automatically; verify it is there
- Register 10DLC before going live — US carriers block unregistered traffic; registration takes 1–2 weeks through your SMS platform
Common Pitfalls
| Problem | Solution |
|---|---|
| Messages blocked by carriers | Complete 10DLC brand and campaign registration through your SMS platform before sending |
| STOP not being honored | Dedicated SMS apps handle this automatically; for custom Twilio, configure the inbound webhook |
| Quiet hours violation | Use your SMS platform's built-in quiet hours setting; for Twilio, implement timezone-based scheduling |
| Checkbox pre-checked at checkout | This violates TCPA — change to unchecked by default immediately; it is a legal requirement, not a preference |
| Multi-part SMS for 161-character message | Count characters server-side before sending; use a URL shortener for cart links |
Related Skills
- @email-marketing-automation
- @cart-abandonment-recovery
- @cart-recovery-sms
- @push-notifications
- @customer-segmentation
{
"context": "Tests whether the agent collects SMS marketing consent correctly at checkout: unchecked checkbox by default, full audit trail storage, phone normalization to E.164, separation of marketing vs transactional consent types, and GDPR-ready export capability.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Checkbox not pre-checked",
"max_score": 12,
"description": "The opt-in checkbox is explicitly set to unchecked by default (e.g., defaultChecked={false} or checked={false} or equivalent) — NOT left to browser defaults or set to true"
},
{
"name": "Consent timestamp stored",
"max_score": 8,
"description": "The consent record includes a timestamp field (e.g., consentGivenAt, created_at, or similar) capturing when consent was given"
},
{
"name": "IP address stored",
"max_score": 8,
"description": "The consent record stores the user's IP address"
},
{
"name": "Consent source stored",
"max_score": 8,
"description": "The consent record stores how/where consent was collected (e.g., 'checkout', 'popup', 'keyword', or equivalent source field)"
},
{
"name": "Consent type stored",
"max_score": 8,
"description": "The consent record distinguishes between 'marketing' and 'transactional' consent types — both types are represented as distinct values"
},
{
"name": "E.164 phone format",
"max_score": 10,
"description": "Phone numbers are normalized to E.164 format (starting with '+' followed by country code and number, e.g. +12125551234) before being stored"
},
{
"name": "Marketing vs transactional separation",
"max_score": 12,
"description": "Marketing consent and transactional consent are stored or queried as separate types — the implementation does NOT conflate them into a single boolean flag"
},
{
"name": "STOP language in opt-in UI",
"max_score": 8,
"description": "The opt-in UI or consent language includes a reference to replying STOP (or similar keyword) to unsubscribe"
},
{
"name": "GDPR export includes required fields",
"max_score": 10,
"description": "The consent export or audit trail includes at minimum: phone, consentType, consentSource, consentGivenAt, and ipAddress fields"
},
{
"name": "revokedAt in GDPR export",
"max_score": 8,
"description": "The consent export includes a revocation timestamp field (revokedAt or equivalent) that can be null when consent is still active"
},
{
"name": "Privacy policy linked",
"max_score": 8,
"description": "The opt-in UI includes a link or reference to a privacy policy"
}
]
}
SMS Opt-In for Checkout Page
Problem/Feature Description
A direct-to-consumer apparel brand is launching a text messaging channel alongside their email program. Their legal team has flagged that their previous SMS list was collected improperly and they need to rebuild it from scratch with clean, provable consent. The compliance officer has made it clear that they must be able to demonstrate — in writing if challenged — exactly when, where, and how each subscriber consented to receive texts.
The team needs a checkout opt-in component for their React/TypeScript storefront and the backend logic to store consent records in a way that will hold up to legal scrutiny. They also serve customers in the EU and need to be able to produce a complete consent history for any customer on request.
Output Specification
Produce the following TypeScript source files in your working directory:
SmsOptIn.tsx— A React component that renders the SMS opt-in field for a checkout form. The component should accept a phone number and a callback for when the user toggles the checkbox.consentService.ts— Backend service containing:- A function to record SMS consent in a database (you can use a mock
dbobject — no real database connection is needed) - A function to export a customer's full SMS consent history (for GDPR data access requests)
README.md— A short description (2–3 paragraphs) of the consent model used, explaining how it handles different consent types and what data is stored for audit purposes.
{
"context": "Tests whether the agent implements an inbound SMS webhook that correctly handles the full set of opt-out and opt-in keywords, routes non-keyword messages to support, and correctly handles transactional SMS with its own separate opt-out check distinct from marketing consent.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Full STOP keyword set",
"max_score": 10,
"description": "The webhook handles all of: STOP, STOPALL, UNSUBSCRIBE, CANCEL, END, QUIT as opt-out keywords (not just 'STOP' alone)"
},
{
"name": "Deactivate consent on STOP",
"max_score": 10,
"description": "When a STOP-family keyword is received, the implementation deactivates ALL consent records for that phone number"
},
{
"name": "TwiML response on STOP",
"max_score": 8,
"description": "The STOP handler responds with a TwiML MessagingResponse (not a plain JSON or text response) confirming unsubscription"
},
{
"name": "HELP keyword handled",
"max_score": 8,
"description": "The webhook has a dedicated handler for the HELP keyword that responds with store name, messaging disclosure, and STOP instructions"
},
{
"name": "Full re-subscribe keyword set",
"max_score": 8,
"description": "The webhook handles all of: START, UNSTOP, YES as re-subscribe keywords"
},
{
"name": "Reactivate consent on START",
"max_score": 8,
"description": "When a START-family keyword is received, the implementation reactivates marketing consent for that phone number"
},
{
"name": "Non-keyword routed to support",
"max_score": 8,
"description": "Inbound messages that are NOT one of the recognized keywords are routed to a support queue rather than receiving an automated reply"
},
{
"name": "Keyword match is case-insensitive",
"max_score": 6,
"description": "Keywords are compared case-insensitively (e.g., 'stop', 'Stop', 'STOP' all trigger the opt-out flow)"
},
{
"name": "Transactional opt-out separate",
"max_score": 10,
"description": "The transactional SMS send function checks a transactional-specific opt-out (NOT marketing consent) — the check uses a 'transactional' type distinct from 'marketing'"
},
{
"name": "Transactional no opt-in required",
"max_score": 10,
"description": "The transactional SMS send does NOT require an active marketing opt-in — it only checks whether the customer has opted OUT of transactional messages"
},
{
"name": "STOP in transactional message",
"max_score": 8,
"description": "The transactional SMS message body includes an opt-out instruction (e.g., 'Reply STOP to opt out of order texts')"
},
{
"name": "Phone normalized in transactional",
"max_score": 6,
"description": "The transactional SMS send normalizes the phone number to E.164 format before passing it to Twilio"
}
]
}
Inbound SMS Handler and Transactional Notifications
Problem/Feature Description
A furniture e-commerce company has set up a Twilio number for SMS marketing but customers have started texting back with a variety of responses — some trying to opt out, some asking for help, and some with general questions. Carrier guidelines require the company to handle certain keywords automatically and consistently or risk having their messages filtered. The customer support manager also wants to make sure that general replies don't get lost.
Separately, the operations team wants to send shipping confirmation texts to customers who haven't opted into marketing — they assume that since it's operational information and not a promotion, the same rules don't apply. The engineering team needs to implement both pieces correctly: a webhook that handles inbound messages according to carrier requirements, and a transactional notification sender that plays by its own distinct rules.
Output Specification
Produce the following TypeScript source files:
inboundWebhook.ts— An Express-style POST handler (/api/sms/inbound) that processes inbound messages from Twilio's webhook. You can mockdb,supportQueue, andprocess.envvalues.transactionalSms.ts— A function that sends a shipping notification SMS, using a mockdband Twilio client.README.md— A short explanation (1–2 paragraphs) of how inbound keyword handling works and how the transactional consent model differs from marketing consent.
Use TypeScript. No real database or Twilio connection is needed — mock the external dependencies.
{
"context": "Tests whether the agent implements a marketing SMS send function with all required compliance checks: opt-in verification, quiet hours enforcement with timezone lookup, STOP instruction in message body, rate limiting, and message length validation. Also covers package choices and logging.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Uses twilio package",
"max_score": 8,
"description": "The implementation imports and uses the 'twilio' npm package (not an alternative SMS provider SDK or raw HTTP calls)"
},
{
"name": "Opt-in check before send",
"max_score": 12,
"description": "The send function queries for active marketing consent before sending, and suppresses/skips the send if no active consent is found"
},
{
"name": "Quiet hours check",
"max_score": 10,
"description": "The send function checks whether the current time is within quiet hours for the recipient and does NOT send during quiet hours (before 8am or after 9pm local time)"
},
{
"name": "Quiet hours queuing",
"max_score": 8,
"description": "Messages that fall in quiet hours are queued/deferred for delivery at the next allowed time (9am) rather than simply dropped"
},
{
"name": "Recipient timezone from zip code",
"max_score": 8,
"description": "Quiet hours are determined using the recipient's local timezone derived from their zip code (uses zipcode-to-timezone or equivalent zip-to-timezone lookup)"
},
{
"name": "Default timezone fallback",
"max_score": 6,
"description": "When the recipient's zip code is unavailable, the implementation falls back to 'America/New_York' as the default timezone"
},
{
"name": "STOP instruction in body",
"max_score": 10,
"description": "Every outgoing marketing SMS message body includes a 'Reply STOP to unsubscribe' instruction (or equivalent STOP opt-out text)"
},
{
"name": "Message length check",
"max_score": 8,
"description": "The implementation validates or enforces that message content stays within 160 characters, OR includes a comment/documentation warning about the 160-character limit"
},
{
"name": "Rate limiting delay",
"max_score": 8,
"description": "The bulk send loop includes a delay between messages (approximately 100ms) to stay within carrier/Twilio rate limits"
},
{
"name": "SMS log written",
"max_score": 8,
"description": "After a successful send, the implementation writes a log record containing at minimum the twilioSid (message SID) and sent timestamp"
},
{
"name": "10DLC / short code mentioned",
"max_score": 6,
"description": "The implementation or its documentation mentions 10DLC registration requirement OR the use of short codes for high-volume sending (>1,000 messages/day)"
},
{
"name": "date-fns-tz for timezone conversion",
"max_score": 8,
"description": "The timezone conversion for quiet hours uses date-fns-tz (utcToZonedTime or equivalent) rather than manual UTC offset arithmetic"
}
]
}
Promotional SMS Campaign Sender
Problem/Feature Description
A mid-sized e-commerce retailer wants to run flash sale campaigns via SMS. Their marketing team sends promotions to thousands of subscribers at a time, and they have run into problems in the past: some customers complained they received texts at 6am, a carrier blocked a batch for violating rate limits, and their legal team is concerned about messages sent to customers who had opted out weeks earlier.
The engineering team has been asked to build a reliable, compliant campaign sender that handles all of these edge cases automatically. The system needs to work with Twilio, respect when customers can legally be messaged based on their location, and not overwhelm the carrier. Detailed records of every message sent are required for compliance audits.
Output Specification
Produce the following TypeScript source files:
smsSender.ts— The core send function that sends a single marketing SMS to a subscriber, plus any helper functions it depends on (timezone handling, phone normalization, etc.)campaignSender.ts— A function that sends a message to a list of phone numbers (representing a segment), using the send function aboveREADME.md— Documentation covering: the compliance approach taken (delivery timing restrictions, throughput management), and any infrastructure or registration requirements that must be completed before the system can go live
The implementation should use mock objects for the database (db) and queue (smsQueue) — no real connections are needed.
{
"name": "finsi/sms-marketing",
"version": "0.1.0",
"summary": "SMS campaigns with opt-in, segmentation, and compliance (TCPA/GDPR)",
"skills": {
"sms-marketing": {
"path": "SKILL.md"
}
}
}