Warum Screenshots der falsche Ausgangspunkt waren
Screenshot-basierte Recorder für React Native erfassen zwei oder mehr Bilder pro Sekunde und laden sie hoch. Veröffentlichte Angaben anderer Anbieter nennen dafür am unteren Ende 50 bis 500 KB pro Minute und am oberen Ende etwa 0,5 MB pro Minute. Das kostet zuerst Akku und Datenvolumen Ihrer Nutzer und erst danach Geld auf Ihrer Rechnung. Vor allem ist es eine Sackgasse für genau das, wofür AnyReplay existiert: Aus dem Bild eines türkischen Checkout-Screens wird kein deutscher. In Pixeln stecken keine Wörter.
Ein Tool, dessen Daseinszweck es ist, eine Session in der Sprache der Person zu zeigen, die sie prüft, darf die Wörter bei der Aufzeichnung nicht wegwerfen. Deshalb macht das Mobile-SDK überhaupt keine Screenshots.
Was der Recorder tatsächlich erfasst
Bei jedem Durchlauf geht das SDK den Elementbaum durch, den React festgeschrieben hat – denselben, den die React DevTools lesen –, und notiert für jedes Host-Element, was es ist und was darin steht: ein Text mit seinem String, ein Pressable mit seinem Label, ein TextInput mit seinem Placeholder. Anschließend misst es, wo jedes Element auf dem Bildschirm sitzt; dafür braucht es die New Architecture von React Native. React weiß, was auf dem Bildschirm ist, die Messung weiß, wo – zusammen beschreiben sie den Screen gut genug, um ihn wiederzugeben.
Das Ergebnis ist ein Wireframe, kein Foto: Boxen an den richtigen Stellen mit dem richtigen Text darin, aktualisiert, sobald sich der Baum ändert. Das ist ehrlich in Bezug auf das, was erfasst wurde – und genau das macht eine Session in einer anderen Sprache ansehbar: Jeder String ist noch ein String, wenn er beim Player ankommt.
- Der erste Frame eines Screens umfasst wenige Kilobyte.
- Jeder weitere Frame enthält nur, was sich geändert hat – oft nur eine Handvoll Zahlen.
- Ein Screen im Leerlauf sendet gar nichts.
- Ein Tippen wird aufgezeichnet, wenn der Finger sich hebt, sodass Scrollen oder Wischen nie dafür gehalten wird; Scrollpositionen werden ebenfalls aufgezeichnet.
- Die Navigation wird über Ihren
NavigationContainererfasst, sodass Screens in der Zeitleiste ihre Namen tragen.
Zwei Zeilen App-Code, kein Rebuild
Es gibt kein natives Modul – also kein pod install, keine Gradle-Änderung und keinen Rebuild. Es läuft in Expo Go ab SDK 52. Die zweite Zeile umschließt Ihre App mit <AnyReplay>: Weil React Native kein Document hat, an dem sich Taps abfangen lassen, findet der Recorder darüber Reacts Baum und die Taps; alles andere holt er sich selbst.
npm install @anyreplay/react-native
// App.tsx
import { AnyReplay, init, trackNavigation } from '@anyreplay/react-native';
init({
projectKey: 'ar_pk_live_your_project_key',
ingestUrl: 'https://in.anyreplay.com',
// Your bundle id (iOS) or package name (Android). Required once the project lists allowed domains or apps.
// appId: 'com.example.app',
// Stop recording after this many sessions in a calendar month.
// maxSessionsPerMonth: 10000,
// Fields are masked: what people type replays as asterisks. Secure
// fields, passwords, one-time codes and card fields are masked either
// way. Uncomment the first line to record what people type, or the
// second to mask every field in a way nothing can weaken.
// maskAllInputs: false,
// maskAllTyping: true
});
export default function Root() {
return (
<AnyReplay>
<NavigationContainer ref={(ref) => { if (ref) trackNavigation(ref); }}>
<App />
</NavigationContainer>
</AnyReplay>
);
}Die Optionen decken ab, was ein Mobile-Team braucht: sampleRate wird einmal pro Besucher entschieden, sodass eine aufgezeichnete Person aufgezeichnet bleibt; snapshotIntervalMs ist der wichtigste Kostenhebel; mit requireConsent wird nichts aufgezeichnet, bis Sie consent(true) aufrufen; und wenn Sie AsyncStorage übergeben, erkennt das SDK wiederkehrende Nutzer. Die gesamte API besteht aus zehn Funktionen – init, stop, consent, identify, screen, track, trackError, trackNavigation, flush und getSessionId – und dem Wrapper <AnyReplay>. Wenn Ihr Projekt erlaubte Domains führt, tragen Sie die Bundle-ID der App unter Erlaubte Apps ein und übergeben denselben Wert als appId; jede Session zeigt dann, welche Plattform und welche App-Version sie aufgezeichnet hat.
Maskiert auf dem Gerät, bevor etwas es verlässt
Die Maskierung greift auf dem Gerät, bevor irgendetwas gesendet wird, und funktioniert genau wie im Browser. Alles mit secureTextEntry wird maskiert – ganz gleich, wie die Komponente heißt –, ebenso jedes Feld, das ein textContentType, ein autoComplete, ein keyboardType, ein Placeholder oder ein Label als Passwort, Einmalcode oder Zahlungsfeld ausweist, jeder Wert aus 13 bis 19 Ziffern, der die Luhn-Prüfung besteht, und bei einer Kartennummer, die gerade getippt wird, alles nach der sechsten Ziffer. Alles, dessen testID die Zeichenfolge ar-mask enthält, wird maskiert, weil Sie es so festgelegt haben. Was in andere Felder getippt wird, maskiert das SDK ebenfalls, solange Sie nicht maskAllInputs: false setzen. Ein maskiertes Element behält seine Box und verliert seine Wörter: Wer die Session prüft, sieht, dass etwas eingegeben wurde und wo, aber nie was. Der Wert wird ersetzt, bevor er gesendet wird – nicht erst hochgeladen und dann ausgeblendet. Eine Grenze sei offen benannt: Nach diesem Opt-out sagt ein blankes <TextInput /> ohne Props nichts über sich aus und wird aufgezeichnet – genau wie ein <input> ohne Attribute im Web. Die Datenschutzseite behandelt beide SDKs.
Was es noch nicht kann
Uns ist lieber, Sie kennen die Grenzen schon vor der Installation. Eine FlatList meldet nur die Zeilen, die sie gerendert hat; wer im Replay zurückscrollt, sieht also die Zeilen, die in diesem Moment existierten, nicht die ganze Liste. Bilder, die mit Ihrem App-Bundle ausgeliefert werden, werden einmal hochgeladen und gezeichnet; Fotos vom Gerät werden nie gelesen, und mit maskImages: true wird gar kein Bild aufgezeichnet. Eigene native Komponenten erscheinen als unbekannte Box an der richtigen Stelle, ohne Text, weil es nichts Lesbares zu erfassen gibt. Karten, Web-Views und Videos sind beschriftete Boxen, deren Inhalt nicht erfasst wird, und die Bildschirmtastatur wird nicht gezeichnet. Ein natives SDK für iOS oder Android gibt es noch nicht.
Dasselbe Dashboard, derselbe Player, dieselbe Sandbox
Mobile Sessions stehen in derselben Projektliste wie Web-Sessions, laufen im selben Player mit derselben Zeitleiste und Interaktionsliste und durchlaufen dieselbe Übersetzungspipeline. Da sie als Daten und nicht als Markup aufgezeichnet werden, hat die Replay-Sandbox sogar noch weniger zu tun – es gibt schlicht kein fremdes DOM zu rendern. Die hier verwendeten Begriffe erklärt das Glossar; die Technik hinter dem Recorder beschreibt unser Blog.
