> ## Documentation Index
> Fetch the complete documentation index at: https://help.hoopai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send an SMS blast to your contact list

> Learn how to send a bulk SMS message to your entire contact list, a smart list, or specific contacts — immediately, scheduled, or in drip batches.

export const CourseTracker = ({courseId, lessonId, videoId}) => {
  const [progress, setProgress] = useState({});
  const [expanded, setExpanded] = useState(false);
  useEffect(() => {
    setProgress(loadProgress());
    document.body.setAttribute("data-academy", "true");
    return () => document.body.removeAttribute("data-academy");
  }, []);
  const course = COURSES[courseId];
  if (!course) return null;
  const lessons = course.lessons;
  const currentIndex = lessons.findIndex(l => l.id === lessonId);
  const completedCount = lessons.filter(l => !!progress[courseId + "/" + l.id]).length;
  const percent = lessons.length > 0 ? Math.round(completedCount / lessons.length * 100) : 0;
  const isCurrentDone = !!progress[courseId + "/" + lessonId];
  const prev = currentIndex > 0 ? lessons[currentIndex - 1] : null;
  const next = currentIndex < lessons.length - 1 ? lessons[currentIndex + 1] : null;
  const totalDuration = formatTotalDuration(lessons);
  const handleToggle = () => {
    const key = courseId + "/" + lessonId;
    const updated = {
      ...progress
    };
    if (updated[key]) {
      delete updated[key];
    } else {
      updated[key] = Date.now();
    }
    setProgress(updated);
    persistProgress(updated);
  };
  const lessonPath = lesson => "/academy/" + course.dir + "/" + lesson.id;
  const videoEmbed = videoId ? <div style={{
    position: "relative",
    width: "100%",
    paddingBottom: "56.25%",
    borderRadius: "var(--ds-radius-lg)",
    overflow: "hidden",
    marginBottom: "24px",
    background: "#000"
  }}>
      <iframe src={"https://www.youtube-nocookie.com/embed/" + videoId + "?rel=0"} title="Lesson video" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen style={{
    position: "absolute",
    top: 0,
    left: 0,
    width: "100%",
    height: "100%",
    border: "none"
  }} />
    </div> : null;
  const lessonList = lessons.map(lesson => {
    const isActive = lesson.id === lessonId;
    const isDone = !!progress[courseId + "/" + lesson.id];
    const itemStyle = {
      display: "flex",
      alignItems: "center",
      gap: "8px",
      padding: "10px 16px",
      borderTop: "1px solid var(--academy-border-subtle, #f3f4f6)",
      background: isActive ? "var(--academy-active-bg, #f9fafb)" : "transparent",
      textDecoration: "none",
      cursor: isActive ? "default" : "pointer",
      color: "inherit",
      transition: "background 0.15s"
    };
    const titleStyle = {
      flex: 1,
      fontSize: "13px",
      fontWeight: isActive ? 600 : 400,
      color: isActive ? "var(--academy-text, #111827)" : "var(--academy-text-secondary, #6b7280)",
      overflow: "hidden",
      textOverflow: "ellipsis",
      whiteSpace: "nowrap",
      lineHeight: "1.4"
    };
    const durationStyle = {
      fontSize: "12px",
      color: "var(--academy-text-muted, #9ca3af)",
      whiteSpace: "nowrap"
    };
    const inner = <>
        {isDone ? <CheckCircle /> : <VideoIcon />}
        <span style={titleStyle}>{lesson.title}</span>
        <span style={durationStyle}>{lesson.duration}</span>
      </>;
    if (isActive) {
      return <div key={lesson.id} style={itemStyle}>
          {inner}
        </div>;
    }
    return <a key={lesson.id} href={lessonPath(lesson)} style={itemStyle}>
        {inner}
      </a>;
  });
  return <div className="not-prose" id="academy-course-tracker">
      {videoEmbed}
      <div className="academy-tracker" style={{
    fontFamily: "Inter, -apple-system, BlinkMacSystemFont, sans-serif",
    borderRadius: "var(--ds-radius-lg)",
    border: "1px solid var(--academy-border, #e5e7eb)",
    background: "var(--academy-bg, #ffffff)",
    overflow: "hidden",
    marginBottom: "24px"
  }}>
        {}
        <div style={{
    padding: "16px 16px 0"
  }}>
          <h3 style={{
    margin: 0,
    fontSize: "16px",
    fontWeight: 600,
    lineHeight: "1.4",
    color: "var(--academy-text, #111827)"
  }}>
            {course.title}
          </h3>
          <div style={{
    display: "flex",
    gap: "12px",
    marginTop: "8px"
  }}>
            <span style={{
    display: "flex",
    alignItems: "center",
    gap: "5px",
    fontSize: "12px",
    color: "var(--academy-text-secondary, #6b7280)",
    padding: "3px 8px 3px 6px",
    borderRadius: "var(--ds-radius-sm)",
    border: "1px solid var(--academy-border, #e5e7eb)"
  }}>
              <BookIcon /> {lessons.length} lessons
            </span>
            <span style={{
    display: "flex",
    alignItems: "center",
    gap: "5px",
    fontSize: "12px",
    color: "var(--academy-text-secondary, #6b7280)",
    padding: "3px 8px 3px 6px",
    borderRadius: "var(--ds-radius-sm)",
    border: "1px solid var(--academy-border, #e5e7eb)"
  }}>
              <ClockIcon /> Approx. {totalDuration}
            </span>
          </div>
        </div>

        {}
        <div style={{
    padding: "14px 16px 16px"
  }}>
          <div style={{
    display: "flex",
    justifyContent: "space-between",
    fontSize: "12px",
    color: "var(--academy-text-secondary, #6b7280)"
  }}>
            <span>Your progress</span>
            <span style={{
    fontWeight: 500,
    color: "var(--academy-text, #111827)"
  }}>
              {percent}%
            </span>
          </div>
          <div style={{
    height: "6px",
    borderRadius: "var(--ds-radius-full)",
    background: "var(--academy-track, #f3f4f6)",
    marginTop: "8px",
    overflow: "hidden"
  }}>
            <div style={{
    height: "100%",
    borderRadius: "var(--ds-radius-full)",
    background: "var(--academy-progress, #3b82f6)",
    transition: "width 0.5s cubic-bezier(0.4, 0, 0.2, 1)",
    width: percent + "%"
  }} />
          </div>
        </div>

        {}
        <div className="academy-lessons-desktop">{lessonList}</div>

        {}
        <div className="academy-lessons-mobile">
          <button onClick={() => setExpanded(!expanded)} aria-expanded={expanded} style={{
    display: "flex",
    alignItems: "center",
    justifyContent: "space-between",
    padding: "12px 16px",
    cursor: "pointer",
    borderTop: "1px solid var(--academy-border-subtle, #f3f4f6)",
    background: "transparent",
    border: "none",
    borderTopStyle: "solid",
    borderTopWidth: "1px",
    borderTopColor: "var(--academy-border-subtle, #f3f4f6)",
    width: "100%",
    textAlign: "left",
    color: "var(--academy-text-secondary, #6b7280)",
    fontSize: "13px",
    fontWeight: 500,
    fontFamily: "inherit"
  }}>
            <span>
              {expanded ? "Hide lessons" : "Show all " + lessons.length + " lessons"}
            </span>
            <ChevronDown open={expanded} />
          </button>
          {expanded && lessonList}
        </div>

        {}
        <div style={{
    display: "flex",
    alignItems: "center",
    justifyContent: "space-between",
    borderTop: "1px solid var(--academy-border, #e5e7eb)",
    padding: "10px 16px"
  }}>
          {prev ? <a href={lessonPath(prev)} style={{
    fontSize: "13px",
    color: "var(--academy-text-secondary, #6b7280)",
    textDecoration: "none",
    display: "flex",
    alignItems: "center",
    gap: "4px"
  }}>
              ‹ Previous
            </a> : <div />}
          <button onClick={handleToggle} style={{
    fontSize: "13px",
    fontWeight: 500,
    cursor: "pointer",
    padding: "6px 14px",
    borderRadius: "var(--ds-radius-md)",
    border: isCurrentDone ? "1px solid var(--academy-border, #e5e7eb)" : "none",
    background: isCurrentDone ? "var(--academy-bg, #ffffff)" : "var(--academy-btn-bg, #111827)",
    color: isCurrentDone ? "var(--academy-complete, #10b981)" : "var(--academy-btn-text, #ffffff)",
    display: "flex",
    alignItems: "center",
    gap: "6px",
    transition: "all 0.2s",
    lineHeight: "1.4",
    fontFamily: "inherit"
  }}>
            {isCurrentDone ? <>
                <CheckCircle /> Completed
              </> : "Mark as completed"}
          </button>
          {next ? <a href={lessonPath(next)} style={{
    fontSize: "13px",
    color: "var(--academy-text-secondary, #6b7280)",
    textDecoration: "none",
    display: "flex",
    alignItems: "center",
    gap: "4px"
  }}>
              Next ›
            </a> : <div />}
        </div>
      </div>
    </div>;
};

<CourseTracker courseId="sms-phone-numbers" lessonId="send-an-sms-blast-to-your-contact-list" />

SMS blasts let you reach your entire audience with a single message in seconds. With a 98% open rate and replies coming straight into your Conversations inbox, SMS blasts are one of the most powerful tools for driving immediate engagement and sales — with no ad spend required.

<Frame caption="The Send an SMS Blast lesson in the HoopAI Academy">
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/hoopai-84ec0cdc/images/academy-sms-blast.png" alt="Send an SMS blast article" />
</Frame>

## Why this matters

SMS messages have a 98% open rate versus email's 20%, and most texts are read within 3 minutes of delivery. An SMS blast to your contact list generates engagement — and often direct sales — almost every time you send one, with zero ad spend.

## How to send an SMS blast

<Steps>
  <Step title="Navigate to Marketing or Contacts">
    Go to **Marketing** > **SMS**, or use **Bulk Actions** from the **Contacts** section. Both paths let you send an SMS blast to your list.

    <Frame caption="The SMS marketing section in the HoopAI Platform">
      <img src="https://mintlify.s3.us-west-1.amazonaws.com/hoopai-84ec0cdc/images/academy-sms-blast.png" alt="SMS marketing navigation" />
    </Frame>
  </Step>

  <Step title="Create a new SMS campaign">
    Click **New SMS Campaign** or **New Bulk Action** and give your campaign a descriptive name so you can track it later.
  </Step>

  <Step title="Choose your recipients">
    Select who will receive the message. You can choose:

    * Your entire contact list
    * A specific Smart List (filtered segment)
    * Individually selected contacts

    <Frame caption="Selecting recipients for your SMS blast">
      <img src="https://mintcdn.com/hoopai-84ec0cdc/gyU98wGhFXcTdqFf/images/academy-onboarding-import-contacts.png?fit=max&auto=format&n=gyU98wGhFXcTdqFf&q=85&s=02abfd10adb996867d3c6e9fb874b771" alt="SMS recipient selection" width="1536" height="826" data-path="images/academy-onboarding-import-contacts.png" />
    </Frame>
  </Step>

  <Step title="Write your message">
    Compose your SMS. Keep it concise — SMS messages are best under 160 characters per segment to avoid multi-part messages that increase costs.

    Use **custom fields** to personalize each message. For example, `{{contact.first_name}}` inserts the recipient's first name automatically.

    Optionally include a **trigger link** for click tracking or to fire a workflow when the contact clicks your link.

    <Tip>
      Start with the contact's name, lead with the value offer, and include a clear call to action with a link. Example: "Hey `{{contact.first_name}}`, we're running a special this week only! Claim your offer here: \[link]"
    </Tip>
  </Step>

  <Step title="Choose your send timing">
    Select one of three delivery options:

    * **Send now:** Delivers the message immediately to all recipients
    * **Schedule:** Sets a specific date and time for delivery
    * **Drip send:** Sends messages in batches over time (e.g., 100 per 15 minutes) to manage sending volume

    <Frame caption="Choosing send timing — immediate, scheduled, or drip">
      <img src="https://mintlify.s3.us-west-1.amazonaws.com/hoopai-84ec0cdc/images/academy-sms-call-tracking.png" alt="SMS send timing options" />
    </Frame>
  </Step>

  <Step title="Review and send">
    Review your message content, recipient count, and send settings carefully. Click **Send** (or **Schedule**) to launch your campaign.
  </Step>

  <Step title="Track results">
    After sending, view your campaign statistics:

    * **Delivered:** How many messages were successfully delivered
    * **Failed:** Messages that could not be delivered
    * **Clicked:** How many contacts clicked a link in the message

    Replies from contacts appear automatically in your **Conversations** inbox.

    <Frame caption="Tracking SMS blast delivery and click statistics">
      <img src="https://mintcdn.com/hoopai-84ec0cdc/gyU98wGhFXcTdqFf/images/academy-quick-start-conversations.png?fit=max&auto=format&n=gyU98wGhFXcTdqFf&q=85&s=b35ece2a2ead2ac8c92820a62c044b70" alt="SMS blast statistics" width="1536" height="826" data-path="images/academy-quick-start-conversations.png" />
    </Frame>
  </Step>
</Steps>

## Key points

<AccordionGroup>
  <Accordion title="SMS open rates vs. email">
    SMS messages have an average open rate of 98%, compared to roughly 20% for email. Most texts are read within 3 minutes of delivery, making SMS ideal for time-sensitive offers and announcements.
  </Accordion>

  <Accordion title="Using custom fields in SMS">
    Personalization dramatically improves response rates. Using `{{contact.first_name}}` or other custom field values makes each message feel personal even when sent to thousands of contacts.
  </Accordion>

  <Accordion title="Drip send for high-volume lists">
    If sending to a large list, drip sending staggers delivery in batches to stay within carrier rate limits and reduce the risk of messages being flagged. This is especially important for lists over 1,000 contacts.
  </Accordion>

  <Accordion title="Trigger links in SMS blasts">
    Including a trigger link lets you track who clicked and when. You can also use trigger links to automatically enroll contacts who click into a follow-up workflow.
  </Accordion>
</AccordionGroup>

## Key benefits

<AccordionGroup>
  <Accordion title="High engagement">
    SMS generates sales almost every time you send — with no ad spend required.
  </Accordion>

  <Accordion title="Fast setup">
    Engage your entire contact list in under a minute with just a few clicks.
  </Accordion>

  <Accordion title="Full tracking">
    Monitor delivered, failed, and clicked statistics for every blast.
  </Accordion>

  <Accordion title="Unified replies">
    All contact replies flow directly into the Conversations area for easy response management.
  </Accordion>

  <Accordion title="Advanced automation">
    Combine trigger links with workflows to create automated follow-up sequences based on who clicks.
  </Accordion>
</AccordionGroup>
