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 app — Created 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 installBasic 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-jsThen 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 State — Show an ActivityIndicator while the WebView loads
- Error Handling — Use the onError prop to handle network errors
- Pull to Refresh — Consider adding pull-to-refresh functionality
- Dark Mode — Reqflow automatically adapts to the system theme