# Early Access Features

Early Access Features allow you to manage beta feature enrollments and give users opt-in/opt-out control over experimental features. This enables gradual feature rollouts and gathering feedback from early adopters.

## Capabilities

### Get Early Access Features

Fetches all early access features available for the current user.

```typescript { .api }
/**
 * Gets early access features for the current user
 * @param callback - Callback receiving features and load status
 * @param force_reload - Force reload from server instead of using cache
 */
function getEarlyAccessFeatures(
    callback: EarlyAccessFeatureCallback,
    force_reload?: boolean
): void;
```

**Usage Examples:**

```typescript
// Get all early access features
posthog.getEarlyAccessFeatures((features) => {
    console.log('Available features:', features);
    features.forEach(feature => {
        console.log(`${feature.name}: ${feature.stage}`);
    });
});

// Force reload from server
posthog.getEarlyAccessFeatures((features) => {
    console.log('Fresh features:', features);
}, true);

// Display features in UI
function EarlyAccessPanel() {
    posthog.getEarlyAccessFeatures((features) => {
        renderFeatureList(features);
    });
}
```

### Update Feature Enrollment

Updates a user's enrollment status for a specific early access feature.

```typescript { .api }
/**
 * Updates user's enrollment in an early access feature
 * @param key - Feature key identifier
 * @param isEnrolled - Whether the user should be enrolled
 * @param stage - Optional stage override ('alpha', 'beta', 'general-availability')
 */
function updateEarlyAccessFeatureEnrollment(
    key: string,
    isEnrolled: boolean,
    stage?: EarlyAccessFeatureStage
): void;
```

**Usage Examples:**

```typescript
// Enroll user in a feature
posthog.updateEarlyAccessFeatureEnrollment('new-editor', true);

// Unenroll user from a feature
posthog.updateEarlyAccessFeatureEnrollment('new-editor', false);

// Enroll with specific stage
posthog.updateEarlyAccessFeatureEnrollment('ai-features', true, 'beta');

// Toggle enrollment
function toggleFeature(featureKey: string, currentlyEnrolled: boolean) {
    posthog.updateEarlyAccessFeatureEnrollment(featureKey, !currentlyEnrolled);

    // Capture enrollment event
    posthog.capture('early_access_enrollment_changed', {
        feature: featureKey,
        enrolled: !currentlyEnrolled
    });
}
```

## Types

### EarlyAccessFeatureCallback

```typescript { .api }
/**
 * Callback invoked when early access features are loaded
 * @param features - Array of available early access features
 */
type EarlyAccessFeatureCallback = (features: EarlyAccessFeature[]) => void;
```

### EarlyAccessFeature

```typescript { .api }
/**
 * Early access feature definition
 */
interface EarlyAccessFeature {
    /**
     * Unique feature identifier
     */
    id: string;

    /**
     * Feature key used for enrollment
     */
    key: string;

    /**
     * Feature name
     */
    name: string;

    /**
     * Feature description
     */
    description?: string;

    /**
     * Current stage of the feature
     */
    stage: EarlyAccessFeatureStage;

    /**
     * Whether the current user is enrolled
     */
    isEnrolled: boolean;

    /**
     * Documentation URL
     */
    documentationUrl?: string;

    /**
     * Feature flag key (if linked to a flag)
     */
    flagKey?: string;
}
```

### EarlyAccessFeatureStage

```typescript { .api }
/**
 * Stage of an early access feature
 */
type EarlyAccessFeatureStage = 'alpha' | 'beta' | 'general-availability';
```

## Best Practices

### Feature Opt-In UI

```typescript
// Create an opt-in panel for early access features
function EarlyAccessSettings() {
    const [features, setFeatures] = useState<EarlyAccessFeature[]>([]);

    useEffect(() => {
        posthog.getEarlyAccessFeatures((loadedFeatures) => {
            setFeatures(loadedFeatures);
        });
    }, []);

    const toggleFeature = (feature: EarlyAccessFeature) => {
        posthog.updateEarlyAccessFeatureEnrollment(
            feature.key,
            !feature.isEnrolled
        );

        // Update local state
        setFeatures(features.map(f =>
            f.key === feature.key
                ? { ...f, isEnrolled: !f.isEnrolled }
                : f
        ));
    };

    return (
        <div>
            <h2>Early Access Features</h2>
            {features.map(feature => (
                <div key={feature.key}>
                    <h3>{feature.name} ({feature.stage})</h3>
                    <p>{feature.description}</p>
                    <button onClick={() => toggleFeature(feature)}>
                        {feature.isEnrolled ? 'Opt Out' : 'Opt In'}
                    </button>
                </div>
            ))}
        </div>
    );
}
```

### Feature-Flag Integration

```typescript
// Link early access features with feature flags
posthog.getEarlyAccessFeatures((features) => {
    features.forEach(feature => {
        if (feature.flagKey) {
            const isFlagEnabled = posthog.isFeatureEnabled(feature.flagKey);
            console.log(`${feature.name}: ${isFlagEnabled ? 'enabled' : 'disabled'}`);
        }
    });
});
```

### Stage-Based Access

```typescript
// Show features based on stage
posthog.getEarlyAccessFeatures((features) => {
    const alphaFeatures = features.filter(f => f.stage === 'alpha');
    const betaFeatures = features.filter(f => f.stage === 'beta');

    console.log('Alpha features:', alphaFeatures.length);
    console.log('Beta features:', betaFeatures.length);

    // Show beta features to all users, alpha only to internal users
    const userEmail = posthog.get_property('email');
    const isInternal = userEmail?.endsWith('@company.com');

    if (isInternal) {
        renderFeatures([...alphaFeatures, ...betaFeatures]);
    } else {
        renderFeatures(betaFeatures);
    }
});
```

## Common Patterns

### Automatic Enrollment

```typescript
// Auto-enroll users who meet criteria
posthog.getEarlyAccessFeatures((features) => {
    const userPlan = posthog.get_property('plan');

    features.forEach(feature => {
        // Auto-enroll premium users in beta features
        if (userPlan === 'premium' && feature.stage === 'beta' && !feature.isEnrolled) {
            posthog.updateEarlyAccessFeatureEnrollment(feature.key, true);
            console.log(`Auto-enrolled in ${feature.name}`);
        }
    });
});
```

### Feature Announcement

```typescript
// Notify users of new early access features
function checkForNewFeatures() {
    const seenFeatures = posthog.get_property('seen_early_access_features') || [];

    posthog.getEarlyAccessFeatures((features) => {
        const newFeatures = features.filter(f => !seenFeatures.includes(f.key));

        if (newFeatures.length > 0) {
            showNotification(`${newFeatures.length} new features available!`);

            // Mark as seen
            posthog.register({
                seen_early_access_features: features.map(f => f.key)
            });
        }
    });
}
```

### Feedback Collection

```typescript
// Collect feedback on enrolled features
posthog.getEarlyAccessFeatures((features) => {
    const enrolledFeatures = features.filter(f => f.isEnrolled);

    enrolledFeatures.forEach(feature => {
        // Track feature usage
        posthog.capture('early_access_feature_used', {
            feature_key: feature.key,
            feature_name: feature.name,
            stage: feature.stage
        });
    });
});
```

### Progressive Rollout

```typescript
// Gradually roll out features
function promoteFeatureStage(featureKey: string) {
    posthog.getEarlyAccessFeatures((features) => {
        const feature = features.find(f => f.key === featureKey);

        if (feature && feature.stage === 'alpha') {
            // Promote to beta
            posthog.updateEarlyAccessFeatureEnrollment(
                featureKey,
                true,
                'beta'
            );
        }
    });
}
```

## Integration with Feature Flags

Early access features can be linked to feature flags for conditional rendering:

```typescript
// Check both enrollment and flag status
posthog.getEarlyAccessFeatures((features) => {
    const newEditorFeature = features.find(f => f.key === 'new-editor');

    if (newEditorFeature?.isEnrolled && newEditorFeature.flagKey) {
        const flagEnabled = posthog.isFeatureEnabled(newEditorFeature.flagKey);

        if (flagEnabled) {
            // Show new editor
            renderNewEditor();
        } else {
            // Flag is off, show old editor even though enrolled
            renderOldEditor();
        }
    }
});
```

## Notes

- Early access features are loaded from PostHog servers and may require network connectivity
- Enrollment changes are persisted and synchronized across sessions
- Feature availability may be controlled by feature flags, user properties, or cohorts
- Use early access features for gradual rollouts and collecting user feedback before general availability
