posthog-js
Version:
Posthog-js allows you to automatically capture usage and send events to PostHog.
295 lines (294 loc) • 15.4 kB
TypeScript
import type { Client, Extension } from '@posthog/browser-common';
import { FlagsResponse, FeatureFlagsCallback, EarlyAccessFeatureCallback, Properties, JsonType, EarlyAccessFeature, RemoteConfigFeatureFlagCallback, EarlyAccessFeatureStage, FeatureFlagDetail, FeatureFlagResult, FeatureFlagOptions, IsFeatureEnabledOptions, OverrideFeatureFlagsOptions, PostHogConfig } from './types';
import type { PostHog } from './posthog-core';
import { type FeatureFlagsConfigSource } from './feature-flags-config';
import { PERSISTENCE_EARLY_ACCESS_FEATURES, PERSISTENCE_ACTIVE_FEATURE_FLAGS, PERSISTENCE_FEATURE_FLAG_DETAILS, PERSISTENCE_FEATURE_FLAG_ERRORS, PERSISTENCE_FEATURE_FLAG_EVALUATED_AT, PERSISTENCE_FEATURE_FLAG_REQUEST_ID, PERSISTENCE_MINIMAL_FLAG_CALLED_EVENTS, ENABLED_FEATURE_FLAGS, STORED_GROUP_PROPERTIES_KEY, STORED_PERSON_PROPERTIES_KEY, FLAG_CALL_REPORTED, FLAG_CALL_REPORTED_SESSION_ID, PERSISTENCE_FEATURE_FLAG_PAYLOADS, PERSISTENCE_OVERRIDE_FEATURE_FLAGS, PERSISTENCE_OVERRIDE_FEATURE_FLAG_PAYLOADS } from './constants';
import { type Logger } from '@posthog/core';
type FeatureFlagsState = {
[PERSISTENCE_ACTIVE_FEATURE_FLAGS]?: string[];
[ENABLED_FEATURE_FLAGS]?: Record<string, string | boolean>;
[PERSISTENCE_FEATURE_FLAG_DETAILS]?: Record<string, FeatureFlagDetail>;
[PERSISTENCE_FEATURE_FLAG_PAYLOADS]?: Record<string, JsonType>;
[PERSISTENCE_FEATURE_FLAG_REQUEST_ID]?: string;
[PERSISTENCE_FEATURE_FLAG_EVALUATED_AT]?: number;
[PERSISTENCE_MINIMAL_FLAG_CALLED_EVENTS]?: boolean;
[PERSISTENCE_FEATURE_FLAG_ERRORS]?: string[];
[PERSISTENCE_OVERRIDE_FEATURE_FLAGS]?: Record<string, string | boolean>;
[PERSISTENCE_OVERRIDE_FEATURE_FLAG_PAYLOADS]?: Record<string, JsonType>;
[FLAG_CALL_REPORTED]?: Record<string, string[]>;
[FLAG_CALL_REPORTED_SESSION_ID]?: string;
[STORED_PERSON_PROPERTIES_KEY]?: Properties;
[STORED_GROUP_PROPERTIES_KEY]?: Record<string, Properties>;
[PERSISTENCE_EARLY_ACCESS_FEATURES]?: EarlyAccessFeature[];
};
/**
* Error type constants for the $feature_flag_error property.
*
* These values are sent in analytics events to track flag evaluation failures.
* They should not be changed without considering impact on existing dashboards
* and queries that filter on these values.
*/
export declare const FeatureFlagError: {
readonly ERRORS_WHILE_COMPUTING: "errors_while_computing_flags";
readonly FLAG_MISSING: "flag_missing";
readonly QUOTA_LIMITED: "quota_limited";
readonly TIMEOUT: "timeout";
readonly CONNECTION_ERROR: "connection_error";
readonly UNKNOWN_ERROR: "unknown_error";
readonly apiError: (status: number | string) => string;
};
export declare const filterActiveFeatureFlags: (featureFlags?: Record<string, string | boolean>) => Record<string, string | boolean>;
export declare const parseFlagsResponse: (response: Partial<FlagsResponse>, currentFlags?: Record<string, string | boolean>, currentFlagPayloads?: Record<string, JsonType>, currentFlagDetails?: Record<string, FeatureFlagDetail>, options?: {
partialResponse?: boolean;
}, responseLogger?: Logger) => FeatureFlagsState | undefined;
export declare const QuotaLimitedResource: {
readonly FeatureFlags: "feature_flags";
readonly Recordings: "recordings";
};
export type QuotaLimitedResource = (typeof QuotaLimitedResource)[keyof typeof QuotaLimitedResource];
export declare class PostHogFeatureFlags implements Extension {
readonly name: import("@posthog/browser-common").ExtensionToken<PostHogFeatureFlags>;
_override_warning: boolean;
featureFlagEventHandlers: FeatureFlagsCallback[];
$anon_distinct_id: string | undefined;
private _client?;
private _initializingClient?;
private _logger;
private _dynamicProperties?;
private _crossTabPersistenceUnsubscribe?;
private _baseEventProperties;
private _eventPropertiesWithFlagValues;
private _reloadingHandlers;
private _hasLoadedFlags;
private _requestInFlight;
private _requestGeneration;
private _reloadingDisabled;
private _additionalReloadRequested;
private _reloadDebouncer?;
private _flagsLoadedFromRemote;
private _staleCacheRefreshTriggered;
private _consecutiveStatusZeroFailures;
private _refreshInterval?;
private _refreshIntervalMs?;
private _lastRefreshAt?;
private readonly _configSource;
private readonly _mutableConfigSource?;
private readonly _instance?;
constructor(instance: PostHog);
constructor(configSource: FeatureFlagsConfigSource);
updateConfig(config: PostHogConfig, remoteRequestsDisabled: boolean): void;
setup(client: Client): void | Promise<void>;
private _finishSetup;
private _onOnline;
private _refreshIfDue;
private _onVisibilityChange;
private _syncAutomaticRefresh;
private _scheduleNextRefresh;
private _stopAutomaticRefresh;
destroy(): void;
dispose(): void;
private _dispose;
private get _config();
private _prop;
private _set;
private _markCrossTabFeatureFlagSnapshot;
private _remove;
private _persist;
private _rebuildEventProperties;
/**
* Check if the feature flag cache is stale based on the configured TTL.
*/
private _isCacheStale;
/**
* Triggers a debounced reload when cache staleness is first detected.
* Returns true if cache is stale, false otherwise.
*/
private _checkAndTriggerStaleRefresh;
private _getValidEvaluationEnvironments;
private _getValidFlagKeys;
initialize(): void;
updateFlags(flags: Record<string, boolean | string>, payloads?: Record<string, JsonType>, options?: {
merge?: boolean;
}): void;
get hasLoadedFlags(): boolean;
getFlags(): string[];
getFlagsWithDetails(): Record<string, FeatureFlagDetail>;
getAllFeatureFlags(): FeatureFlagResult[];
getFlagVariants(): Record<string, string | boolean>;
getFlagPayloads(): Record<string, JsonType>;
/**
* Reloads feature flags asynchronously.
*
* Constraints:
*
* 1. Avoid parallel requests
* 2. Delay a few milliseconds after each reloadFeatureFlags call to batch subsequent changes together
*/
reloadFeatureFlags(): void;
private _clearDebouncer;
onReloading(handler: () => void): () => void;
ensureFlagsLoaded(): void;
setAnonymousDistinctId(anon_distinct_id: string): void;
setReloadingPaused(isPaused: boolean): void;
resetFlagCallReported(): void;
_callFlagsEndpoint(options?: {
disableFlags?: boolean;
}): void;
private _hasStatusZeroCircuitBreakerTripped;
private _trackStatusZeroReachability;
/**
* Get feature flag's value for user.
*
* By default, this method may return cached values from localStorage if the `/flags` endpoint
* hasn't responded yet. This reduces flicker but means you might briefly see stale values
* (e.g., a flag that was disabled on the server).
*
* ### Usage:
*
* if(posthog.getFeatureFlag('my-flag') === 'some-variant') { // do something }
*
* // Only use fresh values from the server (returns undefined until /flags responds)
* if(posthog.getFeatureFlag('my-flag', { fresh: true }) === 'some-variant') { // do something }
*
* @param {String} key Key of the feature flag.
* @param {Object} options Optional settings.
* @param {boolean} [options.send_event=true] If false, won't send a $feature_flag_called event to PostHog.
* @param {boolean} [options.fresh=false] If true, only returns values loaded from the server, not cached localStorage values.
* Use this when you need to ensure the flag value reflects the current server state,
* such as after disabling a flag. Returns undefined until the /flags endpoint responds.
* @returns {boolean | string | undefined} The flag value, or undefined if not found or not yet loaded.
*/
getFeatureFlag(key: string, options?: FeatureFlagOptions): boolean | string | undefined;
getFeatureFlagDetails(key: string): FeatureFlagDetail | undefined;
/**
* @deprecated Use `getFeatureFlagResult()` instead which properly tracks the feature flag call.
* `getFeatureFlagPayload()` does not emit the `$feature_flag_called` event which may result in
* missing analytics. This method will be removed in a future version.
*/
getFeatureFlagPayload(key: string): JsonType;
/**
* Get a feature flag result including both the flag value and payload, while properly tracking the call.
* This method emits the `$feature_flag_called` event by default.
*
* By default, this method may return cached values from localStorage if the `/flags` endpoint
* hasn't responded yet. This reduces flicker but means you might briefly see stale values
* (e.g., a flag that was disabled on the server).
*
* ### Usage:
*
* const result = posthog.getFeatureFlagResult('my-flag')
* if (result?.enabled) {
* console.log('Flag is enabled with payload:', result.payload)
* }
*
* // Only use fresh values from the server
* const freshResult = posthog.getFeatureFlagResult('my-flag', { fresh: true })
*
* @param {String} key Key of the feature flag.
* @param {Object} [options] Options for the feature flag lookup.
* @param {boolean} [options.send_event=true] If false, won't send the $feature_flag_called event.
* @param {boolean} [options.fresh=false] If true, only returns values loaded from the server, not cached localStorage values.
* Use this when you need to ensure the flag value reflects the current server state.
* Returns undefined until the /flags endpoint responds.
* @returns {FeatureFlagResult | undefined} The feature flag result including key, enabled, variant, and payload.
*/
getFeatureFlagResult(key: string, options?: FeatureFlagOptions): FeatureFlagResult | undefined;
private _captureFeatureFlagCalled;
getRemoteConfigPayload(key: string, callback: RemoteConfigFeatureFlagCallback): void;
private _getRemoteConfigPayload;
/**
* See if feature flag is enabled for user.
*
* By default, this method may return cached values from localStorage if the `/flags` endpoint
* hasn't responded yet. This reduces flicker but means you might briefly see stale values
* (e.g., a flag that was disabled on the server).
*
* ### Usage:
*
* if(posthog.isFeatureEnabled('beta-feature')) { // do something }
*
* // Only use fresh values from the server
* if(posthog.isFeatureEnabled('beta-feature', { fresh: true })) { // do something }
*
* @param {String} key Key of the feature flag.
* @param {Object} [options] Optional settings.
* @param {boolean} [options.send_event=true] If false, won't send a $feature_flag_called event to PostHog.
* @param {boolean} [options.fresh=false] If true, only returns values loaded from the server, not cached localStorage values.
* Use this when you need to ensure the flag value reflects the current server state.
* Returns undefined until the /flags endpoint responds.
* @param {boolean} [options.defaultValue] Value to return when the flag has no value, e.g. flags have not loaded yet or no flag with that key exists.
* @returns {boolean | undefined} Whether the flag is enabled; when the flag has no value, defaultValue if given, otherwise undefined.
*/
isFeatureEnabled(key: string, options: IsFeatureEnabledOptions & {
defaultValue: boolean;
}): boolean;
isFeatureEnabled(key: string, options?: IsFeatureEnabledOptions): boolean | undefined;
addFeatureFlagsHandler(handler: FeatureFlagsCallback): void;
removeFeatureFlagsHandler(handler: FeatureFlagsCallback): void;
receivedFeatureFlags(response: Partial<FlagsResponse>, errorsLoading?: boolean, options?: {
partialResponse?: boolean;
}): void;
private _receivedFeatureFlags;
/**
* @deprecated Use overrideFeatureFlags instead. This will be removed in a future version.
*/
override(flags: boolean | string[] | Record<string, string | boolean>, suppressWarning?: boolean): void;
/**
* Override feature flags on the client-side. Useful for setting non-persistent feature flags,
* or for testing/debugging feature flags in the PostHog app.
*
* ### Usage:
*
* - posthog.featureFlags.overrideFeatureFlags(false) // clear all overrides
* - posthog.featureFlags.overrideFeatureFlags(['beta-feature']) // enable flags
* - posthog.featureFlags.overrideFeatureFlags({'beta-feature': 'variant'}) // set variants
* - posthog.featureFlags.overrideFeatureFlags({ flags: ['beta-feature'] }) // enable flags
* - posthog.featureFlags.overrideFeatureFlags({ flags: {'beta-feature': 'variant'} }) // set variants
* - posthog.featureFlags.overrideFeatureFlags({ // set both flags and payloads
* flags: {'beta-feature': 'variant'},
* payloads: { 'beta-feature': { someData: true } }
* })
* - posthog.featureFlags.overrideFeatureFlags({ // only override payloads
* payloads: { 'beta-feature': { someData: true } }
* })
*/
overrideFeatureFlags(overrideOptions: OverrideFeatureFlagsOptions): void;
private _overrideFeatureFlags;
onFeatureFlags(callback: FeatureFlagsCallback): () => void;
updateEarlyAccessFeatureEnrollment(key: string, isEnrolled: boolean, stage?: string): void;
getEarlyAccessFeatures(callback: EarlyAccessFeatureCallback, force_reload?: boolean, stages?: EarlyAccessFeatureStage[]): void;
private _getEarlyAccessFeatures;
_prepareFeatureFlagsForCallbacks(): {
flags: string[];
flagVariants: Record<string, string | boolean>;
};
_fireFeatureFlagsCallbacks(errorsLoading?: boolean): void;
/**
* Set override person properties for feature flags.
* This is used when dealing with new persons / where you don't want to wait for ingestion
* to update user properties.
*/
setPersonPropertiesForFlags(properties: Properties, reloadFeatureFlags?: boolean): void;
private _setPersonPropertiesForFlags;
/**
* Remove override person properties used for feature flags.
* This is the counterpart to setPersonPropertiesForFlags, used when person properties
* are unset so flags re-evaluate without the removed values.
*/
unsetPersonPropertiesForFlags(propertyNames: string[], reloadFeatureFlags?: boolean): void;
resetPersonPropertiesForFlags(reloadFeatureFlags?: boolean): void;
/**
* Set override group properties for feature flags.
* This is used when dealing with new groups / where you don't want to wait for ingestion
* to update properties.
* Takes in an object, the key of which is the group type.
* For example:
* setGroupPropertiesForFlags({'organization': { name: 'CYZ', employees: '11' } })
*/
setGroupPropertiesForFlags(properties: {
[type: string]: Properties;
}, reloadFeatureFlags?: boolean): void;
resetGroupPropertiesForFlags(group_type?: string): void;
reset(): void;
}
export {};