ScaleBun
Skip to article

Engage

react-nativeDeveloperv0.1.0-alpha.4

The ScaleBun.engage namespace — 16 members.

Updated Reviewed

Engage surface namespace (foundation: transport + native push-token plumbing).

TypeScript
import ScaleBun from '@scalebun/react-native';
ScaleBun.engage.<method>(…);

Members#

MemberSignature
getIdentifiedUserIdgetIdentifiedUserId(): string | undefined
fetchConfigfetchConfig(context?: EngageConfigContext): Promise<EngageConfigResponse | null>
trackCoachmarkEventtrackCoachmarkEvent(name: string, properties: Record<string, unknown>): void
clearInAppMessageCacheclearInAppMessageCache(): number
resetInAppStateresetInAppState(): number
flushEventsflushEvents(): void
debugFetchInAppMessagesdebugFetchInAppMessages(context?: EngageConfigContext): Promise<EngageConfigResponse['inAppMessages']>
submitResponsesubmitResponse(input: EngageResponseInput): void
submitResponseWithAttachmentssubmitResponseWithAttachments(input: EngageResponseInput, attachments: EngageAttachmentDraft[]): void
submitResponseConfirmedsubmitResponseConfirmed(input: EngageResponseInput, attachments: EngageAttachmentDraft[], opts: { responseId: string; onStage?: (stage: SubmitStage) => void }): Promise<void>
trackEventtrackEvent(input: EngageEventInput): void
trackSurveyImpressiontrackSurveyImpression(input: SurveyImpressionInput): void
emitRatingEventemitRatingEvent(input: RatingFunnelEventInput): void
requestStoreReviewrequestStoreReview(): Promise<boolean>
submitRatingsubmitRating(input: { rating: number; comment?: string; source?: 'in_app' | 'prompt' | 'manual'; clientRatingId?: string; }): void
registerForPushregisterForPush(): Promise<void>

Reference#

getIdentifiedUserId#

TypeScript
ScaleBun.engage.getIdentifiedUserId(): string | undefined

Current external identity, forwarded by the provider for segment targeting.

fetchConfig#

TypeScript
ScaleBun.engage.fetchConfig(context?: EngageConfigContext): Promise<EngageConfigResponse | null>

Fetch the versioned Engage config (campaigns + in-app messages).

trackCoachmarkEvent#

TypeScript
ScaleBun.engage.trackCoachmarkEvent(name: string, properties: Record<string, unknown>): void

Internal bridge used by the shared renderer to feed standalone tour analytics.

clearInAppMessageCache#

TypeScript
ScaleBun.engage.clearInAppMessageCache(): number

DEBUG/DEV ONLY — clear the persisted in-app/campaign frequency-cap state (every scalebun_engage_throttle:* key: impressions, showOnce/completed, cooldown). Lets a tester see throttled/dismissed messages again WITHOUT uninstalling the app. Does NOT change the device id (identity is preserved). Returns the number of cleared entries. NOT a substitute for the real fix (revision-scoped state + test-preview bypass already make normal Send Test work without this).

resetInAppState#

TypeScript
ScaleBun.engage.resetInAppState(): number

DEBUG/DEV ONLY — alias of {@link clearInAppMessageCache} with the broader name used in docs. Resets all on-device in-app frequency/dismiss/impression state so the next config poll can show messages again. Identity (device id) is untouched.

flushEvents#

TypeScript
ScaleBun.engage.flushEvents(): void

Force an immediate flush of queued in-app events. The provider calls this right after a TEST preview's impression/dismiss ACK so the backend consumes the one-shot preview row promptly — a fast close→kill→reopen can't re-serve a still-delivered test. Best-effort, never throws.

debugFetchInAppMessages#

TypeScript
ScaleBun.engage.debugFetchInAppMessages(context?: EngageConfigContext): Promise<EngageConfigResponse['inAppMessages']>

DEBUG/DEV ONLY — force a fresh config fetch (deviceId in context) and return the in-app messages the backend is serving THIS device right now, including any queued test previews (preview:true). Use it to verify Send Test targeting/ delivery without rendering. Logs a one-line summary for the dev console.

submitResponse#

TypeScript
ScaleBun.engage.submitResponse(input: EngageResponseInput): void

Upload a survey/NPS/feedback response (idempotent, rides the outbox).

submitResponseWithAttachments#

TypeScript
ScaleBun.engage.submitResponseWithAttachments(input: EngageResponseInput, attachments: EngageAttachmentDraft[]): void

[P3-e] Submit a response carrying native attachments (screenshot/voice). Presigns + PUTs bytes direct to storage, then enqueues the response with key-only metadata linked by responseId. Falls back to a plain response (no media) when storage is disabled. Best-effort, never throws.

submitResponseConfirmed#

TypeScript
ScaleBun.engage.submitResponseConfirmed(input: EngageResponseInput, attachments: EngageAttachmentDraft[], opts: { responseId: string; onStage?: (stage: SubmitStage) => void }): Promise<void>

[Slice D5] CONFIRMED response submit for the in-prompt submitting→success→error UI. UNLIKE submitResponse*, this AWAITS real server persistence (presign+PUT any audio/screenshot bytes, then a direct response POST) and REJECTS on failure so the caller can show a retryable error. Idempotent: pass the SAME responseId on retry — both response and attachments de-dupe server-side. Used by EVERY question type.

trackEvent#

TypeScript
ScaleBun.engage.trackEvent(input: EngageEventInput): void

Upload an in-app impression/click/dismiss event (idempotent, rides the outbox).

trackSurveyImpression#

TypeScript
ScaleBun.engage.trackSurveyImpression(input: SurveyImpressionInput): void

Upload an idempotent survey shown/started funnel beacon.

emitRatingEvent#

TypeScript
ScaleBun.engage.emitRatingEvent(input: RatingFunnelEventInput): void

Emit a rating-funnel tracking event (ratings-rebuild CONTRACT §1.2). These are dimensioned FACTS feeding the Overview funnel — NOT campaign responses (D1) — so they ride their own /ingestion/rating-events lane. Idempotent (client eventId, D8). Best-effort, never throws.

requestStoreReview#

TypeScript
ScaleBun.engage.requestStoreReview(): Promise<boolean>

Trigger the native in-app review sheet (Play In-App Review on Android, SKStoreReviewController on iOS) — the genuinely-native leg of the rating funnel (D5). Resolves true ONLY when the OS flow ran/resolved after a positive route, so the caller emits store_redirect_clicked solely on a true result. Fail-soft: resolves false when native review is unavailable.

submitRating#

TypeScript
ScaleBun.engage.submitRating(input: { rating: number; comment?: string; source?: 'in_app' | 'prompt' | 'manual'; clientRatingId?: string; }): void

Submit a 1–5 app-store rating via the EXISTING app-rating lane (D1 keeps ratings a distinct funnel — NOT submitResponse). Delegates to the facade's submitRating, threading the renderer's clientRatingId for idempotency (D8). Used by the RATING_PROMPT render branch.

registerForPush#

TypeScript
ScaleBun.engage.registerForPush(): Promise<void>

Acquire the native push token (FCM/APNs) and register it for delivery. Subscribes to native token-refresh (rotation) so the backend always holds the live token. Fail-soft: no-op when native push is unavailable.

Notes#

engage is the largest namespace here and the one whose scope is easiest to overestimate. It covers in-app messaging, survey and rating responses, the store-review prompt, and push registration.

Ordering#

  1. init(), then identify(), then anything targeted

    getIdentifiedUserId() returning undefined is the check for whether targeting can work at all. An unidentified user cannot be reached by an audience built from people.

  2. fetchConfig() before you expect a message

    Nothing is presented from configuration you have not fetched. It takes an optional context, which is what lets targeting depend on where the user currently is.

  3. Submit a response once, and prefer the confirmed variant when it matters

    submitResponse is fire-and-forget. submitResponseConfirmed awaits and reports stage progress, which is what you want when the user is watching a spinner or when attachments are involved.

  4. flushEvents() before a boundary you may not survive

    Sign-out, or the end of a flow. Otherwise let it batch.

Members worth specific care#

  • requestStoreReview() returns a boolean, and on iOS that boolean does not mean the user rated — or even that the prompt appeared. The OS decides, silently rate-limits, and reports nothing back. See Ratings for what is and is not measurable.

  • submitRating takes an optional clientRatingId, which exists for idempotency. Generate one per rating and reuse it on retry, or a resubmitted rating counts twice.

  • clearInAppMessageCache() and resetInAppState() return the number of entries cleared. They are development and support tools — calling them in a normal app flow re-presents messages the user has already dismissed.

  • registerForPush() overlaps with push and with enablePush() on the facade. Pick one path.

  • submitResponseWithAttachments uploads user-provided files. Whatever the user attaches leaves the device — worth stating in your own UI.

Limits and edge cases#

  • These calls do not throw and are silent in release builds, so a failed submission looks exactly like a successful one.

  • Suppression is enforced server-side. A user on a suppression list is not messaged regardless of what you fetch or submit.

  • Cached messages are per device. Clearing on one device does not clear another.

Engage · API reference · React Native SDK · ScaleBun