Skip to content

Error Handling

import { Aside } from ‘@astrojs/starlight/components’;

The SDK is designed with fail-open semantics — when RevTurbine is unreachable, your app’s baseline UX continues unaffected. Placements disappear gracefully and entitlement checks default to allowed.

RevTurbine is an enhancement layer, not a critical dependency. The SDK never blocks your app from functioning:

API failure scenarioSDK behavior
API unreachablePlacements return visible: false
Entitlement check failsReturns { allowed: true, reason: 'entitlement_service_unavailable' }
Config fetch failsFalls back to cached config or empty state
Event delivery failsEvents are buffered and retried silently

Hooks expose errors as strings — they never throw:

const { error, isLoading } = usePlacement({ ... });
const { error: entError } = useEntitlement({ handle: 'data_export' });
if (error) {
// Non-critical — log and continue
console.warn('Placement error:', error);
}

Headless controllers surface errors through state:

const ctrl = new PlacementController(sdk, config);
await ctrl.load();
if (ctrl.state.error) {
console.warn('Controller error:', ctrl.state.error);
}

Most SDK methods fail silently and return sensible defaults:

// Returns allowed on API failure
await sdk.checkEntitlement('data_export');
// Silently drops event on delivery failure
await sdk.trackEvent('page_viewed');
// Returns null decision on failure
await sdk.getPlacement({ slotId: 'banner' });

When the provider chain is exhausted (all providers failed), slots behave according to providerFailureSlotBehavior:

<RevTurbineProvider
options={{
// ...
providerFailureSlotBehavior: 'invisible', // default
}}
>
ValueBehavior
'invisible'Slots render nothing — your layout stays intact
'placeholder'Slots render fallback placeholder content

Use 'invisible' (default) for production. Placements are additive — your app should work fine without them.

Use 'placeholder' during development to visually verify that slots are wired correctly even when the provider is down.

Placement decisions include reason_codes that explain why a placement was hidden or shown:

CodeMeaning
cap_limit_exceededImpression cap reached
suppressedUser recently dismissed/snoozed
plan_mismatchUser’s plan doesn’t match targeting
segment_mismatchUser doesn’t match targeting segment
config_not_loadedExportedConfig not yet available
api_errorAPI returned non-200
network_errorNetwork/timeout failure
fallback_contentUsing fallback placeholder
const { decision } = usePlacement({ ... });
if (decision?.reason_codes?.includes('cap_limit_exceeded')) {
// User has seen this placement too many times
}
ReasonMeaning
entitlement_service_unavailableAPI unreachable — defaulted to allowed
entitlement_check_errorParse/exception error — defaulted to allowed
local_runtime_default_allowLocal mode with no matching entitlement data
OperationRetry Strategy
Placement resolutionNo auto-retry. Call refresh() to retry manually.
Entitlement checkNo auto-retry. Call recheck() to retry manually.
Event deliveryAuto-buffered and retried on next batch interval.
Config fetchFalls back to cached config. Retried on next SDK initialization.
const { refresh, error } = usePlacement({ ... });
const { recheck, error: entError } = useEntitlement({ handle: 'data_export' });
// Retry after transient failure
if (error) await refresh();
if (entError) await recheck();

Structure your components so the SDK enhancement is purely additive:

function Dashboard() {
return (
<div>
{/* Baseline UX — always works */}
<DashboardContent />
{/* SDK enhancement — fails gracefully to nothing */}
<SurfaceSlotComponent id="dashboard_banner" surfaceType="banner" />
</div>
);
}

If the SDK is down, SurfaceSlotComponent renders nothing and the baseline dashboard continues working.

Enable verbose logging to diagnose issues:

// In browser console
localStorage.setItem('revturbine:debug', 'true');

This logs decision resolution, provider chain evaluation, and error details to the browser console.