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

# The Claim Flow

> What happens when a user claims an offer in the Web SDK: one step, immediate handoff, and what the claimed result carries.

Presenting an offer is one call, and claiming one is one step. The user taps **Claim**
inside the offer sheet, the SDK opens the advertiser in a new tab within that same tap
gesture, and [`show()`](/publishers/web/sdk-reference/show) resolves
`{ status: 'claimed' }`. The SDK renders nothing after a claim: the host owns whatever
comes next.

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

if (result.status === 'claimed') {
  // The advertiser tab is already open. Keep result.transactionId.
}
```

There is no second call to make, no pending state to track, and no handle to stash between
steps.

<Note>
  Requires the current **`@encorekit/web-sdk` 2.x** release. Upgrading an existing integration:
  [Updating to 2.x](/publishers/web/guides/updating-to-2-x).
</Note>

## What a claimed result carries

```typescript theme={null}
{
  status: 'claimed';
  offerId: string;
  campaignId: string;
  advertiserName: string;
  transactionId?: string;
}
```

| Field                    | What it is                                                                                                                           |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| `offerId` / `campaignId` | Identify what was claimed. On web these are distinct values and both are reported.                                                   |
| `advertiserName`         | The merchant's display name, for a confirmation message you render yourself.                                                         |
| `transactionId`          | The claim's durable handle: the id Encore keys on. It is how a completion that lands days later is traced back to this user and app. |

The payload mirrors the iOS and Android `ClaimedOffer` field for field, so a
cross-platform integration reads one shape everywhere.

<Warning>
  **`transactionId` is optional, and that is deliberate.** The transaction write can fail
  while the claim itself genuinely happened. When that occurs the SDK logs a warning naming
  the attribution consequence rather than fabricating a placeholder id, and the result still
  resolves `claimed`: a failed write must never retroactively turn a real claim into a
  decline. Persist `transactionId` when it is present, and treat its absence as a claim you
  cannot later join on, not as a failure.
</Warning>

## Which sheet renders

The [`useCase`](/publishers/web/sdk-reference/placement) option is the only thing that
selects a composition, and it defaults to `'reduceChurn'`:

| `useCase`                 | What renders                                                                                                                                                                 |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `'reduceChurn'` (default) | The offer carousel: a save attempt at a moment the user is leaving.                                                                                                          |
| `'rewardUsers'`           | The reward composition: its own headline chrome around a paged carousel, for a moment the user just accomplished something. Claim-only, with no purchase ask anywhere in it. |

A use case with nothing to present is not an error. `show()` resolves
`{ status: 'unavailable' }`, the same result no eligible offers produce, and it never falls
back to another use case's offers or copy.

<Note>
  These symbols match the native SDKs verbatim (iOS `.reduceChurn` / `.rewardUsers`, Android
  `REDUCE_CHURN` / `REWARD_USERS`), so a cross-platform integration reads one vocabulary. The
  values Encore sends and stores are separate frozen labels, which is what keeps a rename from
  ever changing the wire. You never type a wire value: passing one is rejected as an
  unrecognized use case.
</Note>

## Where the sheet's copy comes from

`headline` and `subheadline` on the
[placement options](/publishers/web/sdk-reference/placement) set the copy for one
presentation, ahead of the copy Encore resolved for your app. The full resolution order,
and how blank values behave, are on
[Where the copy comes from](/publishers/use-cases/post-action-reward#where-the-copy-comes-from).

## Identify before you present

Call [`identify()`](/publishers/web/sdk-reference/identify) with your stable user id before
presenting, so the claim binds to an account id that survives reloads, navigations, and
device switches. Exposures recorded before `identify()` are keyed to the auto-generated
anonymous id and are not retro-linked, so a late identify leaves them unattributed. See
[Configure Analytics](/publishers/web/quickstart/configure-analytics).

## A claim is not a conversion

`claimed` reports a **presentation fact**: the user tapped Claim and was handed off to the
advertiser. Nothing has been earned or verified at that moment.

Advertiser completion happens later, is asynchronous, and is server-authoritative. Verify
real access from your backend through Encore's HMAC-authenticated server-side entitlements
API, by user, never from this result and never from the client.

## Gotchas

* **Nothing renders after a claim.** If your flow wants a confirmation moment, render it
  yourself when the result is `claimed`.
* **`unavailable` is overloaded on purpose.** It means no eligible offers, a measurement
  control cohort, or nothing to present for the requested use case, and the SDK keeps them
  indistinguishable so incrementality experiments aren't contaminated. Show your normal
  fallback; don't branch on a suspected control assignment.
* **You don't need a click handler for `show()`.** The advertiser tab opens inside the
  user's tap on Claim, which happens within the SDK's own sheet, so popup blockers have
  nothing to catch. Present offers from whatever moment makes sense in your app.
* **`reset()` does not revoke anything.** It clears local SDK state and generates a fresh
  anonymous id. Claims already recorded belong to the user id they were made under.

## Related

* [`show()`](/publishers/web/sdk-reference/show): the full `ShowResult` contract.
* [`placement()`](/publishers/web/sdk-reference/placement): the `PlacementOptions` contract, including `headline` and `subheadline`.
* [Updating to 2.x](/publishers/web/guides/updating-to-2-x): moving off the two-phase flow.
* [Reduce Churn at the Paywall](/publishers/web/guides/intercept-paywall-abandonment) · [Post-Purchase Placements](/publishers/web/guides/post-purchase-placements): the two use cases end to end.
