クライアントエージェント
React Native
アプリには比較対象となるサーバー側のスパンがないので、拒否された呼び出しや空のレスポンスは端末からしか見えません。それを見えるようにするのがこのエージェントです。
- パッケージ
@sixty-sh/react-native/ npm- 動作環境
- iOS と Android。観測するリクエスト1件あたり、ブロッキングのコストはおよそ2.6マイクロ秒。
- ソース
- sixty-sh/sixty-react-native
導入方法
iOS and Android. API shape and latency, errors and crashes, render loops — with a public key.
導入手順は、あなた向けのチェックリストではなく、すでに開いているコーディングエージェント向けのプロンプトとして書かれています。これは意図的です。どのファイルを編集するかではなく、導入が終わった時点で何が成り立っていなければならないかを述べています。コードをどこに置くかはフレームワーク次第で、置き場所を間違えると静かに失敗するからです。エージェントはリポジトリを読んでそれを判断できますが、ドキュメントの段落にはできません。
同じ文面は、 install_sixty が MCP サーバー 経由で返すものであり、コレクタが次の場所で配信しているものでもあります: /v1/setup?kind=react-native. 実体は1つだけです。
React Native の導入手順(全文)
Add sixty.sh monitoring to this React Native app. It measures API call shape
and latency, JavaScript errors and crashes, and runaway re-render loops, and
reports anonymously.
Before editing, ask: "Do you want mobile incident replay?" Enable replay
only if the user says yes. It retains a bounded screen/request/error timeline
around failures, never screenshots, screen text, bodies, headers or ids.
1. Install @sixty-sh/react-native. Also install
@react-native-async-storage/async-storage if it is not already present —
without it, telemetry buffered when the user backgrounds the app is lost,
and that is how most sessions end.
2. Call init() once, at the top of the entry file (index.js or App.tsx),
before anything else imports:
import { init, composeRelease } from "@sixty-sh/react-native"
init({
key: "sixty_pk_YOUR_KEY",
service: "my-app",
endpoint: "https://ingest.sixty.sh",
release: composeRelease({ version: APP_VERSION, build: BUILD_NUMBER }),
// replay: true, // uncomment only with explicit consent
})
Work out where the version and build number actually come from in THIS
project — expo-constants, react-native-device-info, a generated file, or a
constant somebody maintains by hand. Do not add a dependency just for this;
if none exists, hardcode the current version and say so in your summary.
IF this app ships over-the-air updates (expo-updates or CodePush), the
release MUST also include the update id:
composeRelease({ version, build, updateId: Updates.updateId })
Without it every OTA bundle reports as the same release, and since OTA is
how most changes ship, almost nothing can ever be compared. Nothing errors;
the feed just stays empty.
3. Add the Babel plugin to babel.config.js:
plugins: ["@sixty-sh/react-native/babel"]
Then start Metro with --reset-cache once. Metro caches transformed modules
and will not notice the plugin list changed, so without this the build
succeeds and the transform is silently not applied.
4. Wire the navigator, or every measurement in the app is filed under one
route and no per-screen finding is possible. Find the NavigationContainer:
import { createNavigationTracker } from "@sixty-sh/react-native/navigation"
const tracker = createNavigationTracker()
<NavigationContainer onReady={tracker.onReady} onStateChange={tracker.onStateChange}>
If this app does not use React Navigation, call setRoute("ScreenName") from
wherever it does track the current screen instead.
5. If the app has React error boundaries, call reportError(error) from
componentDidCatch. React calls the boundary instead of any global handler,
so errors caught there are invisible to the agent otherwise — and those are
the ones that leave a user looking at a fallback screen.
Constraints — correctness requirements, not style preferences:
- Do NOT wrap or replace fetch. React Native's fetch is implemented on top of
XMLHttpRequest, which the agent already instruments; adding a fetch wrapper
makes every request count twice and nothing will look wrong.
- Do NOT change any existing screen, hook, or network call. This is
instrumentation only; no behaviour should change.
- The key above is PUBLIC by design: write-only and pinned to one service.
Paste it literally. Do not move it into an environment variable.
- Do NOT add any analytics library, user id, session id, or device id. This
agent is deliberately anonymous and must stay that way.
When you are done, tell me where you found the version number, whether this
app ships OTA updates, and whether you cleared the Metro cache. Findings need
two released builds with traffic under each before anything can be compared.公開鍵が必要です — オリジンに固定されたもので、自前のサーバーを持たないアプリには秘密を置く場所がないからです。
何を測るか
| シグナル | 単位 | 意味 |
|---|---|---|
client_error | of views | this error is being thrown in real users’ browsers |
auth_failures | — | The server is turning these away on permission grounds rather than failing. People see an empty page or a save that quietly does nothing. |
silent_empty | — | The query runs and succeeds, and returns no rows where it used to return plenty. Nothing reports an error, so the page just renders blank — this is what a broken permission rule looks like from the outside. |
latency | ms per call | this operation takes longer end to end than it used to |
errors | error rate | a larger fraction of calls are throwing |
runaway | calls per minute | this operation is being called far more often than anything triggers it |
どこに入り込むか
- React Navigation — ナビゲータに接続すると、計測結果が画面ごとに整理されます。これを飛ばすと、すべての数値が1つのルートの下にまとまってしまいます。
- あなた自身のコンポーネント — Babel プラグイン。Metro は変換済みモジュールをキャッシュし、プラグイン一覧が変わっても気づかないので、キャッシュを消さないとビルドは黙って何もしません。
これだけができること
- 端末からのネットワークのシグナル — 認証の拒否と、成功しているのに空のレスポンス。携帯では、そのどちらも観測できる唯一の場所がここです。
- OTA を意識したリリース — Over-the-air 更新の id がリリース識別子の一部になります。これがないと、無線で配信したバンドルはすべて同じリリースになり、比較に比べる相手がなくなります。
できないこと
- 公開鍵を使います。アプリにはプロキシできるオリジンがなく、秘密を置く場所もないからです。ブラウザの段と違って、ここではより良いモードを諦めているわけではありません。
- dead_interaction は button、a、form に紐づいていて、Pressable や onPress はまだ知りません。effect_loop と missing_cleanup は React の規則で、このコードにもそのまま適用されます。
設定
どのエージェントも同じ4つの変数を読みます。そして SIXTY_* が答えるところでは DRIFT_* も引き続き答えます — 製品名は変わりましたが、その名前は他人のデプロイから引き上げてよい類のものではありません。
SIXTY_API_KEY | これがないとエージェントは何もせず、そのことを伝えます。推測もせず、未知のエンドポイントに再試行もせず、例外も投げません。 |
|---|---|
SIXTY_SERVICE | このサービスを何と呼ぶか。読み取れる場合はプロジェクト名が既定になります。 |
SIXTY_RELEASE | いちばん重要なもの。Vercel、Render、Railway、Fly、Heroku、GitHub Actions では自動で拾われます。それ以外ではコミットの SHA を設定してください。これがないとすべての計測が名前のない1つのバケツに入り、比較は永遠にできません。 |
SIXTY_ENDPOINT | どこへ報告するか。既定は http://localhost:4319で、ノートPCの上では正しく、そのアプリが他人に配信された瞬間に間違いになります。 |
残り — 送信間隔、サンプリング率、何を計測するか — はパッケージ自身の README にあります。エージェントが変わっても正しいままでいられる場所だからです。