Skip to content

Examples

Real-world examples of using the Tappd Mobile SDK in React Native applications.

E-commerce

Product Purchase Flow

javascript
import TappdSDK from '@tappd/mobile-sdk';

const tappd = new TappdSDK({ appId: 'YOUR_APP_ID' });

// 1. User views product
await tappd.track('ecommerce.product_viewed', {
  productId: 'prod_123',
  productName: 'iPhone 15',
  category: 'Electronics',
  price: 999.00,
  currency: 'USD'
});

// 2. User adds to cart
await tappd.track('ecommerce.add_to_cart', {
  productId: 'prod_123',
  productName: 'iPhone 15',
  quantity: 1,
  price: 999.00,
  currency: 'USD'
});

// 3. User starts checkout
await tappd.track('ecommerce.checkout_started', {
  cartValue: 999.00,
  currency: 'USD'
});

// 4. User completes purchase
await tappd.track('ecommerce.purchase', {
  orderId: 'ord_456',
  total: 999.00,
  currency: 'USD',
  items: [{
    productId: 'prod_123',
    name: 'iPhone 15',
    price: 999.00,
    quantity: 1
  }]
});

User Authentication

Sign Up Flow

javascript
async function handleSignUp(email, name) {
  // Track signup attempt
  await tappd.track('user.signup.started', {
    method: 'email'
  });

  try {
    // Create user account
    const user = await createAccount(email, name);
    
    // Identify user (merges anonymous data)
    await tappd.identify({
      external_id: user.id,  // Your internal user ID
      email: email,
      name: name,
      signupDate: new Date().toISOString()
    });

    // Track successful signup
    await tappd.track('user.signup.completed', {
      method: 'email'
      // Note: userId not needed - SDK automatically associates event with identified user
    });
  } catch (error) {
    // Track signup failure
    await tappd.track('user.signup.failed', {
      method: 'email',
      error: error.message
    });
  }
}

Login Flow

javascript
async function handleLogin(email) {
  // Track login attempt
  await tappd.track('user.login.started', {
    method: 'email'
  });

  try {
    const user = await authenticate(email);
    
    // Identify user
    await tappd.identify({
      external_id: user.id,  // Your internal user ID
      email: user.email,
      name: user.name,
      lastLogin: new Date().toISOString()
    });

    // Track successful login
    await tappd.track('user.login.completed', {
      method: 'email'
      // Note: userId not needed - SDK automatically associates event with identified user
    });
  } catch (error) {
    // Track login failure
    await tappd.track('user.login.failed', {
      method: 'email',
      error: error.message
    });
  }
}

Logout

javascript
function handleLogout() {
  // Track logout
  tappd.track('user.logout');
  
  // Reset SDK (clears user data)
  tappd.reset();
}

Screen Tracking

With React Navigation

javascript
import React from 'react';
import { View, Text } from 'react-native';
import { useFocusEffect } from '@react-navigation/native';
import { useTappd } from '../contexts/TappdContext';

function ProductScreen({ route }) {
  const tappd = useTappd();
  const { productId } = route.params;

  useFocusEffect(
    React.useCallback(() => {
      tappd.trackScreen('ProductScreen', {
        productId: productId,
        category: 'ecommerce'
      });
    }, [productId])
  );

  return (
    <View>
      <Text>Product Screen</Text>
    </View>
  );
}

Manual Screen Tracking

javascript
import { useEffect } from 'react';

function MyScreen() {
  const tappd = useTappd();

  useEffect(() => {
    tappd.trackScreen('MyScreen', {
      category: 'main',
      section: 'dashboard'
    });
  }, []);

  return (
    // Screen content
  );
}

Push Notifications

Complete Push Setup

javascript
import React, { useEffect } from 'react';
import messaging from '@react-native-firebase/messaging';
import { Platform } from 'react-native';
import TappdSDK from '@tappd/mobile-sdk';

const tappd = new TappdSDK({ appId: 'YOUR_APP_ID' });

function App() {
  useEffect(() => {
    setupPushNotifications();
  }, []);

  async function setupPushNotifications() {
    try {
      // Request permission
      if (Platform.OS === 'ios') {
        const authStatus = await messaging().requestPermission();
        const enabled =
          authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
          authStatus === messaging.AuthorizationStatus.PROVISIONAL;
        
        if (!enabled) return;
      }

      // Get token
      const token = await messaging().getToken();
      
      if (token) {
        // User must be identified first
        await tappd.identify({
          external_id: 'user_123',
          email: 'john@example.com'
        });
        
        // Register token
        await tappd.registerPushToken(
          token,
          Platform.OS === 'ios' ? 'ios' : 'android'
        );
      }

      // Listen for token refresh
      messaging().onTokenRefresh(async (newToken) => {
        await tappd.registerPushToken(
          newToken,
          Platform.OS === 'ios' ? 'ios' : 'android'
        );
      });

      // Handle foreground messages
      messaging().onMessage(async (remoteMessage) => {
        await tappd.track('push_notification.received', {
          notificationId: remoteMessage.messageId,
          title: remoteMessage.notification?.title
        });
      });

      // Handle notification opens
      messaging().onNotificationOpenedApp(async (remoteMessage) => {
        await tappd.track('push_notification.opened', {
          notificationId: remoteMessage.messageId
        });
      });
    } catch (error) {
      console.error('Push setup failed:', error);
    }
  }

  return (
    // Your app
  );
}

Subscription Management

Subscription Upgrade

javascript
async function handleUpgrade(newPlan, userId) {
  const currentPlan = getUserPlan();
  
  await tappd.track('subscription.upgrade', {
    fromPlan: currentPlan,
    toPlan: newPlan,
    upgradeDate: new Date().toISOString()
  });

  // Update user attributes (requires external_id)
  // Note: external_id must match the one used in identify()
  await tappd.setUserAttributes({
    external_id: userId,  // Required: Must match the external_id from identify()
    plan: newPlan,
    upgradedAt: new Date().toISOString()
  });
}

Subscription Cancellation

javascript
async function handleCancellation(reason, userId) {
  await tappd.track('subscription.cancelled', {
    reason: reason,
    cancelledAt: new Date().toISOString()
  });

  await tappd.setUserAttributes({
    external_id: userId,  // Required: Must match the external_id from identify()
    planStatus: 'cancelled',
    cancellationDate: new Date().toISOString()
  });
}

App Lifecycle

Track App State Changes

javascript
import { AppState } from 'react-native';
import { useEffect } from 'react';

function App() {
  useEffect(() => {
    const subscription = AppState.addEventListener('change', (nextAppState) => {
      if (nextAppState === 'active') {
        // App came to foreground
        tappd.track('app.foreground');
      } else if (nextAppState === 'background') {
        // App went to background
        tappd.track('app.background');
        tappd.cleanup(); // Cleanup on background
      }
    });

    return () => {
      subscription.remove();
    };
  }, []);

  return (
    // Your app
  );
}

Button Tracking

Track Button Clicks

javascript
import { TouchableOpacity, Text } from 'react-native';
import { useTappd } from '../contexts/TappdContext';

function MyButton({ buttonId, title, onPress }) {
  const tappd = useTappd();

  const handlePress = async () => {
    // Track button click
    await tappd.track('button_click', {
      buttonId: buttonId,
      buttonText: title,
      location: 'home_screen'
    });

    // Execute original onPress
    if (onPress) onPress();
  };

  return (
    <TouchableOpacity onPress={handlePress}>
      <Text>{title}</Text>
    </TouchableOpacity>
  );
}

// Usage
<MyButton
  buttonId="signup_button"
  title="Sign Up"
  onPress={() => navigation.navigate('SignUp')}
/>

Form Tracking

Track Form Interactions

javascript
import { useState } from 'react';
import { TextInput, Button } from 'react-native';
import { useTappd } from '../contexts/TappdContext';

function SignUpForm() {
  const tappd = useTappd();
  const [formData, setFormData] = useState({});

  const handleFieldFocus = async (fieldName) => {
    await tappd.track('form.field_focused', {
      formId: 'signup_form',
      fieldName: fieldName
    });
  };

  const handleSubmit = async () => {
    // Track form submission
    await tappd.track('form.submitted', {
      formId: 'signup_form',
      formName: 'Sign Up',
      fieldsCompleted: Object.keys(formData).length
    });

    // Submit form
    await submitForm(formData);
  };

  return (
    <>
      <TextInput
        placeholder="Email"
        onFocus={() => handleFieldFocus('email')}
        onChangeText={(text) => setFormData({ ...formData, email: text })}
      />
      <Button title="Submit" onPress={handleSubmit} />
    </>
  );
}

Context Provider Pattern

Create Tappd Context

javascript
// contexts/TappdContext.js
import React, { createContext, useContext, useState, useEffect } from 'react';
import TappdSDK from '@tappd/mobile-sdk';

const TappdContext = createContext(null);

export function TappdProvider({ children, appId }) {
  const [tappd] = useState(() => {
    return new TappdSDK({
      appId: appId,
      debug: __DEV__
    });
  });

  useEffect(() => {
    // Cleanup on unmount
    return () => {
      tappd.cleanup();
    };
  }, []);

  return (
    <TappdContext.Provider value={tappd}>
      {children}
    </TappdContext.Provider>
  );
}

export function useTappd() {
  const context = useContext(TappdContext);
  if (!context) {
    throw new Error('useTappd must be used within TappdProvider');
  }
  return context;
}

Use in App

javascript
// App.js
import { TappdProvider } from './contexts/TappdContext';

function App() {
  return (
    <TappdProvider appId="YOUR_APP_ID">
      {/* Your app components */}
    </TappdProvider>
  );
}

Error Tracking

Track Errors

javascript
import { ErrorUtils } from 'react-native';

// Set up global error handler
ErrorUtils.setGlobalHandler(async (error, isFatal) => {
  try {
    await tappd.track('error', {
      message: error.message,
      stack: error.stack,
      isFatal: isFatal,
      timestamp: new Date().toISOString()
    });
  } catch (trackingError) {
    console.error('Failed to track error:', trackingError);
  }

  // Call default handler
  if (ErrorUtils.getGlobalHandler) {
    ErrorUtils.getGlobalHandler()(error, isFatal);
  }
});

Deep Linking

javascript
import { Linking } from 'react-native';
import { useEffect } from 'react';
import { useTappd } from '../contexts/TappdContext';

function App() {
  const tappd = useTappd();

  useEffect(() => {
    // Get initial URL
    Linking.getInitialURL().then((url) => {
      if (url) {
        tappd.track('deep_link.opened', {
          url: url,
          source: 'cold_start'
        });
      }
    });

    // Listen for deep links
    const subscription = Linking.addEventListener('url', (event) => {
      tappd.track('deep_link.opened', {
        url: event.url,
        source: 'warm_start'
      });
    });

    return () => {
      subscription.remove();
    };
  }, []);

  return (
    // Your app
  );
}

Next Steps

Released under the MIT License.