Four SDKs, one version
Flutter, Expo, Web/React and Swift ship together and always carry the same version โ today 2.0. Each one brings the same tester experience into your app.
Flutter
For Flutter apps on Android and iOS.
Install ยท pub.devflutter pub add testerpaykit Expo / React Native
For Expo and React Native apps.
Install ยท npmnpx expo install @testerpaykit/expo Web / React
For web apps built with React, Next.js or Vite.
Install ยท npmnpm install @testerpaykit/react Swift (iOS, macOS)
For native iOS and macOS apps, with a built-in SwiftUI tester experience.
PackageSwift Package โ on request Not on a public package registry yet. Write to us and we send you the package.
What all four can do
- โReport a bug: form with screenshot and annotation, voice, quick actions
- โGeneral feedback
- โRetest after a fix, with a verdict per step
- โEarnings in the tester menu, guided tour, German and English
- โLive link to Claude Code (beta): Claude sees the screen and your notes and can tap through your own app
- โChecklist "What to test": testers tick the steps off in the app
AI runs (auto test, AI retest after a fix) work with Flutter and Expo only.
At a glance
| Feature | Flutter | Expo | Web | Swift |
|---|---|---|---|---|
| Bug report, feedback, retest | โ | โ | โ | โ |
| Live link to Claude Code (beta) | โ | โ | โ | โ |
| Checklist "What to test" | โ | โ | โ | โ |
| AI runs: auto test, AI retest | โ | โ | โ | โ |
Quick examples
import 'package:flutter/material.dart';
import 'package:testerpaykit/testerpaykit.dart';
final _navigatorKey = GlobalKey<NavigatorState>();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final tpk = await TesterPayKit.initialize(
config: TesterPayKitConfig(
projectId: '<project-uuid>',
apiBaseUrl: 'https://api.testerpaykit.com',
enableTesterMode: true,
),
);
runApp(MaterialApp(
navigatorKey: _navigatorKey,
navigatorObservers: [tpk.navigatorObserver],
builder: (context, child) => TesterPayKitWrapper(
sdk: tpk,
navigatorKey: _navigatorKey,
child: child ?? const SizedBox.shrink(),
),
home: const HomeScreen(),
));
} import { TpkExpo, useShake } from '@testerpaykit/expo';
import { useEffect, useState } from 'react';
export function App() {
const [tpk, setTpk] = useState<TpkExpo | null>(null);
useEffect(() => {
TpkExpo.init({
projectId: '<project-uuid>',
testerCode: '<tester-invite-code>',
}).then(setTpk);
}, []);
useShake({
enabled: !!tpk,
onShake: () => {
tpk?.submitBug({
title: 'Shake-reported bug',
description: 'Reported by shaking the device.',
currentScreen: 'HomeScreen',
severity: 'medium',
});
},
});
return null;
} import { useEffect, useState } from 'react';
import { TesterPayKit } from '@testerpaykit/sdk';
import { TesterPayKitApiClient } from '@testerpaykit/api-client';
import { IndexedDBAdapter } from '@testerpaykit/storage-browser';
import { TpkTesterHub } from '@testerpaykit/react';
export function Tpk({ screen }: { screen: string }) {
const [sdk, setSdk] = useState<TesterPayKit | null>(null);
useEffect(() => {
const instance = new TesterPayKit({
apiKey: '',
projectId: '<project-uuid>',
testerId: '<tester-invite-code>',
deviceId: crypto.randomUUID(),
storage: new IndexedDBAdapter(),
apiClient: new TesterPayKitApiClient({ apiKey: '' }),
deviceMetadata: { os: 'Web', osVersion: navigator.userAgent, deviceModel: 'browser', appVersion: '1.0.0', sdkVersion: '2.0.0', timezoneOffset: -new Date().getTimezoneOffset() },
appMetadata: { bundleId: 'com.example.web', version: '1.0.0', buildNumber: '1' },
autoStartSession: true,
});
void instance.init().then(() => setSdk(instance));
}, []);
return sdk ? <TpkTesterHub sdk={sdk} currentScreen={screen} /> : null;
} The example also imports @testerpaykit/sdk, @testerpaykit/api-client and @testerpaykit/storage-browser; with pnpm, add them explicitly.
import SwiftUI
import TesterPayKit
let sdk = try await TesterPayKit.initialize(
config: TesterPayKitConfig(
projectId: "<project-uuid>",
testerCode: "<tester-invite-code>",
apiBaseURL: URL(string: "https://api.testerpaykit.com")!
)
)
try await sdk.startSession()
ContentView()
.tpkFeedbackOverlay() Ready to integrate?
Create a project account and configure the SDK for your app. Existing accounts can sign in to the web console.