Presents targeted offers to users in a modal overlay. Returns a promise that resolves when the modal closes with the presentation result.
Signature
function presentOffer(options?: PresentationOptions): Promise<PresentationResult>
Parameters
Optional callbacks and configurationinterface PresentationOptions {
onGranted?: (entitlement: EntitlementType) => void
onNotGranted?: (reason: NotGrantedReason) => void
onError?: (error: EncoreError) => void
}
Return Value
Type: Promise<PresentationResult>
interface PresentationResult {
granted: boolean
entitlement?: EntitlementType
reason?: NotGrantedReason
}
Whether an entitlement was granted
The entitlement type that was granted (only present if granted is true)
Reason why entitlement wasn’t granted (only present if granted is false)Possible values:
'userClosedModal' - User clicked X or pressed ESC
'userClickedOutside' - User clicked modal backdrop
'userDeclinedLastOffer' - User clicked “No Thanks” on last offer
'noOffersAvailable' - Server returned no offers
{ type: 'error', error: EncoreError } - System error occurred
Examples
Basic Usage
import Encore from '@encore/web-sdk';
const result = await Encore.presentOffer();
if (result.granted) {
console.log('Access granted:', result.entitlement);
unlockFeature();
} else {
console.log('Not granted:', result.reason);
}
With Callbacks
await Encore.presentOffer({
onGranted: (entitlement) => {
console.log('User granted:', entitlement);
unlockFeature();
trackEvent('offer_accepted');
},
onNotGranted: (reason) => {
console.log('User declined:', reason);
if (reason === 'noOffersAvailable') {
showAlternativeFlow();
}
trackEvent('offer_declined', { reason });
},
onError: (error) => {
console.error('Error:', error);
showErrorMessage();
}
});
Handling All Results
const result = await Encore.presentOffer();
if (result.granted) {
// User claimed an offer
console.log('Entitlement type:', result.entitlement.type);
unlockPremiumFeature();
} else {
// User didn't claim
switch (result.reason) {
case 'userClosedModal':
console.log('User closed the modal');
break;
case 'userDeclinedLastOffer':
console.log('User declined all offers');
showPricingPage();
break;
case 'noOffersAvailable':
console.log('No offers available');
showAlternativeFlow();
break;
default:
if (typeof result.reason === 'object' && result.reason.type === 'error') {
console.error('Error:', result.reason.error);
}
}
}
Framework Integration
import { useState } from 'react';
import Encore from '@encore/web-sdk';
function UnlockButton() {
const [loading, setLoading] = useState(false);
const handleClick = async () => {
setLoading(true);
try {
const result = await Encore.presentOffer();
if (result.granted) {
// Feature unlocked - UI updates automatically via event listeners
}
} finally {
setLoading(false);
}
};
return (
<button onClick={handleClick} disabled={loading}>
{loading ? 'Loading...' : 'Unlock Premium'}
</button>
);
}
Common Use Cases
Cancellation Flow
async function handleCancelSubscription() {
const confirmed = await showCancelConfirmation();
if (!confirmed) return;
const result = await Encore.presentOffer();
if (result.granted) {
cancelCancellationFlow();
showMessage('Your subscription continues with a special offer!');
} else if (result.reason !== 'noOffersAvailable') {
await cancelSubscription();
showMessage('Your subscription has been cancelled.');
}
}
Feature Paywall
async function showPremiumFeature() {
if (Encore.isActive({ type: 'freeTrial' })) {
renderPremiumContent();
return;
}
const result = await Encore.presentOffer();
if (result.granted) {
renderPremiumContent();
} else {
redirectToPricingPage();
}
}
Onboarding Enhancement
async function completeOnboarding() {
await finishOnboardingSteps();
const result = await Encore.presentOffer();
if (result.granted) {
showPremiumOnboarding();
} else {
showStandardOnboarding();
}
}
Presentation Flow
SDK Fetches Offers
The SDK calls the Encore API to fetch available offers based on user ID, attributes, location, and targeting rules.
Modal Displays
A responsive modal overlay appears with offer details, instructions, and call-to-action buttons.
User Interacts
User can claim an offer (opens advertiser URL), decline (shows next offer), or close the modal.
Provisional Grant
When user claims an offer, the SDK sends a provisional grant signal and refreshes entitlements automatically.
Modal Closes
Success screen is shown, then the modal closes and the promise resolves.
The SDK automatically refreshes entitlements after an offer is claimed. You don’t need to manually call refreshEntitlements().
Best Practices
1. Check Before Presenting
// Good
if (!Encore.isActive({ type: 'freeTrial' })) {
await Encore.presentOffer();
}
2. Handle All Outcomes
// Good
const result = await Encore.presentOffer();
if (result.granted) {
// Success
} else if (result.reason === 'noOffersAvailable') {
// No offers
} else {
// User declined
}
3. Show Loading States
// Good
setLoading(true);
try {
await Encore.presentOffer();
} finally {
setLoading(false);
}
4. Track Analytics
const result = await Encore.presentOffer();
analytics.track(result.granted ? 'offer_accepted' : 'offer_declined', {
entitlementType: result.entitlement?.type,
reason: result.reason
});
Next Steps