ScaleBun
Skip to article

Engage

react-nativeDeveloper

In-app messages, surveys, NPS and ratings rendered by one overlay — plus the frequency capping that stops it becoming spam.

Updated Reviewed

Engage renders campaigns inside your app: in-app messages, surveys, NPS prompts, rating requests and coachmarks. One shared overlay renders all of them, so a new campaign type needs no app release.

Wrap your app#

App.tsxTSX
import { EngagePromptProvider } from '@scalebun/react-native';
export default function App() {  return (    <EngagePromptProvider>      <NavigationContainer>{/* screens */}</NavigationContainer>    </EngagePromptProvider>  );}

Place it inside any navigation container but outside your screens, so a prompt survives navigation and renders above whatever is on screen.

Trigger a prompt#

TSX
import { useEngagePrompt } from '@scalebun/react-native';
function OrderComplete() {  const engage = useEngagePrompt();
  useEffect(() => {    // The backend decides whether anything actually shows.    engage.showPrompt({ event: 'order_completed' });  }, []);}

You are signalling that a moment has occurred — not commanding a prompt. Whether one appears depends on targeting, frequency caps and whether a campaign is live. That separation is the point: campaign timing is changed in the dashboard, not in a release.

Anchors and inline placement#

Coachmarks need to point at something. Register an anchor:

TSX
import { ScaleBunAnchor } from '@scalebun/react-native';
<ScaleBunAnchor id="filter-button">  <FilterButton /></ScaleBunAnchor>

For a message that sits in your layout rather than floating over it:

TSX
import { ScaleBunInlineSlot } from '@scalebun/react-native';
<ScaleBunInlineSlot id="home-banner" />

An inline slot renders nothing when no campaign targets it, so it is safe to leave in place permanently — no conditional wrapper needed.

Frequency capping#

Impressions, dismissals and completions are persisted on the device. This is what stops Engage becoming spam: a message marked show-once stays dismissed across launches and reinstalls of the JS bundle.

Seeing what the backend is serving#

TypeScript
const messages = await ScaleBun.engage.debugFetchInAppMessages();

Forces a fresh config fetch and returns the in-app messages targeted at this device right now, including queued test previews. This is the fastest way to tell a targeting problem from a rendering problem: if the message is not in this list, the issue is targeting or eligibility, not your overlay.

Both of these are development helpers. Neither belongs on a release path.

Collecting responses#

Survey, NPS and feedback answers upload through the outbox, so they survive offline:

TypeScript
ScaleBun.engage.submitResponse({  campaignId: 'cmp_123',  answers: [{ questionId: 'q1', value: 9 }],});

With a screenshot or voice note attached:

TypeScript
ScaleBun.engage.submitResponseWithAttachments(response, attachments);

Attachments are presigned and uploaded directly to storage, then the response is enqueued referencing them. If storage is disabled it degrades to a plain response rather than failing — the answer is worth more than the attachment.

Ratings#

TypeScript
ScaleBun.submitRating({ rating: 5, comment: 'Works well' });

Rating campaigns can route a high rating to the platform store review prompt and a low one to a feedback form, so you are not asking unhappy users to review you publicly. That routing is configured in the dashboard.

Custom renderers#

The overlay resolves a renderer per campaign type from a registry, so you can replace one with your own component while leaving the rest alone:

TypeScript
import { PROMPT_RENDERERS, INAPP_RENDERERS } from '@scalebun/react-native';

Only do this when your design system genuinely cannot be expressed through campaign configuration — a custom renderer is app code, so changing it needs a release, which gives back the main advantage of using Engage at all.

Engage · Engagement · React Native SDK · ScaleBun