Building an AI Photo App with Expo & React Native with Imgwire
This tutorial shows how to structure an Expo app where the mobile client asks your backend to generate an image, the backend saves the generated asset to Imgwire, and the app renders the returned image ID.
Do not call image generation providers directly from the mobile app. Keep provider API keys and Imgwire Server API Keys on your backend.
Architecture
The flow has three parts:
- The Expo app sends a prompt to your backend.
- The backend uses an image-generation provider and uploads the result to Imgwire.
- The backend returns the Imgwire image ID to the app.
The mobile app only needs an Imgwire Client Key for rendering and optional user uploads. It does not need access to the AI provider key.
Install the mobile SDK
yarn add @imgwire/react-native
Wrap the app:
import { ImgwireProvider } from '@imgwire/react-native';
import { GeneratePhotoScreen } from './GeneratePhotoScreen';
export default function App() {
return (
<ImgwireProvider
config={{
apiKey: process.env.EXPO_PUBLIC_IMGWIRE_CLIENT_KEY!,
}}
>
<GeneratePhotoScreen />
</ImgwireProvider>
);
}
Build the generation screen
The screen sends the prompt to your backend and renders the Imgwire image ID returned by the server.
import { useState } from 'react';
import { Button, Text, TextInput, View } from 'react-native';
import { Image as ImgwireImage } from '@imgwire/react-native';
export function GeneratePhotoScreen() {
const [prompt, setPrompt] = useState('');
const [imageId, setImageId] = useState<string | null>(null);
const [isGenerating, setIsGenerating] = useState(false);
async function generatePhoto() {
setIsGenerating(true);
try {
const response = await fetch('https://api.example.com/ai/photos', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ prompt }),
});
if (!response.ok) {
throw new Error('Image generation failed');
}
const data = (await response.json()) as { imageId: string };
setImageId(data.imageId);
} finally {
setIsGenerating(false);
}
}
return (
<View>
<TextInput
value={prompt}
onChangeText={setPrompt}
placeholder="Describe the image"
/>
<Button
title={isGenerating ? 'Generating...' : 'Generate image'}
onPress={generatePhoto}
disabled={!prompt || isGenerating}
/>
{imageId ? (
<ImgwireImage
id={imageId}
width={1024}
height={1024}
resizing_type="cover"
format="auto"
style={{ width: '100%', height: 320 }}
/>
) : null}
</View>
);
}
Backend response shape
Your backend route should return the Imgwire image ID and, optionally, a ready-to-render CDN URL:
{
"imageId": "img_123",
"url": "https://cdn.imgwire.dev/..."
}
The app should store the image ID if users can revisit, share, or edit generated results later.
Backend generation pattern
On the backend, use the image-generation provider and @imgwire/node. For a complete OpenAI SDK example, see Saving AI Generated Images to Imgwire.
import { ImgwireClient } from '@imgwire/node';
const imgwire = new ImgwireClient({
apiKey: process.env.IMGWIRE_API_KEY!,
});
export async function saveGeneratedImageBuffer(
imageBuffer: Buffer,
prompt: string
) {
const image = await imgwire.images.upload({
file: imageBuffer,
fileName: 'generated-photo.png',
mimeType: 'image/png',
purpose: 'ai generated mobile photo',
customMetadata: {
source: 'ai-photo-app',
prompt,
},
});
return {
imageId: image.id,
url: image.url({
width: 1024,
height: 1024,
resizing_type: 'cover',
format: 'auto',
quality: 'auto',
}),
};
}
Add source image uploads
If the app lets users transform one of their own photos, combine this guide with the Expo photo sharing tutorial. Upload the source photo to Imgwire first, store the source image ID, then have your backend use that source image in the AI workflow where your provider supports image inputs.
Best practices
- Keep AI provider keys and Imgwire Server API Keys on the backend.
- Store both prompt metadata and Imgwire image IDs for generated results.
- Return small preview variants to the mobile app when generation finishes.
- Use background jobs for long-running generation workflows.
- Consider moderation and user permission checks before saving generated images to a shared feed.
Related pages
- Saving AI Generated Images to Imgwire
- Photo Sharing App with Expo & React Native
- Backend Quickstart
- Transformations API Overview
Last updated at: May 8, 2026