@getrheo/rheo-skill 2.5.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -12
- package/package.json +7 -5
- package/rheo/SKILL.md +20 -11
- package/rheo/rheo-best-practices/SKILL.md +32 -19
- package/rheo/rheo-best-practices/examples/swiftui-install-snippet.md +3 -1
- package/rheo/rheo-best-practices/examples/web-install-snippet.md +26 -0
- package/rheo/rheo-best-practices/references/analytics.md +104 -0
- package/rheo/rheo-best-practices/references/engage.md +95 -0
- package/rheo/rheo-best-practices/references/implement-workflow.md +20 -15
- package/rheo/rheo-best-practices/references/integrations.md +38 -4
- package/rheo/rheo-best-practices/references/product-model.md +66 -0
- package/rheo/rheo-best-practices/references/react-native-bare.md +3 -1
- package/rheo/rheo-best-practices/references/react-native-expo.md +5 -4
- package/rheo/rheo-best-practices/references/react-web.md +78 -0
- package/rheo/rheo-best-practices/references/swiftui.md +20 -49
- package/rheo/rheo-best-practices/references/troubleshooting.md +15 -2
- package/rheo/rheo-flow-import/SKILL.md +4 -2
- package/rheo/rheo-flow-import/references/capabilities.md +10 -1
- package/rheo/rheo-flow-import/references/flow-spec.md +11 -1
- package/rheo/rheo-flow-import/references/import-workflow.md +1 -1
- package/rheo/rheo-flow-import/references/manifest-agent-profile-fallback.md +1 -1
- package/rheo/rheo-flow-import/references/manifest-rules.md +1 -1
- package/rheo/rheo-flow-import/references/publish-gates.md +2 -2
- package/rheo/rheo-flow-import/references/react-native-source-patterns.md +3 -1
- package/rheo/rheo-flow-import/references/swiftui-source-patterns.md +2 -0
- package/rheo/rheo-flow-import/scripts/lib/rheo-cli.mjs +3713 -259
package/README.md
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
# @getrheo/rheo-skill
|
|
2
2
|
|
|
3
|
-
Current release: **`
|
|
3
|
+
Current release: **`3.0.0`** on npm (`PLATFORM_SDK_VERSION` in `scripts/publish-package-registry.mjs`). Public source: [getrheo/rheo-skill](https://github.com/getrheo/rheo-skill) (mirrored from this private monorepo via `pnpm extract:oss-repos`).
|
|
4
4
|
|
|
5
5
|
Source and build tooling for the **`rheo`** agent skill — a single, self-contained
|
|
6
|
-
skill with two sub-skills
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
skill with two sub-skills. Rheo is one SDK and one Customer across **Analytics**,
|
|
7
|
+
**Convert**, and **Engage**.
|
|
8
|
+
|
|
9
|
+
- **`rheo/rheo-best-practices`** — how to install and wire that SDK on **Expo**,
|
|
10
|
+
**bare React Native**, and **React web** (SwiftUI / Flutter SDK install is
|
|
11
|
+
coming soon): product analytics, Convert flows, Engage `identify` / `track`,
|
|
12
|
+
integrations, and auth. Pure guidance, no scripts.
|
|
13
|
+
- **`rheo/rheo-flow-import`** — the Convert authoring path: analyze an existing
|
|
14
|
+
mobile flow and export it as a compliant Rheo `FlowManifest`, plus self-contained
|
|
15
|
+
`node` scripts (audit, scaffold, validate, audit-publish, normalize, summary,
|
|
16
|
+
profile).
|
|
14
17
|
|
|
15
18
|
## The deliverable is `rheo/`
|
|
16
19
|
|
|
@@ -25,8 +28,9 @@ rheo/
|
|
|
25
28
|
├── SKILL.md # router → rheo-best-practices / rheo-flow-import
|
|
26
29
|
├── rheo-best-practices/
|
|
27
30
|
│ ├── SKILL.md
|
|
28
|
-
│ ├── references/ #
|
|
29
|
-
│
|
|
31
|
+
│ ├── references/ # product-model, analytics, engage, react-web,
|
|
32
|
+
│ │ # install-* , integrations, implement-workflow, troubleshooting
|
|
33
|
+
│ └── examples/ # install snippets (RN, SwiftUI, web)
|
|
30
34
|
└── rheo-flow-import/
|
|
31
35
|
├── SKILL.md
|
|
32
36
|
├── references/ # import-workflow, flow-spec, capabilities (generated), manifest-rules,
|
|
@@ -74,5 +78,6 @@ back to `rheo/rheo-flow-import/references/manifest-agent-profile-fallback.md` of
|
|
|
74
78
|
## Compatibility
|
|
75
79
|
|
|
76
80
|
- Manifest schema version: `7`
|
|
77
|
-
-
|
|
81
|
+
- SDK surfaces this skill installs today: React Native (Expo and bare), React web (`@getrheo/react`). SwiftUI / Flutter SDK install is coming soon; SwiftUI **flow import** remains in rheo-flow-import
|
|
82
|
+
- Engage `identify` and `track` ship on web (`@getrheo/react`) and React Native
|
|
78
83
|
- Requires Node.js 20+
|
package/package.json
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getrheo/rheo-skill",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Rheo agent skill — SDK
|
|
5
|
+
"description": "Rheo agent skill — Analytics, Convert, and Engage SDK guidance, plus flow manifest import tooling.",
|
|
6
6
|
"main": "./src/index.ts",
|
|
7
7
|
"types": "./src/index.ts",
|
|
8
8
|
"exports": {
|
|
9
|
-
".": "./src/index.ts"
|
|
9
|
+
".": "./src/index.ts",
|
|
10
|
+
"./flow-import-cli": "./rheo/rheo-flow-import/scripts/lib/rheo-cli.mjs",
|
|
11
|
+
"./package.json": "./package.json"
|
|
10
12
|
},
|
|
11
13
|
"dependencies": {
|
|
12
|
-
"@getrheo/contracts": "
|
|
13
|
-
"@getrheo/flow-runtime": "
|
|
14
|
+
"@getrheo/contracts": "3.0.0",
|
|
15
|
+
"@getrheo/flow-runtime": "3.0.0",
|
|
14
16
|
"zod": "^3.23.8"
|
|
15
17
|
},
|
|
16
18
|
"devDependencies": {
|
package/rheo/SKILL.md
CHANGED
|
@@ -1,32 +1,41 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: rheo
|
|
3
|
-
description: Work with Rheo,
|
|
3
|
+
description: Work with Rheo, a growth platform with one SDK and one Customer across Analytics, Convert, and Engage. Use when a user wants to install or wire the Rheo SDK on Expo, bare React Native, or React web (SwiftUI/Flutter SDK install is coming soon), record product analytics, attribute RevenueCat or Superwall revenue, publish onboarding or paywall flows, wire auth or integrations, identify a customer for lifecycle email, or import an existing mobile flow (React Native or SwiftUI source) into a FlowManifest. Routes to the `rheo-best-practices` and `rheo-flow-import` sub-skills.
|
|
4
4
|
compatibility: Requires Node.js 20+. rheo-flow-import scripts are fully self-contained (no install step). Internet access fetches the latest Manifest Agent Profile; a bundled fallback works offline.
|
|
5
5
|
metadata:
|
|
6
|
-
rheo-version: "
|
|
6
|
+
rheo-version: "3.0.0"
|
|
7
7
|
manifest-schema-version: "7"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Rheo
|
|
11
11
|
|
|
12
|
-
Rheo is a
|
|
12
|
+
Rheo is a growth platform for mobile and web apps. One SDK and one Customer cover three products:
|
|
13
|
+
|
|
14
|
+
- **Analytics** records sessions, page and screen views, custom events, and revenue from RevenueCat, Superwall, and Stripe.
|
|
15
|
+
- **Convert** renders onboarding, paywalls, and experiments from a hosted `FlowManifest`. The host passes a channel id. Rheo decides which flow revision or experiment arm to serve.
|
|
16
|
+
- **Engage** sends lifecycle email through the app's own provider. Push and outbound webhooks are not SDK surfaces yet.
|
|
17
|
+
|
|
18
|
+
The same Customer profile sits behind all three. Start with the product the user asked for. Turning on the next one reuses the provider and the id.
|
|
19
|
+
|
|
20
|
+
This skill helps an agent do two jobs. Pick the sub-skill that matches the request and read its `SKILL.md` before doing anything else.
|
|
13
21
|
|
|
14
22
|
## Routing
|
|
15
23
|
|
|
16
24
|
| The user wants to… | Use sub-skill | Read |
|
|
17
|
-
|
|
18
|
-
| Install the
|
|
19
|
-
| Analyze an existing mobile onboarding
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| Install the SDK, record product analytics, attribute revenue, render `Flow` / `FlowView`, wire RevenueCat / Superwall / Stripe / AppsFlyer / auth, or call `identify` / `track` for Engage | **rheo-best-practices** | [rheo-best-practices/SKILL.md](rheo-best-practices/SKILL.md) |
|
|
27
|
+
| Analyze an existing mobile onboarding, paywall, or setup flow and export it as a compliant Convert `FlowManifest` (or validate/repair a manifest) | **rheo-flow-import** | [rheo-flow-import/SKILL.md](rheo-flow-import/SKILL.md) |
|
|
20
28
|
|
|
21
|
-
If a request spans both (
|
|
29
|
+
If a request spans both (for example "import my onboarding and wire the SDK"), run **rheo-flow-import** to produce the manifest first, then **rheo-best-practices** to implement the SDK.
|
|
22
30
|
|
|
23
31
|
## What each sub-skill is
|
|
24
32
|
|
|
25
|
-
- **rheo-best-practices**
|
|
26
|
-
- **rheo-flow-import**
|
|
33
|
+
- **rheo-best-practices** is guidance for the host app. It detects the stack, installs one SDK, and wires only the products requested: Analytics on `RheoProvider`, Convert on a channel, Engage via `identify` and `track` (web and React Native). No code is run by the skill itself.
|
|
34
|
+
- **rheo-flow-import** is the Convert authoring path: guidance plus self-contained tooling. It reads React Native or SwiftUI source, scaffolds a manifest, and validates publish gates. It does not install the SDK or configure Analytics or Engage.
|
|
27
35
|
|
|
28
36
|
## Shared rules
|
|
29
37
|
|
|
30
|
-
- Never put secrets, API keys, tokens, or private backend URLs in a manifest or
|
|
31
|
-
- The Rheo manifest contract is the source of truth. rheo-flow-import ships a generated capability cheat-sheet ([rheo-flow-import/references/capabilities.md](rheo-flow-import/references/capabilities.md)) and a Manifest Agent Profile fetch
|
|
38
|
+
- Never put secrets, API keys, tokens, or private backend URLs in a manifest, a snippet, or client code.
|
|
39
|
+
- The Rheo manifest contract is the source of truth for Convert. rheo-flow-import ships a generated capability cheat-sheet ([rheo-flow-import/references/capabilities.md](rheo-flow-import/references/capabilities.md)) and a Manifest Agent Profile fetch. Trust those over memory.
|
|
32
40
|
- Only install packages or edit a host app's code when the user explicitly asks for implementation. Analysis and manifest generation never modify the host app.
|
|
41
|
+
- One React Native flavor per app: `@getrheo/react-native-expo` or `@getrheo/react-native-bare`, never both. Web is `@getrheo/react`. SwiftUI / Flutter **SDK install** is coming soon — do not add those packages for customers yet. SwiftUI **flow import** (source → manifest) remains available via rheo-flow-import.
|
|
@@ -1,47 +1,60 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: rheo-best-practices
|
|
3
|
-
description: Install and wire the Rheo SDK
|
|
3
|
+
description: Install and wire the Rheo SDK for Analytics, Convert, and Engage on Expo, bare React Native, or React web. Use when a user asks to install Rheo, add @getrheo/react-native-expo or @getrheo/react-native-bare or @getrheo/react, mount RheoProvider, record product analytics (logEvent, screen, web consent), render Flow, wire terminal callbacks, configure RevenueCat, Superwall, Stripe, or AppsFlyer, call identify for marketing consent, or call track for Engage automations on web or React Native. Do not install RheoSwiftUI or Flutter — those SDK installs are coming soon. Part of the `rheo` skill.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Rheo — Best Practices (SDK implementation)
|
|
7
7
|
|
|
8
|
-
Use this sub-skill when the user wants Rheo **running in their app**.
|
|
8
|
+
Use this sub-skill when the user wants Rheo **running in their app**. Read [references/product-model.md](references/product-model.md) first. Rheo is one SDK and one Customer across Analytics, Convert, and Engage. Wire the products they asked for. Leave the others unwired.
|
|
9
|
+
|
|
10
|
+
The goal is a minimal, reversible integration: one provider, stable identity, and the calls that product actually uses. Do not hard-code secrets. Do not delete the existing onboarding on the first Convert pass.
|
|
9
11
|
|
|
10
12
|
## When to act
|
|
11
13
|
|
|
12
|
-
Only install packages or edit host code when the user explicitly asks for implementation. If they only ask
|
|
14
|
+
Only install packages or edit host code when the user explicitly asks for implementation. If they only ask how Rheo would fit, explain using these references and stop.
|
|
13
15
|
|
|
14
16
|
## Workflow
|
|
15
17
|
|
|
16
|
-
1. **
|
|
18
|
+
1. **Read the product model** in [references/product-model.md](references/product-model.md). Confirm which products this request includes. Analytics starts when `RheoProvider` mounts. Convert needs a channel and `Flow` / `FlowView`. Engage needs `identify`, and `track` on web or React Native.
|
|
19
|
+
2. **Detect the host stack** and read the matching reference:
|
|
17
20
|
- React Native + Expo → [references/react-native-expo.md](references/react-native-expo.md)
|
|
18
21
|
- React Native bare (no `expo` dependency) → [references/react-native-bare.md](references/react-native-bare.md)
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
3.
|
|
22
|
-
4.
|
|
23
|
-
5.
|
|
22
|
+
- React web → [references/react-web.md](references/react-web.md)
|
|
23
|
+
- SwiftUI or Flutter → **stop**. SDK install is coming soon ([references/swiftui.md](references/swiftui.md)). Offer Expo / bare / web, or route SwiftUI **source → manifest** work to rheo-flow-import.
|
|
24
|
+
3. Read [references/implement-workflow.md](references/implement-workflow.md) for the shared steps (identity, dashboard values, provider, verification).
|
|
25
|
+
4. **Analytics** → [references/analytics.md](references/analytics.md). On web, leave consent `pending` until the site grants it.
|
|
26
|
+
5. **Convert** → mount `Flow` / `FlowView` with a channel public id, preserve a rollback path, and when the flow uses paywalls, attribution, auth, permissions, links, or in-app review, read [references/integrations.md](references/integrations.md) before wiring anything.
|
|
27
|
+
6. **Engage** → [references/engage.md](references/engage.md). Call `identify` only for a real email and consent choice. Call `track` only for an automation or segment trigger (web or React Native).
|
|
28
|
+
7. Use the install snippets in [examples/](examples) as a starting point, adapted to the project's package manager and conventions.
|
|
29
|
+
8. If something behaves unexpectedly, consult [references/troubleshooting.md](references/troubleshooting.md).
|
|
24
30
|
|
|
25
31
|
## Hard rules
|
|
26
32
|
|
|
27
|
-
- **One flavor per app.** Install **either** `@getrheo/react-native-expo` **or** `@getrheo/react-native-bare`, never both.
|
|
28
|
-
- **
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
33
|
+
- **One flavor per native app.** Install **either** `@getrheo/react-native-expo` **or** `@getrheo/react-native-bare`, never both. Web uses `@getrheo/react`. Do **not** install `RheoSwiftUI` or Flutter packages until GA (coming soon).
|
|
34
|
+
- **One provider.** Mount `RheoProvider` once. Product analytics starts there, even when no flow is showing.
|
|
35
|
+
- **Three event pipes.** `logEvent` is Analytics. Flow events are automatic. `track` is Engage (web and React Native). Do not use one to fake another.
|
|
36
|
+
- **Consent is `identify`.** Email on a flow answer or an event property does not grant marketing consent. `unknown` does not send.
|
|
37
|
+
- **No secrets in code.** `publishableKey` and `channelId` come from env/config or placeholders the user fills in. Never commit real keys. Email-provider credentials stay in the dashboard.
|
|
38
|
+
- **Production API:** SDK defaults use **`https://api.getrheo.io`**. Omit `apiBaseUrl` / `apiBaseURL` in production unless self-hosting. Never pair **`ob_pk_live_*`** keys with localhost.
|
|
39
|
+
- **Pass the channel public id**, not a flow id, to `Flow` / `FlowView`. Analytics and Engage do not need a channel.
|
|
31
40
|
- **Preserve the existing onboarding** as a fallback/rollback path (feature flag or route swap) unless the user explicitly asks to remove it.
|
|
32
41
|
- **Read local conventions first** (package manager, navigation, env handling) and keep edits localized to the integration entry point and app config.
|
|
33
|
-
- **RevenueCat
|
|
34
|
-
- **External Surface Nodes** need a host `externalSurfaces` registry keyed by Host key (`config.hostKey` or `surf_*` id; callbacks `onComplete` / `onBack` / `onDismiss`). No App settings toggle.
|
|
35
|
-
- **Do not add `request_app_review`** prompts unless the user explicitly asks
|
|
42
|
+
- **RevenueCat, Superwall, AppsFlyer, and Stripe are host integrations**, not SDK peers. Wire `fallback` for every Integration / External Surface Node. After RevenueCat or Superwall identify, call `setBillingIdentity` with that same id. Stripe dollars come from the webhook.
|
|
43
|
+
- **External Surface Nodes** need a host `externalSurfaces` registry keyed by Host key (`config.hostKey` or `surf_*` id; callbacks `onComplete` / `onBack` / `onDismiss`). No App settings toggle. They fail closed on web.
|
|
44
|
+
- **Do not add `request_app_review`** prompts unless the user explicitly asks. Apple discourages prompting from raw button taps.
|
|
45
|
+
- **Do not scaffold Engage push or outbound webhooks.**
|
|
36
46
|
- Run the **narrowest useful verification** (typecheck or a build of the touched module), not a full app build, unless asked.
|
|
37
47
|
|
|
38
48
|
## Final response
|
|
39
49
|
|
|
40
50
|
When you implement, report:
|
|
41
51
|
|
|
52
|
+
- Products wired (Analytics, Convert, Engage) and products left unwired.
|
|
42
53
|
- Files changed.
|
|
43
|
-
- SDK surface
|
|
44
|
-
- Dashboard values still needing real values (`publishableKey`, `channelId`).
|
|
45
|
-
-
|
|
54
|
+
- SDK surface (`RheoProvider`, and `Flow` / `FlowView` only if Convert was requested).
|
|
55
|
+
- Dashboard values still needing real values (`publishableKey`, `channelId` if Convert, web origin if web).
|
|
56
|
+
- Analytics calls added (`logEvent`, `screen`, web consent) or "provider only".
|
|
57
|
+
- Engage calls added (`identify`, `track`) or none.
|
|
58
|
+
- Integrations and auth callbacks wired, including `setBillingIdentity` when a billing SDK is present.
|
|
46
59
|
- Whether the legacy onboarding was preserved as a fallback.
|
|
47
60
|
- Verification run, or why it was skipped.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
# SwiftUI Install Snippet
|
|
1
|
+
# SwiftUI Install Snippet (coming soon — do not use for customer installs)
|
|
2
|
+
|
|
3
|
+
Public SwiftUI SDK install is **paused**. Do not add these products to a customer app until Developer Guide / marketing flip from “coming soon”. Prefer Expo, bare React Native, or React web install paths. For migrating an existing SwiftUI flow into Convert, use **rheo-flow-import** instead.
|
|
2
4
|
|
|
3
5
|
```swift
|
|
4
6
|
import SwiftUI
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# React web install snippet
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
pnpm add @getrheo/react
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Flow, RheoProvider, setAnalyticsConsent } from '@getrheo/react';
|
|
9
|
+
|
|
10
|
+
export const App = () => (
|
|
11
|
+
<RheoProvider
|
|
12
|
+
config={{
|
|
13
|
+
publishableKey: import.meta.env.VITE_RHEO_PUBLISHABLE_KEY,
|
|
14
|
+
// apiBaseUrl defaults to https://api.getrheo.io — omit in production
|
|
15
|
+
analytics: { consent: 'pending' },
|
|
16
|
+
}}
|
|
17
|
+
>
|
|
18
|
+
<Flow channelId={import.meta.env.VITE_RHEO_CHANNEL_ID} />
|
|
19
|
+
</RheoProvider>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const onAccept = () => setAnalyticsConsent('granted');
|
|
23
|
+
const onReject = () => setAnalyticsConsent('denied');
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Drop `Flow` when the task is Analytics only. For Engage, call `identify` after marketing opt-in and `track` for automation triggers.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Analytics
|
|
2
|
+
|
|
3
|
+
Product analytics records what people do in the app or site. It starts when `RheoProvider` mounts, including when no Convert flow is showing. Read [product-model.md](product-model.md) before adding calls. Flow funnel events stay on the flow pipe. Engage `track` stays on the Engage pipe.
|
|
4
|
+
|
|
5
|
+
## Turn it on
|
|
6
|
+
|
|
7
|
+
Mount the provider with a publishable key and a stable `userId`. That is enough for sessions.
|
|
8
|
+
|
|
9
|
+
| SDK | Opt out |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| Web (`@getrheo/react`) | `analytics={{ enabled: false }}` |
|
|
12
|
+
| Expo and bare React Native | `analytics={{ enabled: false }}` |
|
|
13
|
+
| SwiftUI | `analyticsEnabled: false` on `RheoConfig` |
|
|
14
|
+
|
|
15
|
+
Do not opt out unless the user asked to disable Analytics.
|
|
16
|
+
|
|
17
|
+
## Consent (web)
|
|
18
|
+
|
|
19
|
+
On `@getrheo/react`, an omitted `analytics.consent` is `pending`. Rheo writes no anonymous id, session, or first-touch attribution, and it sends no product events, until the host grants consent. Rheo does not ship a banner. The site decides.
|
|
20
|
+
|
|
21
|
+
| `analytics.consent` | Behavior |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| omitted or `pending` | Leave storage untouched. Send nothing until grant. |
|
|
24
|
+
| `granted` | Collect immediately. Use this when a consent tool already stored a grant before paint, so the first page view is kept. |
|
|
25
|
+
| `denied` | Same pause as pending, and delete any analytics id, session, and first-touch values already stored. |
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { RheoProvider, setAnalyticsConsent } from '@getrheo/react';
|
|
29
|
+
|
|
30
|
+
export const App = () => (
|
|
31
|
+
<RheoProvider config={{ publishableKey, analytics: { consent: 'pending' } }}>
|
|
32
|
+
{children}
|
|
33
|
+
</RheoProvider>
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const onAccept = () => setAnalyticsConsent('granted');
|
|
37
|
+
const onReject = () => setAnalyticsConsent('denied');
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`setAnalyticsConsent('granted')` starts collection. `setAnalyticsConsent('denied')` stops it and clears storage. Events recorded before a grant are dropped. App SDKs do not use this consent gate.
|
|
41
|
+
|
|
42
|
+
A flow can still resolve while consent is pending. It uses an in-memory id and writes `rheo_app_user_id` only after consent is granted.
|
|
43
|
+
|
|
44
|
+
## Automatic events
|
|
45
|
+
|
|
46
|
+
- `session_start` when there is no session, or the last product event was more than 30 minutes ago.
|
|
47
|
+
- `first_visit` on web, or `first_open` on app SDKs, once per persisted anonymous `appUserId`.
|
|
48
|
+
- `page_view` on web for the first load and later `pushState`, `replaceState`, and `popstate`. The page name is the path.
|
|
49
|
+
|
|
50
|
+
App navigators differ, so screen views are explicit.
|
|
51
|
+
|
|
52
|
+
## Calls
|
|
53
|
+
|
|
54
|
+
`logEvent(name, properties?)` records a custom event. Name at most 120 characters. Properties at most 32KB. `setUserId(id)` sets `customUserId` on later product events. The anonymous `appUserId` stays the device id.
|
|
55
|
+
|
|
56
|
+
`screen(name)` records `screen_view`. On React Native, `bindNavigationState(state)` reads the focused route from a React Navigation `onStateChange` and calls `screen`.
|
|
57
|
+
|
|
58
|
+
### Web
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { logEvent, setUserId } from '@getrheo/react';
|
|
62
|
+
|
|
63
|
+
setUserId('user_123');
|
|
64
|
+
logEvent('workout_logged', { minutes: 30 });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### React Native
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import { bindNavigationState, logEvent, screen, setUserId } from '@getrheo/react-native-expo';
|
|
71
|
+
|
|
72
|
+
setUserId('user_123');
|
|
73
|
+
logEvent('workout_logged', { minutes: 30 });
|
|
74
|
+
screen('Home');
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Bare React Native exports the same functions from `@getrheo/react-native-bare`.
|
|
78
|
+
|
|
79
|
+
### SwiftUI
|
|
80
|
+
|
|
81
|
+
```swift
|
|
82
|
+
RheoAnalytics.setUserId("user_123")
|
|
83
|
+
RheoAnalytics.logEvent(name: "workout_logged", properties: ["minutes": .number(30)])
|
|
84
|
+
RheoAnalytics.screen("Home")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Revenue on the same person
|
|
88
|
+
|
|
89
|
+
After the host identifies RevenueCat or Superwall, register that id so webhook charges join this Customer:
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
import { setBillingIdentity } from '@getrheo/react-native-expo';
|
|
93
|
+
|
|
94
|
+
setBillingIdentity('revenuecat', originalAppUserId);
|
|
95
|
+
setBillingIdentity('superwall', superwallUserId);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
SwiftUI: `RheoAnalytics.setBillingIdentity(provider:externalId:)`. Web: `setBillingIdentity` from `@getrheo/react` for RevenueCat and Superwall only. Stripe revenue is the webhook. See [integrations.md](integrations.md).
|
|
99
|
+
|
|
100
|
+
## What you should not do
|
|
101
|
+
|
|
102
|
+
- Do not call `logEvent` to start an Engage automation. Use `track` on React Native. See [engage.md](engage.md).
|
|
103
|
+
- Do not pass a flow id where a channel id belongs. Analytics does not need a channel.
|
|
104
|
+
- Do not hard-code live publishable keys. Placeholders or env only.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Engage
|
|
2
|
+
|
|
3
|
+
Engage is lifecycle email for people who already use the product. Rheo writes the message and the audience. The app's own Amazon SES, Resend, Postmark, or SendGrid account sends it. Rheo does not send Engage messages from Rheo-owned infrastructure.
|
|
4
|
+
|
|
5
|
+
Push notifications and outbound webhooks are not SDK surfaces yet. Do not scaffold them.
|
|
6
|
+
|
|
7
|
+
Dashboard setup (provider credentials, physical mailing address, webhook URL, topics, frequency cap) stays in **App settings → Engage settings** or `rheo engage` in the CLI. Do not put provider secrets in the app or in a manifest.
|
|
8
|
+
|
|
9
|
+
## When a person can be emailed
|
|
10
|
+
|
|
11
|
+
All of these must be true:
|
|
12
|
+
|
|
13
|
+
1. The Customer has an email address.
|
|
14
|
+
2. Global marketing consent is `granted`. `unknown` does not send.
|
|
15
|
+
3. If marketing topics mode is on, the message topic is granted too.
|
|
16
|
+
4. The address is not suppressed (hard bounce, complaint, or unsubscribe).
|
|
17
|
+
|
|
18
|
+
Topics mode is off by default.
|
|
19
|
+
|
|
20
|
+
## `identify`
|
|
21
|
+
|
|
22
|
+
Call `identify` when the app collects an email and a real consent choice. Flow answer fields and event properties do not grant consent.
|
|
23
|
+
|
|
24
|
+
If you send `email`, you must send `marketingConsent` (`granted`, `denied`, or `unknown`). `granted` requires an email. Published SDK clients may still send deprecated `emailMarketingConsent`. The API accepts that alias and rejects the request when both fields are set and differ.
|
|
25
|
+
|
|
26
|
+
### React Native
|
|
27
|
+
|
|
28
|
+
`identify` and the provider `config` (`publishableKey`, `userId`, optional `apiBaseUrl`) are the two arguments. Expo and bare export it from the flavor package.
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { identify } from '@getrheo/react-native-expo';
|
|
32
|
+
|
|
33
|
+
await identify(
|
|
34
|
+
{
|
|
35
|
+
email: 'user@example.com',
|
|
36
|
+
marketingConsent: 'granted',
|
|
37
|
+
topicConsents: { product_updates: 'granted' },
|
|
38
|
+
attributes: { plan: 'pro' },
|
|
39
|
+
timezone: 'America/Los_Angeles',
|
|
40
|
+
},
|
|
41
|
+
config,
|
|
42
|
+
);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`attributes` shallow-merge onto the Customer. `timezone` is an IANA zone used for Engage quiet hours. `appUserId` defaults from `config.userId`.
|
|
46
|
+
|
|
47
|
+
### SwiftUI
|
|
48
|
+
|
|
49
|
+
```swift
|
|
50
|
+
try await runtime.identify(
|
|
51
|
+
email: "user@example.com",
|
|
52
|
+
marketingConsent: .granted,
|
|
53
|
+
topicConsents: ["product_updates": .granted]
|
|
54
|
+
)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`RheoRuntime.identify` does not take attributes or timezone. Pass `customUserId` when it differs from `appUserId`.
|
|
58
|
+
|
|
59
|
+
### Web
|
|
60
|
+
|
|
61
|
+
Same `identify` shape as React Native, exported from `@getrheo/react`. An email collected in a web flow answer is still not Engage consent. Call `identify` after an explicit opt-in (or send `denied` / `unknown` to match the UI).
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { identify } from '@getrheo/react';
|
|
65
|
+
|
|
66
|
+
await identify(
|
|
67
|
+
{
|
|
68
|
+
email: 'user@example.com',
|
|
69
|
+
marketingConsent: 'granted',
|
|
70
|
+
topicConsents: { product_updates: 'granted' },
|
|
71
|
+
},
|
|
72
|
+
config,
|
|
73
|
+
);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## `track` (web and React Native)
|
|
77
|
+
|
|
78
|
+
`track` posts to `POST /v1/sdk/track`. It can enroll automations and match segment rules. It does not write product-analytics events and it does not require a flow or a channel.
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { track } from '@getrheo/react';
|
|
82
|
+
// same export from @getrheo/react-native-expo and @getrheo/react-native-bare
|
|
83
|
+
|
|
84
|
+
await track({ name: 'trial_started', properties: { plan: 'pro' } }, config);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
SwiftUI and Flutter do not export this Engage `track`. On those stacks, do not repurpose flow `track` helpers or `logEvent`. Tell the user the automation trigger has to be emitted from web or React Native, or authored in the dashboard from an event the app already sends.
|
|
88
|
+
|
|
89
|
+
Use `logEvent` when the same action should appear in Analytics and the user did not ask for a journey. Call both only when they asked for both. See [analytics.md](analytics.md).
|
|
90
|
+
|
|
91
|
+
## What you should not do
|
|
92
|
+
|
|
93
|
+
- Do not install an email SDK to "add Engage".
|
|
94
|
+
- Do not set consent to `granted` because an email field exists. Wait for an explicit opt-in, or send `denied` / `unknown` to match what the UI collected.
|
|
95
|
+
- Do not put provider API keys, webhook tokens, or SES secrets in client code.
|
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
# Implementation Workflow
|
|
2
2
|
|
|
3
|
-
Use this when the user explicitly asks to install or wire Rheo in a host app.
|
|
3
|
+
Use this when the user explicitly asks to install or wire Rheo in a host app. Read [product-model.md](product-model.md) first and wire only the products they named.
|
|
4
4
|
|
|
5
|
-
## Shared
|
|
5
|
+
## Shared steps
|
|
6
6
|
|
|
7
|
-
1. Read local conventions, package manager, navigation structure, and current onboarding
|
|
8
|
-
2. Identify stable identity inputs: anonymous user id, backend user id, session id, app version, and locale.
|
|
7
|
+
1. Read local conventions, package manager, navigation structure, and the current entry point for the product you are adding (onboarding route, app root, or site layout).
|
|
8
|
+
2. Identify stable identity inputs: anonymous or auth user id, backend user id, session id, app version, and locale. One `userId` is the Customer. Do not mint a separate id for Analytics, Convert, and Engage.
|
|
9
9
|
3. Ask for missing Rheo dashboard values or use placeholders:
|
|
10
10
|
- publishable key
|
|
11
|
-
- channel id
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
- channel id, only when Convert is in scope
|
|
12
|
+
- web origin, only when the stack is React web
|
|
13
|
+
- optional API base URL for non-production
|
|
14
|
+
4. Install the one SDK package for this stack, with required peers. See the stack reference.
|
|
15
|
+
5. Mount `RheoProvider` once around the subtree that should be measured. That starts Analytics.
|
|
16
|
+
6. Then branch:
|
|
17
|
+
- **Analytics only:** stop after the provider, consent (web), `screen` / `logEvent`, and `setUserId` if a CRM id exists. See [analytics.md](analytics.md).
|
|
18
|
+
- **Convert:** gate the existing onboarding entry with `Flow` / `FlowView`. Preserve the old onboarding as a fallback unless the user asked to remove it. Wire terminal callbacks to continue host navigation. Pass the channel public id.
|
|
19
|
+
- **Engage:** after a real email and consent choice, call `identify`. On web or React Native, call `track` for automation triggers. See [engage.md](engage.md).
|
|
20
|
+
- **Revenue:** if the host already configures RevenueCat or Superwall, call `setBillingIdentity` with that provider's user id. See [integrations.md](integrations.md).
|
|
21
|
+
7. Wire optional auth, permissions, and in-app review only when the manifest or the user asks for them.
|
|
22
|
+
8. When `request_app_review` is present, tell the user TestFlight/production may not show prompts every tap and builder preview always advances as `not_shown`.
|
|
23
|
+
9. Run the narrowest useful verification.
|
|
21
24
|
|
|
22
25
|
## Safety
|
|
23
26
|
|
|
24
27
|
- Do not hard-code secrets.
|
|
25
|
-
- Do not remove legacy onboarding on the first integration unless requested.
|
|
28
|
+
- Do not remove legacy onboarding on the first Convert integration unless requested.
|
|
29
|
+
- Do not mount `Flow` for an Analytics-only or Engage-only request.
|
|
30
|
+
- Do not call `logEvent` where `track` belongs, or the reverse.
|
|
26
31
|
- Keep edits localized to the integration entry point and app config.
|
|
27
32
|
- Prefer reversible feature flags or route swaps for production apps.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# Integrations
|
|
2
2
|
|
|
3
|
+
Partner paywalls, Stripe, and host UI are Convert graph nodes. Revenue from those partners also feeds Analytics once the host registers the billing id. Read [product-model.md](product-model.md) for which pipe each call uses.
|
|
4
|
+
|
|
3
5
|
In the flow builder, partner paywalls and host UI are **two add-menu nodes** that share the `externalSurfaceNodes` schema:
|
|
4
6
|
|
|
5
7
|
| Builder node | Manifest `config.provider` | App settings toggle |
|
|
6
8
|
| --- | --- | --- |
|
|
7
|
-
| **Integration Node** | `revenuecat`
|
|
9
|
+
| **Integration Node** | `stripe`, `revenuecat`, `superwall` | Required |
|
|
8
10
|
| **External Surface Node** | `headless` | None (host registry) |
|
|
9
11
|
|
|
10
12
|
## RevenueCat (Integration Node)
|
|
@@ -24,9 +26,37 @@ Manifest mapping:
|
|
|
24
26
|
|
|
25
27
|
The host remains responsible for configuring RevenueCat. Rheo does not own purchase SDK secrets or receipt validation.
|
|
26
28
|
|
|
29
|
+
After `Purchases.configure` or `Purchases.logIn`, call `setBillingIdentity('revenuecat', customerInfo.originalAppUserId)` with the id RevenueCat already has. Dollars come from the RevenueCat webhook, not from the device. In **App settings → Integrations**, pick RevenueCat as the revenue source for that store. One source per store.
|
|
30
|
+
|
|
31
|
+
## Superwall (Integration Node)
|
|
32
|
+
|
|
33
|
+
Detect source calls such as `Superwall.configure`, `SuperwallProvider`, `expo-superwall`, `@superwall/react-native-superwall`, or `register(placement:)` / `registerPlacement`.
|
|
34
|
+
|
|
35
|
+
Manifest mapping:
|
|
36
|
+
|
|
37
|
+
- Create an **Integration Node** with `config.provider: "superwall"`.
|
|
38
|
+
- Preserve the placement id from the Superwall dashboard / source.
|
|
39
|
+
- Wire the same IAP outcomes as RevenueCat (`purchase_completed`, `restore_completed`, `purchase_cancelled`, `dismissed`, `failed`).
|
|
40
|
+
- Always wire `fallback`.
|
|
41
|
+
|
|
42
|
+
The host remains responsible for configuring Superwall. Rheo registers the placement and maps dismiss / skip / error callbacks to normalized outcomes. Skip / holdout / already-entitled paths map to `dismissed`.
|
|
43
|
+
|
|
44
|
+
After `Superwall.identify`, call `setBillingIdentity('superwall', userId)` with that same id. Dollars come from the Superwall webhook. One source per store, shared with RevenueCat: a second source for the same store is rejected.
|
|
45
|
+
|
|
46
|
+
## Stripe (web Integration Node)
|
|
47
|
+
|
|
48
|
+
Stripe Payment Links run on `@getrheo/react` only. There is no Stripe adapter on `RheoProvider` and no `setBillingIdentity('stripe', …)`.
|
|
49
|
+
|
|
50
|
+
- Enable **Stripe** under **App settings → Integrations**.
|
|
51
|
+
- Integration Node `config.provider: "stripe"` with a Payment Link on `buy.stripe.com` or another `https://*.stripe.com` host.
|
|
52
|
+
- Paste Rheo's webhook URL and signing secret into Stripe. The verified `checkout.session.completed` webhook is the purchase record. The browser does not send a price.
|
|
53
|
+
- Always wire `fallback`.
|
|
54
|
+
|
|
55
|
+
RevenueCat, Superwall, and headless surfaces fail closed on web and follow **Fallback**. See [react-web.md](react-web.md).
|
|
56
|
+
|
|
27
57
|
## External Surface Node (headless host UI)
|
|
28
58
|
|
|
29
|
-
Use when a source screen is owned by the host (custom native UI, third-party screen Rheo does not ship) rather than a Rheo layer tree or
|
|
59
|
+
Use when a source screen is owned by the host (custom native UI, third-party screen Rheo does not ship) rather than a Rheo layer tree or a partner paywall.
|
|
30
60
|
|
|
31
61
|
Manifest mapping:
|
|
32
62
|
|
|
@@ -53,7 +83,7 @@ Host wiring (required for success):
|
|
|
53
83
|
|
|
54
84
|
SwiftUI / Flutter: pass the same map on `FlowView` as `externalSurfaces` (builders receive `onComplete` / `onBack` / `onDismiss`). Docs: product Developer Guide → Headless external surfaces.
|
|
55
85
|
|
|
56
|
-
Do **not** use an External Surface Node to wrap RevenueCat when
|
|
86
|
+
Do **not** use an External Surface Node to wrap RevenueCat, Superwall, or Stripe when the flow should record a paywall outcome. Use an Integration Node with `provider: "revenuecat"`, `provider: "superwall"`, or `provider: "stripe"`. Conversion is `surface_outcome` with `purchase_completed`. Dollars come from that provider's webhook, not from the device.
|
|
57
87
|
|
|
58
88
|
## AppsFlyer
|
|
59
89
|
|
|
@@ -78,7 +108,11 @@ Native permission prompts can map to `request_os_permission` button actions. Ver
|
|
|
78
108
|
- Manifest: `action.kind: "request_app_review"` on a button (no extra fields).
|
|
79
109
|
- Requires **`screen.next.default`** on that screen.
|
|
80
110
|
- Submits inputs like **Continue**; advances only via default next (no branching).
|
|
81
|
-
- **React Native (Expo):** required peer `expo-store-review`.
|
|
111
|
+
- **React Native (Expo):** required peer `expo-store-review`. Push uses required peer `expo-notifications` (`registerPush` after a notifications grant).
|
|
112
|
+
- **React Native (bare):** call `registerPushTokenAdapter`, or pass the device token to `registerPush`.
|
|
113
|
+
- **Web:** `registerPush()` subscribes with the app VAPID key. Set `RheoConfig.push.serviceWorkerUrl` or rely on `navigator.serviceWorker.ready`.
|
|
114
|
+
- **SwiftUI:** after notifications are granted the SDK calls `registerForRemoteNotifications`. Forward `didRegister` with `RheoPush.forward(deviceToken:)`.
|
|
115
|
+
- **Flutter:** call `runtime.registerPush(token:)`, or set `runtime.setPushTokenProvider` so a notifications grant uploads a Firebase token.
|
|
82
116
|
- **React Native (bare):** required peer `react-native-in-app-review`.
|
|
83
117
|
- **SwiftUI:** built-in StoreKit; ~1.5s delay when a prompt may have shown (no dismiss callback on iOS).
|
|
84
118
|
- Analytics: `app_review_prompt_shown`, `app_review_prompt_dismissed`; capture key `app_review:{layerId}`.
|