> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encorekit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Redemption Modes — Deferred vs Immediate

> The redemptionMode config picks who controls the advertiser redirect: 'deferred' (default) splits show() and redeem() so the host times the redirect; 'immediate' opens the advertiser tab inside the claim gesture. Covers the two-phase flow, the pending transaction (TTL, reload recovery), and per-placement redeem.

The Web SDK supports two redemption modes, chosen once at
[`configure()`](/publishers/web/sdk-reference/configure) via `redemptionMode`. The mode
decides **who fires the advertiser redirect and when**:

|                              | `'deferred'` (default)                                                 | `'immediate'`                                                                                       |
| ---------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Config value                 | `redemptionMode: 'deferred'`                                           | `redemptionMode: 'immediate'`                                                                       |
| What `show()` does           | Presents the carousel, records a transaction on claim, **no redirect** | Presents the carousel, records a transaction, **opens the advertiser tab inside the claim gesture** |
| `show()` claim result        | `{ status: 'claimed' }`                                                | `{ status: 'claimed' }` — identical; the tab was also opened before resolving                       |
| Advertiser redirect          | Later, in `redeem()`, on the user's CTA tap                            | Immediately, inside the claim gesture                                                               |
| `redeem()` needed?           | **Yes** — phase 2 of the flow                                          | No — already redeemed inline                                                                        |
| Who controls redirect timing | The host app                                                           | The SDK                                                                                             |

<Note>
  The config literal is **`'immediate'`**. Use that exact string in `configure()` —
  `'instant'` is not a valid value.
</Note>

## When to use which

**Use `'deferred'` (the default)** when claiming an offer and redirecting to the advertiser
are separate moments — you want to run your own conversion, navigation, or server check
between the claim and the redirect. Typical cases:

* The user accepts a retention offer mid-cancellation, and you redirect only after your own
  save/confirm step.
* You present on one page or route and redeem after a navigation or reload.
* You gate the advertiser redirect behind a server check or a real conversion.

**Use `'immediate'`** when claiming should redirect in a single step — no host logic between
claim and redirect, and no pending transaction to manage. It's the recommended pairing for
post-purchase surfaces using the
[`thankYou` layout](/publishers/web/guides/thank-you-layout): the claim opens the advertiser
within the tap gesture, with no second host action on a page the user is about to leave.

In **both modes** the SDK renders nothing after a claim — there is no built-in success or
confirmation screen. The host owns the post-claim moment: render your own confirmation (or
none), keyed off the `claimed` result.

## Deferred mode: the two-phase flow

Two calls. `show()` claims; your code runs; `redeem()` redirects.

```javascript theme={null}
import Encore from '@encorekit/web-sdk';

Encore.configure({
  apiKey: 'pk_live_yourpublishablekey',
  redemptionMode: 'deferred', // default — shown for clarity
});

// Phase 1 — claim (no redirect). The SDK records the transaction internally;
// there is no handle to stash.
const shown = await Encore.placement('cancel_flow').show();
if (shown.status !== 'claimed') return; // 'dismissed' | 'unavailable'

// ... run your own conversion / save step ...

// Phase 2 — redirect, called from a user action (button click). redeem()
// renders the redemption screen; the advertiser tab opens on the CTA tap.
const redeemed = await Encore.placement('cancel_flow').redeem();
// redeemed.status === 'redeemed'
```

**Lifecycle:** `show()` → `claimed` (transaction `status: 'claimed'`) → *(host work)* →
`redeem()` → advertiser tab opens + provisional grant → transaction `status: 'redeemed'`.

Two rules make the flow reliable:

* **Call `redeem()` within a user gesture's reach.** The advertiser tab is opened
  synchronously on the CTA tap to dodge popup blockers — trigger `redeem()` from a click
  handler, not a timer or background promise.
* **Identify early.** Call [`identify()`](/publishers/web/sdk-reference/identify) with your
  stable user id before presenting, so the transaction binds to an account id that survives
  reloads and navigations.

### The pending transaction

A deferred claim records a pending transaction **inside the SDK** — self-contained, carrying
everything [`redeem()`](/publishers/web/sdk-reference/redeem) needs to rebuild the advertiser
redirect later. No handle is returned by `show()` and none is needed: `redeem()` resolves the
pending transaction internally.

Claims are stored locally with a **\~7-day TTL** and survive page reloads, so your code never
tracks pending state — even on a fresh page, call `redeem()` when your flow is ready (from a
click handler, e.g. your own "finish claiming your reward" button). If nothing is pending,
`redeem()` resolves `{ status: 'none' }` and renders no UI.

### Per-placement redeem

`placement(id).redeem()` (as above) resolves exactly that placement's transaction — it
never crosses to another placement's. The global
[`Encore.redeem()`](/publishers/web/sdk-reference/redeem) resolves the pending transaction
regardless of placement.

## Immediate mode

One call. Claiming opens the advertiser tab inside the claim gesture; `show()` then resolves
`claimed` and the SDK renders nothing further.

```javascript theme={null}
import Encore from '@encorekit/web-sdk';

Encore.configure({
  apiKey: 'pk_live_yourpublishablekey',
  redemptionMode: 'immediate',
});

// Single step — claim opens the advertiser tab inline
const result = await Encore.placement('post-purchase').show();
if (result.status === 'claimed') {
  // Advertiser tab already opened. The SDK renders nothing after the claim —
  // show your own confirmation here if you want one.
}
// No redeem() call needed in immediate mode.
```

**Lifecycle:** `show()` → opens the advertiser tab in the claim gesture → `claimed`
(transaction `status: 'redeemed'`).

## What differs in events

Both modes record a transaction and emit the same provisional grant on redirect; the only
difference is *when* the redirect fires. Across both:

* `sdk_offer_presentation_triggered` / `_success` / `_failed` — fired when the carousel is
  presented (or when there are no eligible offers).
* `sdk_offer_presented` — per offer impression.
* `sdk_offer_claimed` — when the user claims (both modes).
* The provisional grant signal fires at **redirect** time: in `redeem()` for deferred, inline at
  claim for immediate.

## Gotchas

* **Mode is set once.** The SDK is configure-once; `redemptionMode` can't be changed after
  `configure()` without a fresh SDK instance (e.g. a page reload). Read the live value with
  `Encore.getConfiguration().redemptionMode`.
* **Don't call `redeem()` in immediate mode.** The transaction is already redeemed inline;
  `redeem()` resolves `none`.
* **Expired claims resolve as `none`.** A pending transaction past its \~7-day TTL fails
  resolution — `redeem()` returns `{ status: 'none' }`, meaning "nothing to redeem".
* **`claimed` ≠ conversion.** In either mode the result only says the user accepted an offer —
  advertiser conversion is asynchronous and server-authoritative. Verify conversions and
  entitlements server-side, by user — see
  server-side verification on Encore’s side.

## Related

* [`show()` reference](/publishers/web/sdk-reference/show) — phase 1 contract and `ShowResult`.
* [`redeem()` reference](/publishers/web/sdk-reference/redeem) — phase 2 contract, transaction resolution, `RedeemResult`.
* [Thank-You Layout guide](/publishers/web/guides/thank-you-layout) — the post-purchase surface that pairs with `'immediate'`.
* [configure](/publishers/web/sdk-reference/configure) — where `redemptionMode` is set.
