Integration

React Native Integration

Add Reqflow to your React Native app using the react-native-webview package.

Prerequisites

  • React Native 0.60+Required for auto-linking
  • Reqflow appCreated in the dashboard

Install Dependencies

Install the required packages:

Terminal
# Using npm
npm install react-native-webview react-native-device-info

# Using yarn
yarn add react-native-webview react-native-device-info

# For iOS, install pods
cd ios && pod install

Basic Implementation

Create a FeedbackScreen component:

FeedbackScreen.tsx
import React from 'react';
import { StyleSheet, SafeAreaView, ActivityIndicator, View } from 'react-native';
import { WebView } from 'react-native-webview';
import DeviceInfo from 'react-native-device-info';

// Your app's slug from the Reqflow dashboard
const APP_ID = 'your-app-id';

interface FeedbackScreenProps {
  userId?: string;
  userName: string;
  userEmail?: string;
}

export function FeedbackScreen({
  userId,
  userName,
  userEmail,
}: FeedbackScreenProps) {
  // Use device ID if no userId provided
  const deviceId = DeviceInfo.getUniqueIdSync();
  const finalUserId = userId || deviceId;

  const params = new URLSearchParams({
    user_id: finalUserId,
    user_name: userName,
    ...(userEmail && { user_email: userEmail }),
  });

  const feedbackUrl = `https://reqflow.com/vote/${APP_ID}?${params.toString()}`;

  return (
    <SafeAreaView style={styles.container}>
      <WebView
        source={{ uri: feedbackUrl }}
        style={styles.webview}
        javaScriptEnabled={true}
        domStorageEnabled={true}
        startInLoadingState={true}
        renderLoading={() => (
          <View style={styles.loading}>
            <ActivityIndicator size="large" color="#6366f1" />
          </View>
        )}
      />
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  webview: {
    flex: 1,
  },
  loading: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
  },
});

With React Navigation

If you're using React Navigation, add the screen to your navigator:

AppNavigator.tsx
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { FeedbackScreen } from './screens/FeedbackScreen';

const Stack = createNativeStackNavigator();

function AppNavigator() {
  return (
    <Stack.Navigator>
      {/* ... other screens ... */}
      <Stack.Screen
        name="Feedback"
        component={FeedbackScreenWrapper}
        options={{ title: 'Feedback' }}
      />
    </Stack.Navigator>
  );
}

// Wrapper to pass user props
function FeedbackScreenWrapper() {
  // Get user from your auth context/state
  const { user } = useAuth();

  return (
    <FeedbackScreen
      userId={user?.id}
      userName={user?.name || 'Anonymous'}
      userEmail={user?.email}
    />
  );
}

Opening Feedback Screen

Add a button to navigate to the feedback screen:

import { TouchableOpacity, Text } from 'react-native';
import { useNavigation } from '@react-navigation/native';

function SettingsScreen() {
  const navigation = useNavigation();

  return (
    <TouchableOpacity
      style={styles.button}
      onPress={() => navigation.navigate('Feedback')}
    >
      <Text style={styles.buttonText}>Send Feedback</Text>
    </TouchableOpacity>
  );
}

Expo Users

If you're using Expo, use expo-device instead of react-native-device-info:

deviceId.ts
import * as Device from 'expo-device';
import * as Application from 'expo-application';

// Get a unique device ID
const getDeviceId = async () => {
  if (Platform.OS === 'android') {
    return Application.androidId;
  } else {
    return await Application.getIosIdForVendorAsync();
  }
};

Consistent User ID

Use a device ID or your auth system's user ID. Don't generate a new ID each session, or users will lose their votes.

Secure Authentication (Optional)

For enhanced security, you can add HMAC signature verification to prevent user impersonation. First, install the crypto-js package:

Terminal
npm install crypto-js @types/crypto-js

Then use the signature helper:

FeedbackScreen.tsx
import { HmacSHA256, enc } from 'crypto-js';

/**
 * Generate HMAC signature for secure authentication (optional)
 */
function generateSignature(userId: string, secret: string) {
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const payload = `${userId}:${timestamp}`;

  const signature = HmacSHA256(payload, secret).toString(enc.Hex);

  return { signature, timestamp };
}

// Usage in FeedbackScreen
export function FeedbackScreenWithSignature({
  userId,
  userName,
  userEmail,
  secret, // Fetch from your backend, don't hardcode
}: FeedbackScreenProps & { secret: string }) {
  const deviceId = DeviceInfo.getUniqueIdSync();
  const finalUserId = userId || deviceId;

  const { signature, timestamp } = generateSignature(finalUserId, secret);

  const params = new URLSearchParams({
    user_id: finalUserId,
    user_name: userName,
    signature,
    timestamp,
    ...(userEmail && { user_email: userEmail }),
  });

  const feedbackUrl = `https://reqflow.com/vote/${APP_ID}?${params.toString()}`;

  return (
    <SafeAreaView style={styles.container}>
      <WebView source={{ uri: feedbackUrl }} style={styles.webview} />
    </SafeAreaView>
  );
}

Security Note

Don't hardcode the secret in your app. Fetch it from your backend or use a secure storage solution. The signature feature is optional and only needed if you enable it on your Reqflow server.

Best Practices

  • Loading StateShow an ActivityIndicator while the WebView loads
  • Error HandlingUse the onError prop to handle network errors
  • Pull to RefreshConsider adding pull-to-refresh functionality
  • Dark ModeReqflow automatically adapts to the system theme