> ## 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.

# Updating to 2.x

> Migrate an Encore Web SDK integration from 1.x to 2.x, step by step.

## Overview

2.x reduces the public API to a single dimension: **why a placement presents**. The
composition, the copy slots, and the claim flow all follow from that, or are gone.

<Warning>
  **Read the change, not the version number.** The current 2.x release carries a **full
  public-API rewrite**. Methods, options, and result shapes all changed, and the 1.x surface
  is removed rather than deprecated. Treat this upgrade the way you would treat a major
  version bump, whatever the number suggests.
</Warning>

Coming from 1.x, four things change:

* **Redemption is immediate, and that is the only flow.** Claiming opens the advertiser in
  a new tab inside the claim gesture. `redeem()` and the whole two-phase claim then redeem
  sequence are removed.
* **`PlacementOptions` is one flat shape.** `headline` and `subheadline` replace the
  nested `header` object.
* **`layout` is gone**, along with the `'thankYou'` composition and everything that dressed
  it. A new `useCase` option selects the composition instead.
* **`show()` takes no arguments**, and a claimed result now carries `offerId`, `campaignId`,
  `advertiserName`, and `transactionId`.

***

## Step 1: Update the package

Install the current 2.x release:

```bash theme={null}
npm install @encorekit/web-sdk@latest
```

<Note>
  Check what you resolved to (`npm view @encorekit/web-sdk version`) before pinning. The 2.x
  line began with a release that predates this API, so pin to the version you actually
  installed rather than to `2.0.0`.
</Note>

2.x removes the 1.x surface outright rather than deprecating it, so in TypeScript every call
site that needs attention fails to typecheck. Run your type checker: the errors are your
migration worklist, and each one maps to a step below. The
[removed API table](#removed-apis-at-a-glance) maps every 1.x symbol to its replacement.

JavaScript hosts get no such worklist. Work through the steps in order instead, and pay
particular attention to Step 2.

***

## Step 2: Drop the deferred flow

`redeem()`, `placement(id).redeem()`, `getPendingTransaction()`, `RedeemOptions`, and
`RedeemResult` are removed, along with the redemption screen and the primer screen they
rendered. There is no pending transaction, so there is nothing to redeem.

Claiming now hands the user off immediately, and the `claimed` result is the whole signal:

```javascript theme={null}
// 1.x: two phases
const shown = await Encore.placement('cancel_flow').show();
if (shown.status !== 'claimed') return;
await runYourConversion();
await Encore.placement('cancel_flow').redeem(); // fired the redirect

// 2.x: one phase
const result = await Encore.placement('cancel_flow').show();
if (result.status === 'claimed') {
  // The advertiser tab is already open. Run your own conversion step here
  // if you have one, and render your own confirmation if you want one.
  await runYourConversion();
}
```

If your integration called `redeem()` after your own conversion step, **that call must be
deleted**: the offer is redeemed the moment the user claims it, and the SDK renders nothing
afterward. Treat `{ status: 'claimed' }` as the complete outcome.

<Warning>
  **This one bites even if you never configured it.** `redemptionMode` defaulted to
  `'deferred'` in 1.x, so an integration that never set it recorded claims without
  redirecting. On 2.x the same code redirects on claim. No call site has to change to be
  affected.
</Warning>

Two rules that the deferred flow required no longer apply. You do not need to call anything
from inside a click handler, because the advertiser tab now opens within the user's tap on
Claim inside the SDK's own sheet. And there is no pending state surviving a reload for your
code to reconcile.

Remove `redemptionMode` from both [`configure()`](/publishers/web/sdk-reference/configure)
and any placement options. `getConfiguration()` no longer returns it either.

***

## Step 3: Flatten the placement options

The nested `header` object is replaced by flat fields:

```javascript theme={null}
// 1.x
Encore.placement('milestone_reached', {
  header: { title: 'Nice work, Sam!', subtitle: 'That is your fifth week running' },
}).show();

// 2.x
Encore.placement('milestone_reached', {
  headline: 'Nice work, Sam!',
  subheadline: 'That is your fifth week running',
}).show();
```

The precedence is unchanged: a per-call override beats the copy Encore resolved for your
app, which beats the copy shipped with the screen, each field resolving on its own, and a
blank value still falls through rather than clearing the line.

`.onNotGranted()` and `.onLoadingStateChange()` on the builder are unchanged.

***

## Step 4: Replace the retired compositions

`layout` is removed. The new [`useCase`](/publishers/web/sdk-reference/placement) option
selects the composition instead, and it defaults to `'reduceChurn'`, which renders the offer
carousel your 1.x `'list'` placements already showed.

**A placement that named no layout needs no change here.** Drop the `layout: 'list'` option
if you passed it explicitly; the default covers you.

The **`'thankYou'` composition is retired**, and with it the payment-status sheet a
post-purchase surface could compose. If you presented one, the closest equivalent is the
`'rewardUsers'` composition:

```javascript theme={null}
// 1.x
Encore.placement('post_purchase', {
  layout: 'thankYou',
  redemptionMode: 'immediate',
  header: { icon: 'success', title: 'Payment Successful' },
  offerContext: { title: 'A little thank you, just for you.' },
  footer: { text: 'Secured by Acme' },
}).show({ receipt: { amount: '$9.99', purpose: 'Pro Plan' } });

// 2.x
Encore.placement('post_purchase', {
  useCase: 'rewardUsers',
  headline: 'Payment Successful',
  subheadline: 'You paid $9.99 for Pro Plan', // pre-format it yourself
}).show();
```

Four things genuinely stop rendering, and there is no option that brings them back:

| Removed                                                         | What to do instead                                                                                                        |
| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `receipt` (the composed "You paid {amount} for {purpose}" line) | Pre-format the sentence yourself and pass it as `subheadline`.                                                            |
| `offerContext` (the two-line lead-in above the offers)          | The reward composition suppresses that header. Put the copy in `headline` / `subheadline`, or render it in your own page. |
| `footer` (the trust line below the carousel)                    | Render it in your own page.                                                                                               |
| `display` / `HostDisplay`                                       | Nothing. It only ever fed the deferred-flow screens.                                                                      |

Because `display` is gone, so is the display pre-flight that could resolve a deferred
`show()` to `dismissed` with a `CONFIGURATION_ERROR` before anything rendered.

***

## Step 5: Read the new claim result

A claimed result is no longer bare:

```javascript theme={null}
const result = await Encore.placement('cancel_flow').show();

if (result.status === 'claimed') {
  // 2.x adds these four fields
  const { offerId, campaignId, advertiserName, transactionId } = result;
  await persistClaim({ transactionId, advertiserName });
}
```

`transactionId` is what carries attribution: it is how a completion landing days later is
traced back to this user and app. **Persist it when it is present.** 1.x had no way to obtain
one at all: the claimed result was bare, and the id lived only on the persisted transaction
record reachable through the now-removed `getPendingTransaction()`.

It is optional because the transaction write can fail while the claim genuinely happened, in
which case the SDK logs a warning rather than fabricating a placeholder id, and the result
still resolves `claimed`.

`dismissed` and `unavailable` are unchanged. `show()` still never rejects.

***

## New in 2.x: reward a user, not just save one

1.x could only intervene when a user was about to leave. 2.x adds a second use case for the
opposite moment, a user who just accomplished something:

```javascript theme={null}
await Encore.placement('streak_day_7', {
  useCase: 'rewardUsers',
  headline: 'Nice work, Sam!',
}).show();
```

Nothing forces you to adopt it. Leaving `useCase` unset keeps every placement on
`'reduceChurn'`, which is the behavior your 1.x integration already had. See
[Post-Purchase Placements](/publishers/web/guides/post-purchase-placements) for the full
walkthrough.

<Note>
  The values you type (`'reduceChurn'`, `'rewardUsers'`) match the native SDKs. The values
  Encore sends and stores over the wire are separate frozen labels, so anything you have built
  on the `use_case` analytics property is unaffected.
</Note>

***

## Removed APIs at a glance

| 1.x                                                                                                     | 2.x                                                                                                                                           |
| ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `redemptionMode`, on `configure()` and on placement options                                             | Removed. Redirect on claim is the only flow.                                                                                                  |
| `Encore.redeem()`, `placement(id).redeem()`, `getPendingTransaction()`, `RedeemOptions`, `RedeemResult` | Removed. There is no pending transaction to redeem.                                                                                           |
| `layout: 'list' \| 'thankYou'`                                                                          | `useCase`: `'reduceChurn'` renders the offer carousel, `'rewardUsers'` the reward composition.                                                |
| `header.title`, `header.subtitle`                                                                       | `headline`, `subheadline` on `PlacementOptions`.                                                                                              |
| `header.icon`                                                                                           | `statusIcon` on `PlacementOptions`. **The default flips from `'success'` to `'none'`**, so the check no longer renders unless you ask for it. |
| `offerContext`, `footer`, `receipt`, `ShowOptions`, `Receipt`                                           | Removed. Render any other copy yourself.                                                                                                      |
| `display`, `HostDisplay`                                                                                | Removed.                                                                                                                                      |
| `show(options)` on the placement builder                                                                | `show()`, which takes no arguments.                                                                                                           |

***

## Verify the migration

* Your project type-checks, or (in JavaScript) no call site still references `redeem()`,
  `redemptionMode`, `layout`, `header`, `offerContext`, `footer`, `receipt`, or `display`.
* A claim opens the advertiser tab with no second call from your code.
* Your `claimed` branch reads and persists `transactionId`.
* Your analytics still report against the same use-case values they always did, because the
  wire did not change.

## Related

* [The Claim Flow](/publishers/web/concepts/claim-flow): the single-step flow in full.
* [`placement()`](/publishers/web/sdk-reference/placement): the current `PlacementOptions` contract.
* [`show()`](/publishers/web/sdk-reference/show): the current `ShowResult` contract.
* [`configure()`](/publishers/web/sdk-reference/configure): the current `EncoreConfig` contract.
