For the complete documentation index, see llms.txt. This page is also available as Markdown.

Gating actions

A gate lets a campaign pause the user's flow at a moment you choose, run an action (e.g. a rewarded ad), and resume — or back out — based on the outcome. For the product picture and when to reach for this, read Gating an action first. This page is the wiring.

There are two halves, and they live in different places:

  1. At the call site — instead of firing an event and moving on, you trackGated the event and await a decision before doing the next step. This is opt-in per call site: a moment is gate-able only where you do this.

  2. At app startup — you registerGate for the URLs that are outcome-bearing (the rewarded ad, the survey), supplying a presenter that runs the action and reports how it ended. Everything you don't register stays an ordinary fire-and-forget deeplink.

If no campaign gates the event, or the SDK isn't ready, or anything fails, the decision is proceed — the gate is fail-open and never traps the user.

1. Gate the call site

func handleExport() async {
    let decision = await amply.trackGated(event: "ExportTapped", properties: [:])
    guard case .proceed = decision else { return }   // user backed out — don't export
    exporter.export(currentDocument)                  // your code, your live context
}

trackGated returns a GateDecision.proceed(reason:) or .cancelled. Use the plain guard case .proceed form unless you specifically want the reason (.completed vs .failOpen, e.g. to grant a reward only on a real completion).

Track the same event with plain track elsewhere and it won't gate there. Use trackGated only where the call site can honor a wait.

2. Register what runs at the gate

Register once, at startup, for each outcome-bearing URL. The presenter runs the action and reports how it ended: completed, dismissed by the user, or unavailable (no fill, failed to load, not ready).

final class RewardedAdPresenter: CampaignPresenter {
    func present(params: [String: String], info: [String: Any], resolution: CampaignResolution) {
        let reward = Int(params["reward"] ?? "") ?? 0   // params come from the campaign URL query
        rewardedAd.show(reward: reward) { result in
            switch result {
            case .earned:  resolution.resolve(result: .completed)
            case .closed:  resolution.resolve(result: .dismissed)     // user backed out
            case .noFill, .failed: resolution.resolve(result: .unavailable)  // -> proceeds (fail-open)
            }
        }
    }
    func dismiss() { rewardedAd.tearDown() }   // SDK calls this if the gate is abandoned
}

amply.registerGate(baseUrl: "yourapp://ad", presenter: RewardedAdPresenter(),
                   onAbort: .cancel, timeoutMs: 60_000)
  • Match by base URL. Register yourapp://ad; a campaign firing yourapp://ad?type=rewarded&reward=10 matches it, and the query (type, reward, …) arrives as params. One registration serves many campaign variants — the dashboard tunes the parameters with no app release.

  • onAbort decides what a user dismissal means: cancel (the gate's .cancelled — the flow backs out) or proceed (continue anyway). It defaults to cancel, which is what you want for value-exchange gates like rewarded ads; pass proceed for gates that should never hold the flow back.

  • dismiss() is required on the presenter (there is no default). The SDK calls it when the gate is abandoned — caller cancelled, or the timeout fired — so you can tear down any UI you put on screen. Implement it even if it's a no-op for your action.

  • timeoutMs is the fail-open deadline (default 60s, paused while the app is backgrounded). If the presenter never reports, the gate proceeds.

  • Outcomes, strictly: dismissed is a user-initiated close only. Every infrastructure failure — no fill, failed to show, not ready — is unavailable, which proceeds. Never map an infra failure to dismissed, or you'd cancel the user's action for your own outage.

Don't registerGate ATT / privacy-consent / push-permission URLs. Route them as ordinary deeplinks: present the prompt, record the answer as a user attribute, and let the flow continue. See Gating an action — When not to gate.

Last updated