Appearance
Native iOS Link Routing
This page is the routing companion to the canonical iOS Universal Links guide. FunnelsGrove v1 uses only links shaped as:
text
https://go.funnelsgrove.com/<app-key>/<slug>The URL contains routing and optional opaque attribution context, never email or user identity. Do not add a custom identity-bearing link format or custom-scheme fallback for the FunnelsGrove flow.
Receive The Universal Link
Handle NSUserActivityTypeBrowsingWeb, accept only the exact go.funnelsgrove.com host, and require exactly two path segments. Generate one UUID openId for the received payload and reuse it until the public app-open request succeeds.
The app-open response contains:
json
{
"clickId": "<click-id>",
"destination": "onboarding/welcome"
}Persist clickId until verified login and backend binding complete. Treat optional context or handoff values as opaque; do not decode them or derive navigation or identity from them.
Route A Typed Destination
Convert the server-returned destination into a small app-owned enum before navigation:
swift
enum AppDestination: Equatable {
case onboardingWelcome
case subscription
}
func destination(from value: String) -> AppDestination? {
switch value {
case "onboarding/welcome": return .onboardingWelcome
case "subscription": return .subscription
default: return nil
}
}Reject unknown destinations. Receiving a link never proves subscription ownership and must not unlock paid content.
Buffer Until The App Is Ready
Universal Links can arrive during a cold start, before authentication finishes, or before navigation exists.
- Persist
openIdbefore starting the record request. - Buffer only the validated destination in the navigation layer.
- Persist the returned
clickIdoutside the URL payload until backend binding succeeds or reaches an explicit terminal outcome. - Prevent duplicate delivery from starting duplicate navigation or bind operations.
- Clear stale state on sign-out or account switching.
Verify Before Granting Access
After the user signs in:
- Verify email ownership through OTP or an equivalent identity-provider signal.
- Have the authenticated customer backend bind the persisted
clickIdwith that verified email. - Call
POST /sdk/public/users/verify_subscriptionwith the same verified email. - Continue only when
activeistrueand a stable FunnelsGrove user ID is returned. - Call
POST /sdk/public/users/track_loginwith that ID, save it on the authenticated account, then navigate or unlock access.
The project SDK secret is backend-only. Neither it nor the attribution admin credential belongs in the native app or public app-open request.
Test Native Delivery
Test on a physical device with a release-like signed build:
- Tap the link from Mail, Messages, or Notes with the app installed.
- Test cold and warm starts.
- Confirm malformed hosts and paths are ignored.
- Confirm record retries reuse the same
openId. - Confirm an unknown returned destination is rejected.
- Confirm
clickIdsurvives login and clears only after successful binding or an explicit terminal outcome. - Confirm the app never unlocks access before verified-email subscription status is active.
Typing the URL into Safari's address bar tests web navigation, not a Universal Link tap. Apple can take time to distribute associated-domain changes; use the propagation guidance in the canonical setup page.