🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@sonenta/feedback

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sonenta/feedback

Sonenta End-User Translation Evaluation widget: let your end users rate and suggest translations. React (web) + React Native / Expo.

latest
Source
npmnpm
Version
1.6.1
Version published
Maintainers
1
Created
Source

@sonenta/feedback

Embed a Sonenta End-User Translation Evaluation widget in your app. Your end users accept a short ToS, then rate (5-star) and suggest alternatives for the translations on screen. You moderate everything from the Sonenta dashboard — nothing auto-publishes.

  • @sonenta/feedback/react — React (web)
  • @sonenta/feedback/native — React Native / Expo
  • @sonenta/feedback/core — framework-agnostic client (advanced)

MIT. Add-on available from the Pro plan upward.

Install

npm i @sonenta/feedback

react (and react-native for the native entry) are peer deps.

Architecture

@sonenta/feedback is a plugin of your existing @sonenta/*-i18n provider — not a second context/provider. You add it to the i18n provider's plugins slot; it reuses that provider's apiBase / projectUuid / locale (no re-config) and never re-renders your app when the panel opens. The sessionId is minted server-side — you don't supply a cohort/session id.

React

import { SonentaProvider } from "@sonenta/react-i18next";
import { feedbackPlugin } from "@sonenta/feedback/react";

const feedbackCtl = { current: null };

<SonentaProvider
  token="snt_live_…"
  projectUuid="<project-uuid>"
  defaultLocale="fr"
  plugins={[
    feedbackPlugin({
      tosVersion: "2026-05-18",
      keys: [{ namespace: "common", key: "home.title" }], // or omiti18n registry
      controllerRef: feedbackCtl,                          // imperative handle
    }),
  ]}
>
  <App />
</SonentaProvider>;

// trigger from your own CTA — no hook, no extra provider:
<button onClick={() => feedbackCtl.current?.open()}>Rate translations</button>;

feedbackPlugin also accepts onReady(controller), and optional apiBase / projectId / language overrides (defaults come from the i18n provider config).

React Native / Expo

import { feedbackPlugin } from "@sonenta/feedback/native";
// same plugin API; renders a bottom-sheet <Modal> instead of a side panel.
// add it to your @sonenta/react-i18next provider's `plugins` slot.

Key discovery

If @sonenta/*-i18n is on the page it exposes a tiny key registry; the widget reads the on-screen keys from it automatically (scope: "current-view", the default).

When our capture is wrong, you can always correct it — per open:

// The host knows what is on this screen. The host wins.
await controller.open({
  keys: [{ namespace: "common", key: "home.title" }],
});

Precedence: open({ keys }) → the static keys plugin option → whatever the current-view capture found.

1.3.1 — this README used to promise that fallback and the API did not allow it. controller.open() took no argument, and the only keys was the STATIC plugin option: the same list on every screen, which is the opposite of a per-view fallback. So on the night our capture broke, the workaround this page told you to use was unreachable. open({ keys }) makes it true. If you read the old sentence and could not find the door, it was not there — that is on us.

With tos: "modal" (the default) the SDK shows its own consent step and you do nothing.

With tos: "skip" you own consent, and you must call controller.startSession() once per app start — not once per user, ever.

// on every launch, after your own consent screen has been satisfied at least once:
if (userHasConsentedBefore) await controller.startSession();

It used to be called acceptTos(), and the name was the bug. "Accept the ToS" reads like a one-time act, so an integrator called it once, persisted their own flag, and their panel never unlocked again. acceptTos() still works as a deprecated alias — but nobody calls startSession() once in the life of an app, which is the point.

Why: acceptTos() is the session bootstrap, not a consent record. It mints the scoped token the client authenticates with, and that token lives in memory — this package persists nothing client-side. A cold start begins with no session, so if you persist your own "already accepted" flag and skip the call, the panel stays locked forever while your user's consent sits correctly recorded on the server.

It is idempotent within a process, and the server records consent once, so calling it on every launch is correct and cheap.

This is a trap our own comments set: they claimed the SDK and an external ToS page "share the same persisted token bundle". There is no persisted bundle, and a customer built on that sentence. Making consent survive a restart without this call (a restoreSession() / storage adapter) is a real feature, and it is on the backlog — not something you have today.

Behaviour

Ratings/suggestions are debounced + batched and sent best-effort — the widget never blocks or breaks your app. See CONTRACT.md for the exact wire shape.

Keywords

i18n

FAQs

Package last updated on 06 Aug 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts