
「Claude APIをExpoアプリに組み込みたいけど、どこから始めればいいかわからない」
そういう人向けに、余計なものを全部省いて最短ルートだけまとめました。
この記事を読めば、Expoアプリ内でClaudeにテキストを送り、返答を受け取るところまでを30分以内に実装できます。
この記事でできるようになること
- Anthropic APIキーの取得と設定
- ExpoプロジェクトへのClaude API組み込み
- セキュリティを意識した実装パターン
- よくあるエラーと対処法
前提条件
以下が済んでいる前提で進めます。
- Node.js がインストール済み
- Expo CLI が使える(
npx expoが動く) - Anthropicのアカウントがある(なければ後述)
まだExpoを触ったことがない場合は、先にExpo公式のGet Startedを済ませてから戻ってきてください。
ステップ1:Anthropic APIキーを取得する
まずAnthropic ConsoleにアクセスしてAPIキーを発行します。
- Anthropicアカウントにサインイン(なければ新規登録)
- 左メニューの「API Keys」を開く
- 「Create Key」をクリック
- 名前をつけて(例:
expo-app-dev)キーを発行 sk-ant-...から始まる文字列をコピーして保存
注意:APIキーは発行時の1回しか表示されません。必ずメモしておいてください。
APIの料金は従量課金です。開発中は数十〜数百円程度に収まるケースがほとんどですが、Consoleの Usageから確認できます。
ステップ2:Expoプロジェクトを作成する
既存のプロジェクトに追加する場合はこのステップは飛ばしてください。
npx create-expo-app my-claude-app
cd my-claude-app
ステップ3:環境変数を設定する
APIキーをコードに直書きするのは絶対にNGです。Gitにpushした瞬間に漏洩します。
Expoでは.envファイルで環境変数を管理します。
プロジェクトルートに.envファイルを作成:
EXPO_PUBLIC_ANTHROPIC_API_KEY=sk-ant-ここにあなたのキーを貼る
次に.gitignoreに.envが含まれているか確認してください。
# .gitignoreに以下が含まれているか確認
.env
.env.local
重要:ExpoのEXPO_PUBLIC_プレフィックスはクライアントサイドに公開されます。本番アプリでは後述するサーバーサイド経由の実装を検討してください。
ステップ4:Claude APIを叩く関数を実装する
まずAPIを呼び出す関数を作ります。services/claude.tsというファイルを作成してください。
// services/claude.ts
const ANTHROPIC_API_KEY = process.env.EXPO_PUBLIC_ANTHROPIC_API_KEY;
const API_URL = 'https://api.anthropic.com/v1/messages';
export type Message = {
role: 'user' | 'assistant';
content: string;
};
export async function callClaude(messages: Message[]): Promise<string> {
if (!ANTHROPIC_API_KEY) {
throw new Error('APIキーが設定されていません');
}
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': ANTHROPIC_API_KEY,
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-sonnet-4-5',
max_tokens: 1024,
messages: messages,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`API Error: ${error.error?.message || response.statusText}`);
}
const data = await response.json();
return data.content[0].text;
}
ポイントを3つ説明します。
- model:まずはClaude Sonnet系の最新モデルを選ぶのが無難です。2026年時点ではClaude Sonnet 4.6が有力候補です。利用可能なモデルはAnthropic ConsoleまたはModels APIで確認してください
- anthropic-version:このヘッダーは必須です。省略するとエラーになります
- max_tokens:返答の最大トークン数です。長い文章が必要なら増やしてください
ステップ5:画面に組み込む
シンプルなチャット画面の例です。app/index.tsx(またはApp.tsx)に実装します。
// app/index.tsx
import { useState } from 'react';
import {
View,
TextInput,
Text,
TouchableOpacity,
ScrollView,
ActivityIndicator,
StyleSheet,
} from 'react-native';
import { callClaude, Message } from '../services/claude';
export default function App() {
const [input, setInput] = useState('');
const [messages, setMessages] = useState<Message[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleSend = async () => {
if (!input.trim() || loading) return;
const userMessage: Message = { role: 'user', content: input };
const newMessages = [...messages, userMessage];
setMessages(newMessages);
setInput('');
setLoading(true);
setError('');
try {
const reply = await callClaude(newMessages);
setMessages([...newMessages, { role: 'assistant', content: reply }]);
} catch (e: any) {
setError(e.message);
} finally {
setLoading(false);
}
};
return (
<View style={styles.container}>
<ScrollView style={styles.messages}>
{messages.map((msg, i) => (
<View
key={i}
style={[
styles.bubble,
msg.role === 'user' ? styles.userBubble : styles.assistantBubble,
]}
>
<Text style={styles.bubbleText}>{msg.content}</Text>
</View>
))}
{loading && <ActivityIndicator style={{ margin: 16 }} />}
{error ? <Text style={styles.error}>{error}</Text> : null}
</ScrollView>
<View style={styles.inputRow}>
<TextInput
style={styles.input}
value={input}
onChangeText={setInput}
placeholder="メッセージを入力..."
multiline
/>
<TouchableOpacity style={styles.button} onPress={handleSend}>
<Text style={styles.buttonText}>送信</Text>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#fff', paddingTop: 60 },
messages: { flex: 1, padding: 16 },
bubble: { marginBottom: 12, padding: 12, borderRadius: 12, maxWidth: '85%' },
userBubble: { backgroundColor: '#3b82f6', alignSelf: 'flex-end' },
assistantBubble: { backgroundColor: '#f1f5f9', alignSelf: 'flex-start' },
bubbleText: { color: '#1e293b', fontSize: 15, lineHeight: 22 },
error: { color: '#ef4444', textAlign: 'center', marginVertical: 8 },
inputRow: { flexDirection: 'row', padding: 12, borderTopWidth: 1, borderColor: '#e2e8f0' },
input: { flex: 1, borderWidth: 1, borderColor: '#cbd5e1', borderRadius: 8, padding: 10, fontSize: 15, marginRight: 8 },
button: { backgroundColor: '#3b82f6', borderRadius: 8, paddingHorizontal: 16, justifyContent: 'center' },
buttonText: { color: '#fff', fontWeight: '600' },
});
ステップ6:動作確認する
npx expo start
iOSシミュレーター、Androidエミュレーター、またはExpo Goアプリで確認してください。
メッセージを送信してClaudeから返答が来れば成功です。
よくあるエラーと対処法
401 Unauthorized
APIキーが正しく設定されていないか、無効になっています。.envファイルのキーを確認し、EXPO_PUBLIC_プレフィックスがついているか見直してください。変更後はアプリをフルリロードして反映を確認してください。
Network request failed
ネットワーク接続の問題か、シミュレーターの設定不備です。実機またはExpo Goで試すと解決することが多いです。
返答が途中で切れる
max_tokensが足りていません。1024を2048や4096に増やしてください。
レスポンスが遅い
Claudeのモデルによって速度が変わります。速度重視ならclaude-haiku-4-5-20251001に切り替えてください。体感できるほど速くなります。
本番アプリに向けた注意点
この記事の実装はプロトタイプ・学習用途向けです。本番リリースするアプリでは以下を検討してください。
APIキーをサーバーサイドに移す
EXPO_PUBLIC_の変数はビルドに含まれます。悪意のあるユーザーがアプリを解析すればキーを取り出せる可能性があります。本番では自前のバックエンド(Next.jsのAPI Routeなど)経由でAPIを叩く設計にしてください。
エラーハンドリングを厚くする
ネットワーク断、タイムアウト、レート制限(429エラー)のケースをそれぞれ丁寧に処理することで、ユーザー体験が大きく変わります。
ストリーミングを使う
長い返答の場合、全部届いてから表示するより逐次表示した方がUXが良くなります。Anthropic APIはSSEによるストリーミングに対応しています。
まとめ
ExpoでClaude APIを叩く最小構成をまとめると:
- Anthropic ConsoleでAPIキーを取得
.envにEXPO_PUBLIC_ANTHROPIC_API_KEYを設定fetchでPOSTリクエストを送る関数を作る- 画面に組み込む
APIの組み込み自体はシンプルです。難しいのは「その先」——セキュリティ、エラー処理、UX——の部分です。次の記事で深掘りします。
次に読む記事
- → Claude APIのコストを半分に抑えるプロンプト設計の実践(準備中)
- → Claude APIでストリーミング出力を実装する方法(準備中)
- → ExpoアプリのAPIキーを本番環境で安全に管理する方法(準備中)