Get Started

Install the package, build your app, and run a text request on the device.

You need Expo SDK 54+ and a native build. Expo Go is not supported. For this text example, use an Apple Intelligence device on iOS 26+ or a supported Android device.

Here for speech, images, face detection, or embeddings? Install below, then follow that guide for its configuration and example.

1. Install

npx expo install expo-ai-kit

All features are off by default. Nothing native is compiled into your app until you turn a feature on here. Each option adds one feature and nothing else; this example needs llm:

app.jsonjson
{
  "expo": {
    "plugins": [["expo-ai-kit", { "llm": true }]]
  }
}

In an existing React Native app, install Expo modules first, then set the same option by hand: expoAiKit.llm=true in android/gradle.properties and "expoAiKit.llm": "true" in ios/Podfile.properties.json (or $ExpoAiKitLLM = true in the Podfile). The llm and speech options need Android minSdkVersion 26.

Set the Android minimum SDK in an Expo project
npx expo install expo-build-properties
app.jsonjson
{
  "expo": {
    "plugins": [["expo-build-properties", { "android": { "minSdkVersion": 26 } }]]
  }
}

2. Build the app

Plugin options change native code, so run a native build for your platform, or create an EAS development build.

npx expo run:ios --device
# or
npx expo run:android --device

In a bare React Native app, run npx pod-install for iOS and rebuild using your normal native workflow.

3. Run a request

Replace App.tsx with this component. In a Router app, use it as a screen. Tap Ask; the answer appears below the button.

App.tsxtsx
import { useState } from 'react';
import { Button, ScrollView, Text } from 'react-native';
import { isAvailable, prepareBuiltInModel, sendMessage } from 'expo-ai-kit';

export default function App() {
  const [answer, setAnswer] = useState('Tap Ask to begin.');
  const [busy, setBusy] = useState(false);

  async function ask() {
    setBusy(true);
    try {
      if (!(await isAvailable())) {
        setAnswer('The built-in text model is unavailable on this device.');
        return;
      }
      setAnswer('Preparing the model…');
      await prepareBuiltInModel();
      setAnswer('Thinking…');
      const { text } = await sendMessage([
        { role: 'user', content: 'Explain gravity in one sentence.' },
      ]);
      setAnswer(text);
    } catch (error) {
      setAnswer(error instanceof Error ? error.message : String(error));
    } finally {
      setBusy(false);
    }
  }

  return (
    <ScrollView contentContainerStyle={{ padding: 24, paddingTop: 80, gap: 16 }}>
      <Button title={busy ? 'Working…' : 'Ask'} onPress={ask} disabled={busy} />
      <Text selectable>{answer}</Text>
    </ScrollView>
  );
}

Android may download the built-in model during preparation. Subsequent requests reuse the prepared model.

If the device has no built-in text model, use a downloadable model or see troubleshooting. Next, stream responses and add conversation history.