Skip to main content

Intercom Integration

Sanctiv uses Intercom for customer support, product tours, and user engagement tracking. This document covers setup, deep tracking capabilities, and best practices.

Overview

Intercom provides:
  • In-app messaging - Support chat accessible from anywhere
  • Help center - Self-service documentation
  • Product tours - Guided onboarding flows
  • User segmentation - Target specific user groups
  • Support context - Rich data about user behavior before contacting support

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Mobile App                               │
├─────────────────────────────────────────────────────────────┤
│  useAnalytics()  ←── Unified tracking hook                  │
│       │                                                     │
│       ├── PostHog (analytics, feature flags)               │
│       └── Intercom (support, tours, engagement)            │
├─────────────────────────────────────────────────────────────┤
│  Platform-specific implementations:                         │
│  • intercom.native.ts (iOS/Android)                        │
│  • intercom.web.ts (Web stub)                              │
├─────────────────────────────────────────────────────────────┤
│  intercom.types.ts - Type definitions & event enums        │
└─────────────────────────────────────────────────────────────┘

Setup

1. Environment Variables

Add to .env:
# Intercom Configuration
EXPO_PUBLIC_INTERCOM_APP_ID=your_app_id
EXPO_PUBLIC_INTERCOM_IOS_API_KEY=your_ios_api_key
EXPO_PUBLIC_INTERCOM_ANDROID_API_KEY=your_android_api_key

# JWT Generation (Edge Function)
INTERCOM_IDENTITY_VERIFICATION_SECRET=your_secret

2. Edge Function for JWT

The generate-intercom-jwt Supabase Edge Function creates secure JWT tokens for user verification:
// supabase/functions/generate-intercom-jwt/index.ts
// Already implemented - generates JWT using INTERCOM_IDENTITY_VERIFICATION_SECRET

3. Native Configuration

iOS - Add to ios/sanctivmonorepo/Info.plist:
<key>IntercomAutoIntegrate</key>
<false/>
Android - Add to android/app/build.gradle:
implementation "io.intercom.android:intercom-sdk:+"

Usage

Basic Event Tracking

import { logEvent } from "@/lib/intercom";

// Simple event
await logEvent("button_clicked", {
  button_name: "start_journaling",
});

// Event with rich metadata
await logEvent("journal_entry_created", {
  word_count: 150,
  method: "voice",
  template_id: "gratitude-flow",
  has_ai_summary: true,
});

Using the Unified Analytics Hook

The useAnalytics hook tracks to both PostHog and Intercom:
import { useAnalytics } from "@/hooks/useAnalytics";

function JournalScreen() {
  const { track, trackJournalCreated, syncMetrics } = useAnalytics();

  const handleSaveEntry = async () => {
    // Tracks to both PostHog and Intercom
    trackJournalCreated({
      wordCount: 150,
      method: "text",
      hasAiSummary: true,
    });

    // Sync engagement metrics to Intercom
    syncMetrics({
      totalJournalEntries: 25,
      journalStreakDays: 7,
      hasUsedVoice: true,
    });
  };
}

User Identification

Users are automatically identified on login:
import { registerUser } from "@/lib/intercom";

// Called automatically in authStore.signIn
await registerUser({
  userId: user.id,
  email: user.email,
  name: user.full_name,
  orgId: organization.id,
  orgName: organization.name,
});

Showing Support

import { 
  showMessenger, 
  showHelpCenter, 
  showHelpCenterArticle,
  showTickets 
} from "@/lib/intercom";

// Open support chat
await showMessenger();

// Open help center
await showHelpCenter();

// Open specific article
await showHelpCenterArticle("article-id-123");

// Open ticket history
await showTickets();

Product Tours & Surveys

import { showCarousel, showSurvey } from "@/lib/intercom";

// Show onboarding tour
await showCarousel("onboarding-carousel-id");

// Show NPS survey
await showSurvey("nps-survey-id");

Company Data (B2B)

Track organization-level data:
import { updateCompany } from "@/lib/intercom";

await updateCompany({
  company_id: organization.id,
  name: organization.name,
  org_type: "church",
  member_count: 150,
  active_member_count: 45,
  subscription_status: "active",
});

Events Reference

Core Events

EventDescriptionProperties
signed_inUser logged intimestamp, platform
signed_outUser logged outtimestamp
app_openedApp launchedplatform, app_version
app_backgroundedApp sent to backgroundsession_duration_seconds, screens_viewed
screen_viewedUser viewed a screenscreen_name, timestamp

Journal Events

EventDescriptionProperties
journal_entry_createdNew journal entryword_count, method, template_id, has_ai_summary
journal_entry_viewedEntry openedentry_id
journal_entry_editedEntry modifiedentry_id, word_count
journal_entry_deletedEntry removedentry_id

Voice Events

EventDescriptionProperties
voice_recording_startedRecording began-
voice_recording_completedRecording finishedduration_seconds, method, processing_time_ms, word_count
transcription_completedTranscription successfulmethod, processing_time_ms
transcription_failedTranscription errormethod, error_message

Flow Events

EventDescriptionProperties
flow_session_startedUser began a flowtemplate_id, template_name
flow_session_completedFlow finishedtemplate_id, duration_minutes, completion_rate
flow_session_abandonedFlow exited earlytemplate_id, current_step

Conversion Events

Use for tracking milestones and product goals:
EventDescription
first_journal_createdUser’s first journal entry
first_flow_completedUser’s first guided flow
first_companion_addedUser’s first companion
weekly_activeUser active this week

User Attributes

Attributes synced to Intercom for segmentation:
interface IntercomUserAttributes {
  // Identity
  userId?: string;
  email?: string;
  name?: string;

  // Organization (B2B critical)
  org_id?: string;
  org_name?: string;
  org_type?: "church" | "para_church" | "individual";
  org_role?: "admin" | "leader" | "member";

  // Engagement Metrics
  total_journal_entries?: number;
  total_flow_sessions?: number;
  total_voice_entries?: number;
  journal_streak_days?: number;
  last_journal_at?: number; // Unix timestamp

  // Feature Usage
  has_used_voice?: boolean;
  has_used_ai_summary?: boolean;
  has_companions?: boolean;
  companion_count?: number;

  // App State
  app_version?: string;
  platform?: "ios" | "android";
  preferred_transcription?: "local" | "cloud";

  // Support Context
  last_error_at?: number;
  last_error_message?: string;
  last_viewed_screen?: string;
}

Best Practices

1. Use Type-Safe Events

import { IntercomEvents } from "@/lib/intercom.types";

// ✅ Good - type-safe
await logEvent(IntercomEvents.JOURNAL_ENTRY_CREATED, { ... });

// ❌ Avoid - prone to typos
await logEvent("journal_entry_createdd", { ... });

2. Sync Engagement Metrics Periodically

// Call after significant user actions
useEffect(() => {
  syncEngagementMetrics({
    totalJournalEntries: entries.length,
    journalStreakDays: calculateStreak(entries),
    lastJournalAt: entries[0]?.createdAt,
  });
}, [entries.length]);

3. Provide Support Context

// Before showing messenger, update context
await setUserAttributes({
  last_viewed_screen: "JournalDetailScreen",
  last_error_message: error?.message,
});
await showMessenger();

4. Use Unified Analytics Hook

For components that track to both PostHog and Intercom:
// ✅ Good - tracks to both systems
const { trackJournalCreated } = useAnalytics();
trackJournalCreated({ wordCount, method: "voice" });

// ⚠️ Okay - only for Intercom-specific features
await showMessenger();
await showCarousel("onboarding");

5. Handle Expo Go Gracefully

Intercom requires native modules and won’t work in Expo Go:
// ✅ All functions handle this automatically
await showMessenger(); // No-op in Expo Go, logs info message

Troubleshooting

”Intercom not initialized”

Check:
  1. Environment variables are set correctly
  2. Using development build (not Expo Go)
  3. Native modules are linked properly

JWT Verification Failing

Check:
  1. INTERCOM_IDENTITY_VERIFICATION_SECRET matches Intercom dashboard
  2. Supabase Edge Function is deployed
  3. User has valid session

Events Not Appearing

  1. Check Intercom dashboard for real-time events
  2. Verify user is registered (logged in)
  3. Check for console warnings