Skip to content
All essays
CraftJanuary 15, 20269 min

SMS Marketing Strategies That Drive Engagement

Learn proven SMS marketing strategies including segmentation, personalization, timing optimization, and compliance with regulations

Ü
Ümit Uz
Mobile & Full Stack Developer

SMS marketing boasts incredible 98% open rates and 45% response rates. But success requires more than just blasting messages to your list. This guide covers proven strategies that drive engagement while respecting subscribers and staying compliant.

Building Your SMS List

Permission-Based Growth

Never buy SMS lists. Always obtain explicit permission:

typescript
// lib/sms-consent.ts
export async function captureSMSConsent(userId: string, phoneNumber: string) {
  // Record consent with timestamp and IP
  await db.smsConsent.create({
    data: {
      userId,
      phoneNumber,
      consentedAt: new Date(),
      ipAddress: getClientIP(),
      method: 'web_form', // or 'checkout', 'competition', etc.
    },
  });

  // Send confirmation
  await sendSMS(
    phoneNumber,
    'You're now subscribed to our SMS updates. Reply STOP anytime to opt out.'
  );
}

Incentivized Signups

Offer compelling reasons to subscribe:

  • Exclusive discounts
  • Early access to sales
  • Product updates
  • Insider information

SMS Segmentation

Demographic Segmentation

typescript
interface SMSSegment {
  name: string;
  condition: (user: User) => boolean;
}

const segments: SMSSegment[] = [
  {
    name: 'VIP Customers',
    condition: (user) => user.totalPurchases > 1000,
  },
  {
    name: 'Recent Purchasers',
    condition: (user) => {
      const lastPurchase = new Date(user.lastPurchaseDate);
      const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
      return lastPurchase > thirtyDaysAgo;
    },
  },
  {
    name: 'Cart Abandoners',
    condition: (user) => user.hasAbandonedCart,
  },
];

Behavioral Triggers

Send based on user actions:

typescript
export async function triggerBehavioralSMS(userId: string, event: string) {
  const user = await db.users.findUnique({ where: { id: userId } });

  switch (event) {
    case 'cart_abandoned':
      await sendCartReminder(user);
      break;
    case 'purchase_completed':
      await sendPurchaseConfirmation(user);
      break;
    case 'order_shipped':
      await sendShippingNotification(user);
      break;
    case 'product_viewed_multiple_times':
      await sendProductRecommendation(user);
      break;
  }
}

Personalization Strategies

Dynamic Content

typescript
export async function personalizeMessage(
  userId: string,
  template: string
): Promise<string> {
  const user = await db.users.findUnique({
    where: { id: userId },
    include: {
      preferences: true,
      recentPurchases: true,
    },
  });

  let personalized = template;

  // Replace basic placeholders
  personalized = personalized.replace(/\{firstName\}/g, user.firstName);
  personalized = personalized.replace(/\{lastName\}/g, user.lastName);

  // Replace dynamic content
  personalized = personalized.replace(
    /\{recommendedProduct\}/g,
    user.recentPurchases[0]?.product.name || 'our latest product'
  );

  return personalized;
}

Time Zone Optimization

typescript
export async function optimizeSendTime(phoneNumber: string, message: string) {
  const timeZone = await detectTimeZone(phoneNumber);
  const localTime = getCurrentTimeInZone(timeZone);

  // Optimal send times: 9 AM - 12 PM local time
  if (localTime.getHours() >= 9 && localTime.getHours() < 12) {
    return await sendSMS(phoneNumber, message);
  }

  // Schedule for optimal time
  const optimalSendTime = calculateOptimalSendTime(localTime);
  return await scheduleSMS(phoneNumber, message, optimalSendTime);
}

Campaign Types

Flash Sales

typescript
export async function sendFlashSale(
  segment: string,
  discount: number,
  endTime: Date
) {
  const users = await getUsersBySegment(segment);

  for (const user of users) {
    const message = `🚨 FLASH SALE: ${discount}% off everything! Ends at ${formatTime(endTime)}. Shop now: ${shortenUrl(shopUrl)}`;
    
    await sendSMS(user.phoneNumber, message);
  }
}

Exclusive Offers

typescript
export async function sendExclusiveOffer(
  userId: string,
  offerCode: string,
  discount: number
) {
  const message = `🎁 Exclusive offer just for you: Use code ${offerCode} for ${discount}% off your next order!`;

  return await sendSMS(userId, message);
}

Event Reminders

typescript
export async function sendEventReminder(
  userId: string,
  event: Event
) {
  const message = `Reminder: ${event.name} is tomorrow at ${formatTime(event.startTime)}. See you there!`;

  return await sendSMS(userId, message);
}

Compliance Best Practices

TCPA Compliance

Follow Telephone Consumer Protection Act rules:

  • Get explicit written consent
  • Include clear opt-out instructions
  • Honor opt-out requests immediately
  • Send only during reasonable hours (8 AM - 9 PM)
typescript
export async function ensureCompliance(phoneNumber: string, message: string) {
  // Check if user has consented
  const consent = await db.smsConsent.findFirst({
    where: { phoneNumber, active: true },
  });

  if (!consent) {
    throw new Error('No consent found for this number');
  }

  // Check if user has opted out
  const optOut = await db.smsOptOut.findFirst({
    where: { phoneNumber },
  });

  if (optOut) {
    throw new Error('User has opted out');
  }

  // Add opt-out instructions
  const compliantMessage = `${message}\
\
Reply STOP to opt out`;

  return await sendSMS(phoneNumber, compliantMessage);
}

Measurement and Analytics

Track Key Metrics

typescript
export async function trackSMSMetrics(campaignId: string) {
  const messages = await db.sMSMessages.findMany({
    where: { campaignId },
  });

  const sent = messages.length;
  const delivered = messages.filter(m => m.status === 'delivered').length;
  const failed = messages.filter(m => m.status === 'failed').length;

  // Track conversions
  const conversions = await db.conversions.count({
    where: {
      campaignId,
    },
  });

  return {
    sent,
    delivered,
    deliveryRate: (delivered / sent) * 100,
    failed,
    failureRate: (failed / sent) * 100,
    conversions,
    conversionRate: (conversions / delivered) * 100,
  };
}

A/B Testing

Test Messages

typescript
export async function abTestSMS(
  segment: string,
  messageA: string,
  messageB: string
) {
  const users = await getUsersBySegment(segment);

  // Split 50/50
  const midpoint = Math.floor(users.length / 2);
  const groupA = users.slice(0, midpoint);
  const groupB = users.slice(midpoint);

  // Send messages
  for (const user of groupA) {
    await sendSMS(user.phoneNumber, messageA);
  }

  for (const user of groupB) {
    await sendSMS(user.phoneNumber, messageB);
  }

  // Track results
  return {
    groupASize: groupA.length,
    groupBSize: groupB.length,
  };
}

Best Practices

1. Keep It Short

SMS has a 160-character limit. Be concise:

  • ✅ "SALE: 50% off everything today only!"
  • ❌ "We're having a massive sale with discounts up to 50% off everything in our store, but only for today..."

2. Create Urgency

Use time-sensitive language:

  • "Ends tonight"
  • "Last chance"
  • "Only 2 hours left"

3. Use Emojis

Emojis increase engagement by 25%:

  • 🎉 for celebrations
  • ⚡ for urgency
  • 🎁 for offers

4. Include Clear CTAs

Tell recipients exactly what to do:

  • "Shop now: [link]"
  • "Reply YES to confirm"
  • "Call 555-123-4567"

5. Timing Matters

Send when users are most likely to read:

  • 9 AM - 12 PM: Highest engagement
  • Avoid late nights and early mornings

Conclusion

SMS marketing drives incredible engagement when done right. Focus on:

  • Permission-based lists for compliance
  • Segmentation for relevance
  • Personalization for connection
  • Optimal timing for impact
  • Compliance for trust

Remember: SMS is personal. Respect your subscribers, provide value, and they'll reward you with engagement and loyalty.

The key is balance: frequent enough to stay top-of-mind, but not so frequent that you become annoying. Monitor your metrics and adjust accordingly.

Enjoyed this essay? Share it.

Related essays

Next essay
Ember.js Fundamentals: Building Modern Web Applications