Changelark for React Native

Show What's new after every update, with votes and anonymous comments, in React Native apps on iOS and Android. It works with Expo and bare React Native.

Install

npm install changelark-react-native @react-native-async-storage/async-storage expo-application

The app version is read from your native build, so you never type it. expo-application does that in Expo apps; in bare React Native, install react-native-device-info instead. In Expo Go, pass appVersion yourself, since Expo Go reports its own version.

No npm access? Download the package and run npm install ./changelark-react-native-0.1.0.tgz.

Wrap your app

Add the provider once, around your navigation. Use the public app key from the Install tab in the dashboard.

import { ChangelarkProvider } from "changelark-react-native";

export default function App() {
  return (
    <ChangelarkProvider appKey="clk_…">
      <RootNavigator />
    </ChangelarkProvider>
  );
}

When the sheet appears

  1. First install: the version is recorded quietly. Nobody is interrupted.
  2. New version: its notes show once, the first time the app opens.
  3. Seen or older version: skipped.
  4. Notes not published yet: it waits and tries again on the next launch (up to 3 days).
  5. You replied to someone: on their next launch without new notes, the sheet opens on the feedback chat so they see your answer. Once per reply.

Set treatFirstLaunchAsUpdate to show the notes on first install too. The sheet follows the phone's light or dark appearance; in Expo, set "userInterfaceStyle": "automatic" in app.json, because the default template locks apps to light.

Votes and comments

People vote on the update and on comments without an account. They accept the community guidelines once before commenting, and can reply, report, block someone, or delete their own comment. You reply as the developer from the dashboard.

Bug reports

Under the reactions there's a Report a bug link with a short private form. Reports land in the Bugs tab of your inbox. To attach a screenshot of your app, pass captureScreenshot; with react-native-view-shot it's one line:

import { captureRef } from "react-native-view-shot";

const root = useRef(null);

<ChangelarkProvider
  appKey="clk_…"
  captureScreenshot={() => captureRef(root, { format: "jpg", quality: 0.6, result: "base64" })}
>
  <View ref={root} collapsable={false} style={{ flex: 1 }}>
    <RootNavigator />
  </View>
</ChangelarkProvider>

Without it, reports are text only. You can also show the form in your own screen with <BugReport onBack={…} />, or send one with client.reportBug({ text, screenshot }).

Languages

The package sends the phone's language. If you added a translation for it in the dashboard, the sheet shows that; otherwise your original notes.

Is the app key safe to ship?

Yes. It's a public key (it starts with clk_), so think of it as a web address, not a password. Anyone can read it out of your app, and that's fine: it only picks which app's notes to load and where anonymous comments and votes go. It can't log into the dashboard, change releases, see private data or moderate.

<ChangelarkProvider
  appKey="clk_…"
  getAppProof={async (challenge, { attest }) => {
    // From your App Attest / Play Integrity native module (not part of this package).
    if (Platform.OS === "android") {
      return { kind: "play", token: await PlayIntegrity.requestToken({ nonce: challenge }) };
    }
    const clientDataHash = sha256(challenge);
    return attest
      ? { kind: "apple", keyId, attestation: await AppAttest.attestKey(keyId, clientDataHash) }
      : { kind: "apple", keyId, assertion: await AppAttest.generateAssertion(keyId, clientDataHash) };
  }}
>

Open it yourself

import { useChangelark } from "changelark-react-native";

function WhatsNewButton({ release }) {
  const { open } = useChangelark();
  return <Button title="What's new" onPress={() => open(release)} />;
}