> ## 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.

# How to import & manage contacts

> Learn how to add contacts manually, format and import CSV files, create custom fields, and organize your contact list in the HoopAI Platform.

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="onboarding" lessonId="how-to-import-manage-contacts" />

Your contact list is the foundation of your business growth. A well-organized list lets you segment your audience, send targeted messages, and run personalized campaigns at scale. This lesson covers adding contacts manually, formatting CSV files for import, creating custom fields, and importing your list.

<Frame caption="The Import & Manage Contacts lesson in the HoopAI Academy">
  <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="Import and manage contacts" width="1536" height="826" data-path="images/academy-onboarding-import-contacts.png" />
</Frame>

## Why this matters

A well-organized contact list is like having a goldmine at your fingertips. Every friend, colleague, former client, and new lead belongs in your system — organized, tagged, and ready for follow-up. Contacts are the lifeblood of your business.

<Note>
  Before importing, make sure your CSV is properly formatted with column headers. The platform uses the headers to map your data to the correct fields.
</Note>

## How to add and import contacts

<Steps>
  <Step title="Navigate to Contacts">
    In the left sidebar, click **Contacts**. This is your central hub for managing all leads, clients, and prospects.

    <Frame caption="The Contacts section in the HoopAI Platform">
      <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="Contacts navigation" width="1536" height="826" data-path="images/academy-onboarding-import-contacts.png" />
    </Frame>
  </Step>

  <Step title="Add a contact manually">
    Click the **Add Contact** button (the + icon). Fill in the essential details:

    * First name and last name
    * Phone number
    * Email address
    * Any additional fields relevant to your business

    Click **Save** to add the contact. Manual entry is best for individual connections you want to add right away.

    <Frame caption="Adding a single contact manually in the HoopAI Platform">
      <img src="https://mintcdn.com/hoopai-84ec0cdc/gyU98wGhFXcTdqFf/images/academy-onboarding-business-profile.png?fit=max&auto=format&n=gyU98wGhFXcTdqFf&q=85&s=16ee3d4747e0c5b5fdffec7483279cae" alt="Add contact form" width="1536" height="826" data-path="images/academy-onboarding-business-profile.png" />
    </Frame>
  </Step>

  <Step title="Prepare your CSV file for import">
    Format your existing contact list as a CSV file with clearly labeled column headers. Key columns to include:

    * `first_name`
    * `last_name`
    * `email`
    * `phone`

    You can also add columns for address, company name, or any custom data you want to import.

    <Tip>
      Remove any special characters from phone numbers — use digits only. International numbers should include the country code.
    </Tip>
  </Step>

  <Step title="Create custom fields (if needed)">
    If your CSV includes data that does not map to a standard field — such as lead status, birthday, or membership level — create custom fields first.

    Go to **Settings** > **Custom Fields** and click **Add Field**. Choose the field type (text, dropdown, number, or date), give it a clear label, and save before importing.

    <Frame caption="Creating custom fields in HoopAI Settings">
      <img src="https://mintcdn.com/hoopai-84ec0cdc/gyU98wGhFXcTdqFf/images/academy-onboarding-connect-integrations.png?fit=max&auto=format&n=gyU98wGhFXcTdqFf&q=85&s=438d94999ada2e8819af2eb0ee159b50" alt="Custom fields settings" width="1536" height="826" data-path="images/academy-onboarding-connect-integrations.png" />
    </Frame>
  </Step>

  <Step title="Import your contact list">
    In the **Contacts** section, click **Import** and upload your CSV file. The importer will ask you to map each column header to the corresponding field in the platform.

    Review the mapping carefully, choose how to handle duplicates, and click **Import** to begin.
  </Step>

  <Step title="Organize with Smart Lists">
    After importing, use **Smart Lists** to segment your contacts by tags, engagement, purchase history, automation enrollment, or any custom field value. Smart Lists update automatically as contacts meet your filter criteria.

    <Frame caption="Smart Lists let you segment contacts dynamically">
      <img src="https://mintcdn.com/hoopai-84ec0cdc/gyU98wGhFXcTdqFf/images/academy-onboarding-my-profile.png?fit=max&auto=format&n=gyU98wGhFXcTdqFf&q=85&s=81cf8284a976b0205bb0369da0c3005d" alt="Smart lists overview" width="1536" height="826" data-path="images/academy-onboarding-my-profile.png" />
    </Frame>
  </Step>
</Steps>

## Key points

<AccordionGroup>
  <Accordion title="Adding contacts manually vs. importing">
    Manual addition works best for immediate connections you want to add one at a time. For larger lists, CSV import is the most efficient approach. Both result in contacts that can be used in campaigns, automations, and pipelines.
  </Accordion>

  <Accordion title="Formatting your CSV correctly">
    Each column in your CSV must have a header that maps to a field in the platform. Extra columns without matching fields will be ignored unless you have a corresponding custom field.
  </Accordion>

  <Accordion title="Creating and assigning custom fields">
    Custom fields let you store any data specific to your business. For example, a dropdown field for "Lead Status" with options like Cold Lead, Warm Lead, and Hot Lead — then use these fields to filter Smart Lists and personalize messages.
  </Accordion>

  <Accordion title="Handling duplicates during import">
    The import tool gives you options for handling duplicate records — skip duplicates, update existing records, or create new records. Choose the option that best fits your situation.
  </Accordion>
</AccordionGroup>

## Key benefits

<AccordionGroup>
  <Accordion title="Efficiency">
    Import a large number of contacts at once, saving significant time compared to manual entry.
  </Accordion>

  <Accordion title="Organization">
    Smart Lists segment your audience for highly targeted, personalized messages.
  </Accordion>

  <Accordion title="Personalization">
    Custom fields let you capture and store specific information for tailored communications.
  </Accordion>

  <Accordion title="Analytics">
    An organized contact list gives you data to track campaign performance and identify engagement trends.
  </Accordion>

  <Accordion title="Scalability">
    A well-structured contact list grows with your business, keeping communication efficient at any scale.
  </Accordion>
</AccordionGroup>
