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

# useFeatureAccess

> Check if the current tenant has access to a specific feature or product.

Checks whether the tenant's active plan includes a given feature key. Supports multi-product orgs via a `productSlug` option and an optional remote API check.

## Usage

```tsx theme={null}
import { useFeatureAccess } from 'crovver-react';

function ExportButton() {
  const { hasAccess, isLoading, redirectToUpgrade } = useFeatureAccess('data_export');

  if (isLoading) return null;

  return hasAccess
    ? <button onClick={exportData}>Export CSV</button>
    : <button onClick={redirectToUpgrade}>Upgrade to Export</button>;
}
```

## Parameters

| Param              | Type      | Default | Description                                                                                                          |
| ------------------ | --------- | ------- | -------------------------------------------------------------------------------------------------------------------- |
| `feature`          | `string`  | —       | Feature key to check. Optional when `productSlug` is provided — omitting it performs a subscription-existence check. |
| `opts.checkRemote` | `boolean` | `false` | Check via API instead of local plan data. Required when using `productSlug`.                                         |
| `opts.productSlug` | `string`  | —       | Scope the check to a specific product. Overrides the provider-level `productSlug` for this call.                     |

## Return Value

```typescript theme={null}
{
  hasAccess: boolean;     // true if the plan includes this feature
  canAccess: boolean;     // alias for hasAccess
  isLoading: boolean;
  error: Error | null;
  redirectToUpgrade: () => void;
  refresh: () => Promise<void>;
}
```

## How Access Is Determined

By default this is a **local check** — no API call is made. The subscription data fetched by `CrovverProvider` on mount is used:

1. No active subscription → `hasAccess: false`
2. Feature not in `plan.features` → `hasAccess: false`
3. `plan.features[featureKey] === true` → `hasAccess: true`

When `checkRemote: true`, the hook calls `POST /api/public/can-access` on every render cycle change, which supports `productSlug` scoping.

## Examples

### Disable a button instead of hiding it

```tsx theme={null}
const { hasAccess } = useFeatureAccess('bulk_operations');

<button disabled={!hasAccess} title={!hasAccess ? 'Upgrade to unlock' : undefined}>
  Bulk Delete
</button>
```

### Multi-product: scope to a specific product

```tsx theme={null}
// Feature gate scoped to a product (requires remote check)
const { hasAccess } = useFeatureAccess('job_posting', {
  checkRemote: true,
  productSlug: 'product-a',
});
```

### Subscription-existence check

```tsx theme={null}
// Does this tenant have any active subscription for product-a?
const { hasAccess: hasProductA } = useFeatureAccess(undefined, {
  checkRemote: true,
  productSlug: 'product-a',
});
```

### Check multiple features

```tsx theme={null}
const analytics = useFeatureAccess('advanced_analytics');
const exports   = useFeatureAccess('data_export');
const api       = useFeatureAccess('api_access');
```
